quagga-0.99.24.1/0000755000175000017500000000000012476521377010322 500000000000000quagga-0.99.24.1/pimd/0000755000175000017500000000000012476521400011236 500000000000000quagga-0.99.24.1/pimd/test_igmpv3_join.c0000644000175000017500000000675512476520570014631 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include #include #include #include #include #include "pim_igmp_join.h" const char *prog_name = 0; static int iface_solve_index(const char *ifname) { struct if_nameindex *ini; int ifindex = -1; int i; if (!ifname) return -1; ini = if_nameindex(); if (!ini) { int err = errno; fprintf(stderr, "%s: interface=%s: failure solving index: errno=%d: %s\n", prog_name, ifname, err, strerror(err)); errno = err; return -1; } for (i = 0; ini[i].if_index; ++i) { #if 0 fprintf(stderr, "%s: interface=%s matching against local ifname=%s ifindex=%d\n", prog_name, ifname, ini[i].if_name, ini[i].if_index); #endif if (!strcmp(ini[i].if_name, ifname)) { ifindex = ini[i].if_index; break; } } if_freenameindex(ini); return ifindex; } int main(int argc, const char *argv[]) { struct in_addr group_addr; struct in_addr source_addr; const char *ifname; const char *group; const char *source; int ifindex; int result; int fd; prog_name = argv[0]; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { fprintf(stderr, "%s: could not create socket: socket(): errno=%d: %s\n", prog_name, errno, strerror(errno)); exit(1); } if (argc != 4) { fprintf(stderr, "usage: %s interface group source\n" "example: %s eth0 232.1.1.1 1.1.1.1\n", prog_name, prog_name); exit(1); } ifname = argv[1]; group = argv[2]; source = argv[3]; ifindex = iface_solve_index(ifname); if (ifindex < 0) { fprintf(stderr, "%s: could not find interface: %s\n", prog_name, ifname); exit(1); } result = inet_pton(AF_INET, group, &group_addr); if (result <= 0) { fprintf(stderr, "%s: bad group address: %s\n", prog_name, group); exit(1); } result = inet_pton(AF_INET, source, &source_addr); if (result <= 0) { fprintf(stderr, "%s: bad source address: %s\n", prog_name, source); exit(1); } result = pim_igmp_join_source(fd, ifindex, group_addr, source_addr); if (result) { fprintf(stderr, "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s\n", prog_name, fd, group, source, ifindex, ifname, errno, strerror(errno)); exit(1); } printf("%s: joined channel (S,G)=(%s,%s) on interface %s\n", prog_name, source, group, ifname); printf("%s: waiting...\n", prog_name); getchar(); close(fd); printf("%s: left channel (S,G)=(%s,%s) on interface %s\n", prog_name, source, group, ifname); exit(0); } quagga-0.99.24.1/pimd/pim_main.c0000644000175000017500000001601612476520570013126 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "privs.h" #include "version.h" #include #include "command.h" #include "thread.h" #include #include "memory.h" #include "filter.h" #include "vty.h" #include "sigevent.h" #include "version.h" #include "pimd.h" #include "pim_version.h" #include "pim_signals.h" #include "pim_zebra.h" #ifdef PIM_ZCLIENT_DEBUG extern int zclient_debug; #endif extern struct host host; char config_default[] = SYSCONFDIR PIMD_DEFAULT_CONFIG; struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "version", no_argument, NULL, 'v'}, { "debug_zclient", no_argument, NULL, 'Z'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* pimd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, }; /* pimd privileges to run with */ struct zebra_privs_t pimd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), .cap_num_i = 0 }; char* progname; const char *pid_file = PATH_PIMD_PID; static void usage(int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages PIM.\n\n\ -d, --daemon Run in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -v, --version Print program version\n\ " #ifdef PIM_ZCLIENT_DEBUG "\ -Z, --debug_zclient Enable zclient debugging\n\ " #endif "\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, PIMD_BUG_ADDRESS); } exit (status); } int main(int argc, char** argv, char** envp) { char *p; char *vty_addr = NULL; int vty_port = -1; int daemon_mode = 0; char *config_file = NULL; char *zebra_sock_path = NULL; struct thread thread; umask(0027); progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog(progname, ZLOG_PIM, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* this while just reads the options */ while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:A:P:vZh", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'i': pid_file = optarg; break; case 'z': zebra_sock_path = optarg; break; case 'A': vty_addr = optarg; break; case 'P': vty_port = atoi (optarg); break; case 'v': printf(PIMD_PROGNAME " version %s\n", PIMD_VERSION); print_version(QUAGGA_PROGNAME); exit (0); break; #ifdef PIM_ZCLIENT_DEBUG case 'Z': zclient_debug = 1; break; #endif case 'h': usage (0); break; default: usage (1); break; } } master = thread_master_create(); /* * Temporarily send zlog to stdout */ zlog_default->maxlvl[ZLOG_DEST_STDOUT] = zlog_default->default_lvl; zlog_notice("Boot logging temporarily directed to stdout - begin"); zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting", QUAGGA_VERSION, PIMD_VERSION); /* * Initializations */ zprivs_init (&pimd_privs); pim_signals_init(); cmd_init(1); vty_init(master); memory_init(); access_list_init(); pim_init(); /* * reset zlog default, then will obey configuration file */ zlog_notice("Boot logging temporarily directed to stdout - end"); #if 0 /* this would disable logging to stdout, but config has not been loaded yet to reconfig the logging output */ zlog_default->maxlvl[ZLOG_DEST_STDOUT] = ZLOG_DISABLED; #endif /* Initialize zclient "update" and "lookup" sockets */ pim_zebra_init(zebra_sock_path); zlog_notice("Loading configuration - begin"); /* Get configuration file. */ vty_read_config(config_file, config_default); /* Starting from here zlog_* functions will log according configuration */ zlog_notice("Loading configuration - end"); /* Change to the daemon program. */ if (daemon_mode) { if (daemon(0, 0)) { zlog_warn("failed to daemonize"); } } /* Process ID file creation. */ pid_output(pid_file); /* Create pimd VTY socket */ if (vty_port < 0) vty_port = PIMD_VTY_PORT; vty_serv_sock(vty_addr, vty_port, PIM_VTYSH_PATH); zlog_notice("Quagga %s " PIMD_PROGNAME " %s starting, VTY interface at port TCP %d", QUAGGA_VERSION, PIMD_VERSION, vty_port); #ifdef PIM_DEBUG_BYDEFAULT zlog_notice("PIM_DEBUG_BYDEFAULT: Enabling all debug commands"); PIM_DO_DEBUG_PIM_EVENTS; PIM_DO_DEBUG_PIM_PACKETS; PIM_DO_DEBUG_PIM_TRACE; PIM_DO_DEBUG_IGMP_EVENTS; PIM_DO_DEBUG_IGMP_PACKETS; PIM_DO_DEBUG_IGMP_TRACE; PIM_DO_DEBUG_ZEBRA; #endif #ifdef PIM_ZCLIENT_DEBUG zlog_notice("PIM_ZCLIENT_DEBUG: zclient debugging is supported, mode is %s (see option -Z)", zclient_debug ? "ON" : "OFF"); #endif #ifdef PIM_CHECK_RECV_IFINDEX_SANITY zlog_notice("PIM_CHECK_RECV_IFINDEX_SANITY: will match sock/recv ifindex"); #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_notice("PIM_REPORT_RECV_IFINDEX_MISMATCH: will report sock/recv ifindex mismatch"); #endif #endif #ifdef PIM_UNEXPECTED_KERNEL_UPCALL zlog_notice("PIM_UNEXPECTED_KERNEL_UPCALL: report unexpected kernel upcall"); #endif #ifdef HAVE_CLOCK_MONOTONIC zlog_notice("HAVE_CLOCK_MONOTONIC"); #else zlog_notice("!HAVE_CLOCK_MONOTONIC"); #endif while (thread_fetch(master, &thread)) thread_call(&thread); zlog_err("%s %s: thread_fetch() returned NULL, exiting", __FILE__, __PRETTY_FUNCTION__); /* never reached */ return 0; } quagga-0.99.24.1/pimd/pim_int.c0000644000175000017500000000241712476520570012774 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include "pim_int.h" uint32_t pim_read_uint32_host(const uint8_t *buf) { uint32_t val; memcpy(&val, buf, sizeof(val)); /* val is in netorder */ val = ntohl(val); /* val is in hostorder */ return val; } void pim_write_uint32(uint8_t *buf, uint32_t val_host) { /* val_host is in host order */ val_host = htonl(val_host); /* val_host is in netorder */ memcpy(buf, &val_host, sizeof(val_host)); } quagga-0.99.24.1/pimd/pim_ssmpingd.c0000644000175000017500000002716312476520570014033 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "log.h" #include "memory.h" #include "pim_ssmpingd.h" #include "pim_time.h" #include "pim_sock.h" #include "pim_str.h" #include "pimd.h" static const char * const PIM_SSMPINGD_REPLY_GROUP = "232.43.211.234"; enum { PIM_SSMPINGD_REQUEST = 'Q', PIM_SSMPINGD_REPLY = 'A' }; static void ssmpingd_read_on(struct ssmpingd_sock *ss); void pim_ssmpingd_init() { int result; zassert(!qpim_ssmpingd_list); result = inet_pton(AF_INET, PIM_SSMPINGD_REPLY_GROUP, &qpim_ssmpingd_group_addr); zassert(result > 0); } void pim_ssmpingd_destroy() { if (qpim_ssmpingd_list) { list_free(qpim_ssmpingd_list); qpim_ssmpingd_list = 0; } } static struct ssmpingd_sock *ssmpingd_find(struct in_addr source_addr) { struct listnode *node; struct ssmpingd_sock *ss; if (!qpim_ssmpingd_list) return 0; for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) if (source_addr.s_addr == ss->source_addr.s_addr) return ss; return 0; } static void ssmpingd_free(struct ssmpingd_sock *ss) { XFREE(MTYPE_PIM_SSMPINGD, ss); } static int ssmpingd_socket(struct in_addr addr, int port, int mttl) { struct sockaddr_in sockaddr; int fd; fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) { zlog_err("%s: could not create socket: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } sockaddr.sin_family = AF_INET; sockaddr.sin_addr = addr; sockaddr.sin_port = htons(port); if (bind(fd, &sockaddr, sizeof(sockaddr))) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s: bind(fd=%d,addr=%s,port=%d,len=%zu) failure: errno=%d: %s", __PRETTY_FUNCTION__, fd, addr_str, port, sizeof(sockaddr), errno, safe_strerror(errno)); close(fd); return -1; } /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux IP_PKTINFO */ int opt = 1; if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("%s: could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn("%s: could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", __FILE__, __PRETTY_FUNCTION__); close(fd); return -1; #endif } { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse))) { zlog_warn("%s: could not set Reuse Address Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &mttl, sizeof(mttl))) { zlog_warn("%s: could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, mttl, fd, errno, safe_strerror(errno)); close(fd); return -1; } { int loop = 0; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &loop, sizeof(loop))) { zlog_warn("%s: could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, loop ? "enable" : "disable", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &addr, sizeof(addr))) { zlog_warn("%s: could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } { long flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn("%s: could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn("%s: could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); close(fd); return -1; } } return fd; } static void ssmpingd_delete(struct ssmpingd_sock *ss) { zassert(ss); zassert(qpim_ssmpingd_list); THREAD_OFF(ss->t_sock_read); if (close(ss->sock_fd)) { int e = errno; char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure closing ssmpingd sock_fd=%d for source %s: errno=%d: %s", __PRETTY_FUNCTION__, ss->sock_fd, source_str, e, safe_strerror(e)); /* warning only */ } listnode_delete(qpim_ssmpingd_list, ss); ssmpingd_free(ss); } static void ssmpingd_sendto(struct ssmpingd_sock *ss, const uint8_t *buf, int len, struct sockaddr_in to) { socklen_t tolen = sizeof(to); int sent; sent = sendto(ss->sock_fd, buf, len, MSG_DONTWAIT, &to, tolen); if (sent != len) { int e = errno; char to_str[100]; pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s,%d: fd=%d len=%d: errno=%d: %s", __PRETTY_FUNCTION__, to_str, ntohs(to.sin_port), ss->sock_fd, len, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s,%d: fd=%d len=%d: sent=%d", __PRETTY_FUNCTION__, to_str, ntohs(to.sin_port), ss->sock_fd, len, sent); } } } static int ssmpingd_read_msg(struct ssmpingd_sock *ss) { struct interface *ifp; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); int ifindex = -1; uint8_t buf[1000]; int len; ++ss->requests; len = pim_socket_recvfromto(ss->sock_fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure receiving ssmping for source %s on fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, source_str, ss->sock_fd, errno, safe_strerror(errno)); return -1; } ifp = if_lookup_by_index(ifindex); if (buf[0] != PIM_SSMPINGD_REQUEST) { char source_str[100]; char from_str[100]; char to_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_warn("%s: bad ssmping type=%d from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", __PRETTY_FUNCTION__, buf[0], from_str, ntohs(from.sin_port), to_str, ntohs(to.sin_port), ifp ? ifp->name : "", ifindex, ss->sock_fd, source_str); return 0; } if (PIM_DEBUG_SSMPINGD) { char source_str[100]; char from_str[100]; char to_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", from.sin_addr, from_str, sizeof(from_str)); pim_inet4_dump("", to.sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: recv ssmping from %s,%d to %s,%d on interface %s ifindex=%d fd=%d src=%s", __PRETTY_FUNCTION__, from_str, ntohs(from.sin_port), to_str, ntohs(to.sin_port), ifp ? ifp->name : "", ifindex, ss->sock_fd, source_str); } buf[0] = PIM_SSMPINGD_REPLY; /* unicast reply */ ssmpingd_sendto(ss, buf, len, from); /* multicast reply */ from.sin_addr = qpim_ssmpingd_group_addr; ssmpingd_sendto(ss, buf, len, from); return 0; } static int ssmpingd_sock_read(struct thread *t) { struct ssmpingd_sock *ss; int sock_fd; int result; zassert(t); ss = THREAD_ARG(t); zassert(ss); sock_fd = THREAD_FD(t); zassert(sock_fd == ss->sock_fd); result = ssmpingd_read_msg(ss); /* Keep reading */ ss->t_sock_read = 0; ssmpingd_read_on(ss); return result; } static void ssmpingd_read_on(struct ssmpingd_sock *ss) { zassert(!ss->t_sock_read); THREAD_READ_ON(master, ss->t_sock_read, ssmpingd_sock_read, ss, ss->sock_fd); } static struct ssmpingd_sock *ssmpingd_new(struct in_addr source_addr) { struct ssmpingd_sock *ss; int sock_fd; if (!qpim_ssmpingd_list) { qpim_ssmpingd_list = list_new(); if (!qpim_ssmpingd_list) { zlog_err("%s %s: failure: qpim_ssmpingd_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return 0; } qpim_ssmpingd_list->del = (void (*)(void *)) ssmpingd_free; } sock_fd = ssmpingd_socket(source_addr, /* port: */ 4321, /* mTTL: */ 64); if (sock_fd < 0) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: ssmpingd_socket() failure for source %s", __PRETTY_FUNCTION__, source_str); return 0; } ss = XMALLOC(MTYPE_PIM_SSMPINGD, sizeof(*ss)); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_err("%s: XMALLOC(%zu) failure for ssmpingd source %s", __PRETTY_FUNCTION__, sizeof(*ss), source_str); close(sock_fd); return 0; } ss->sock_fd = sock_fd; ss->t_sock_read = 0; ss->source_addr = source_addr; ss->creation = pim_time_monotonic_sec(); ss->requests = 0; listnode_add(qpim_ssmpingd_list, ss); ssmpingd_read_on(ss); return ss; } int pim_ssmpingd_start(struct in_addr source_addr) { struct ssmpingd_sock *ss; ss = ssmpingd_find(source_addr); if (ss) { /* silently ignore request to recreate entry */ return 0; } { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_info("%s: starting ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); } ss = ssmpingd_new(source_addr); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: ssmpingd_new() failure for source %s", __PRETTY_FUNCTION__, source_str); return -1; } return 0; } int pim_ssmpingd_stop(struct in_addr source_addr) { struct ssmpingd_sock *ss; ss = ssmpingd_find(source_addr); if (!ss) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: could not find ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); return -1; } { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_info("%s: stopping ssmpingd for source %s", __PRETTY_FUNCTION__, source_str); } ssmpingd_delete(ss); return 0; } quagga-0.99.24.1/pimd/pim_igmp_join.c0000644000175000017500000000355412476520570014160 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include "pim_igmp_join.h" #ifndef SOL_IP #define SOL_IP IPPROTO_IP #endif #ifndef MCAST_JOIN_SOURCE_GROUP #define MCAST_JOIN_SOURCE_GROUP 46 struct group_source_req { uint32_t gsr_interface; struct sockaddr_storage gsr_group; struct sockaddr_storage gsr_source; }; #endif int pim_igmp_join_source(int fd, int ifindex, struct in_addr group_addr, struct in_addr source_addr) { struct group_source_req req; struct sockaddr_in *group_sa = (struct sockaddr_in *) &req.gsr_group; struct sockaddr_in *source_sa = (struct sockaddr_in *) &req.gsr_source; memset(group_sa, 0, sizeof(*group_sa)); group_sa->sin_family = AF_INET; group_sa->sin_addr = group_addr; group_sa->sin_port = htons(0); memset(source_sa, 0, sizeof(*source_sa)); source_sa->sin_family = AF_INET; source_sa->sin_addr = source_addr; source_sa->sin_port = htons(0); req.gsr_interface = ifindex; return setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)); return 0; } quagga-0.99.24.1/pimd/pim_macro.c0000644000175000017500000003061712476520570013306 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pim_macro.h" #include "pimd.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_ifchannel.h" #define PIM_IFP_I_am_DR(pim_ifp) ((pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr) /* DownstreamJPState(S,G,I) is the per-interface state machine for receiving (S,G) Join/Prune messages. DownstreamJPState(S,G,I) is either Join or Prune-Pending ? */ static int downstream_jpstate_isjoined(const struct pim_ifchannel *ch) { return ch->ifjoin_state != PIM_IFJOIN_NOINFO; } /* The clause "local_receiver_include(S,G,I)" is true if the IGMP/MLD module or other local membership mechanism has determined that local members on interface I desire to receive traffic sent specifically by S to G. */ static int local_receiver_include(const struct pim_ifchannel *ch) { /* local_receiver_include(S,G,I) ? */ return ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE; } /* RFC 4601: 4.1.6. State Summarization Macros The set "joins(S,G)" is the set of all interfaces on which the router has received (S,G) Joins: joins(S,G) = { all interfaces I such that DownstreamJPState(S,G,I) is either Join or Prune-Pending } DownstreamJPState(S,G,I) is either Join or Prune-Pending ? */ int pim_macro_chisin_joins(const struct pim_ifchannel *ch) { return downstream_jpstate_isjoined(ch); } /* RFC 4601: 4.6.5. Assert State Macros The set "lost_assert(S,G)" is the set of all interfaces on which the router has received (S,G) joins but has lost an (S,G) assert. lost_assert(S,G) = { all interfaces I such that lost_assert(S,G,I) == TRUE } bool lost_assert(S,G,I) { if ( RPF_interface(S) == I ) { return FALSE } else { return ( AssertWinner(S,G,I) != NULL AND AssertWinner(S,G,I) != me AND (AssertWinnerMetric(S,G,I) is better than spt_assert_metric(S,I) ) } } AssertWinner(S,G,I) is the IP source address of the Assert(S,G) packet that won an Assert. */ int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch) { struct interface *ifp; struct pim_interface *pim_ifp; struct pim_assert_metric spt_assert_metric; ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } /* RPF_interface(S) == I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) return 0; /* false */ pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; /* false */ } if (PIM_INADDR_IS_ANY(ch->ifassert_winner)) return 0; /* false */ /* AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 0; /* false */ spt_assert_metric = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); return pim_assert_metric_better(&ch->ifassert_winner_metric, &spt_assert_metric); } /* RFC 4601: 4.1.6. State Summarization Macros pim_include(S,G) = { all interfaces I such that: ( (I_am_DR( I ) AND lost_assert(S,G,I) == FALSE ) OR AssertWinner(S,G,I) == me ) AND local_receiver_include(S,G,I) } AssertWinner(S,G,I) is the IP source address of the Assert(S,G) packet that won an Assert. */ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp = ch->interface->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return 0; /* false */ } /* local_receiver_include(S,G,I) ? */ if (!local_receiver_include(ch)) return 0; /* false */ /* OR AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 1; /* true */ return ( /* I_am_DR( I ) ? */ PIM_IFP_I_am_DR(pim_ifp) && /* lost_assert(S,G,I) == FALSE ? */ (!pim_macro_ch_lost_assert(ch)) ); } int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch) { if (pim_macro_chisin_joins(ch)) return 1; /* true */ return pim_macro_chisin_pim_include(ch); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine CouldAssert(S,G,I) = SPTbit(S,G)==TRUE AND (RPF_interface(S) != I) AND (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) (-) lost_assert(*,G) (+) joins(S,G) (+) pim_include(S,G) ) ) CouldAssert(S,G,I) is true for downstream interfaces that would be in the inherited_olist(S,G) if (S,G) assert information was not taken into account. CouldAssert(S,G,I) may be affected by changes in the following: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface */ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch) { struct interface *ifp; /* SPTbit(S,G) is always true for PIM-SSM-Only Routers */ ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } /* RPF_interface(S) != I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) return 0; /* false */ /* I in joins(S,G) (+) pim_include(S,G) ? */ return pim_macro_chisin_joins_or_include(ch); } /* RFC 4601: 4.6.3. Assert Metrics spt_assert_metric(S,I) gives the assert metric we use if we're sending an assert based on active (S,G) forwarding state: assert_metric spt_assert_metric(S,I) { return {0,MRIB.pref(S),MRIB.metric(S),my_ip_address(I)} } */ struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, struct in_addr ifaddr) { struct pim_assert_metric metric; metric.rpt_bit_flag = 0; metric.metric_preference = rpf->source_nexthop.mrib_metric_preference; metric.route_metric = rpf->source_nexthop.mrib_route_metric; metric.ip_address = ifaddr; return metric; } /* RFC 4601: 4.6.3. Assert Metrics An assert metric for (S,G) to include in (or compare against) an Assert message sent on interface I should be computed using the following pseudocode: assert_metric my_assert_metric(S,G,I) { if( CouldAssert(S,G,I) == TRUE ) { return spt_assert_metric(S,I) } else if( CouldAssert(*,G,I) == TRUE ) { return rpt_assert_metric(G,I) } else { return infinite_assert_metric() } } */ struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; pim_ifp = ch->interface->info; if (pim_ifp) { if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { return pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); } } return qpim_infinite_assert_metric; } /* RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) */ static int pim_macro_chisin_inherited_olist(const struct pim_ifchannel *ch) { if (pim_macro_ch_lost_assert(ch)) return 0; /* false */ return pim_macro_chisin_joins_or_include(ch); } /* RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Additionally, the Packet forwarding rules of Section 4.2 can be simplified in a PIM-SSM-only router: iif is the incoming interface of the packet. oiflist = NULL if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { oiflist = inherited_olist(S,G) } else if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } oiflist = oiflist (-) iif forward packet on all interfaces in oiflist Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) Note: - The following test is performed as response to WRONGVIF kernel upcall: if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } See pim_mroute.c mroute_msg(). */ int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch) { if (ch->upstream->join_state != PIM_UPSTREAM_JOINED) { /* oiflist is NULL */ return 0; /* false */ } /* oiflist = oiflist (-) iif */ if (ch->interface == ch->upstream->rpf.source_nexthop.interface) return 0; /* false */ return pim_macro_chisin_inherited_olist(ch); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine AssertTrackingDesired(S,G,I) = (I in ( ( joins(*,*,RP(G)) (+) joins(*,G) (-) prunes(S,G,rpt) ) (+) ( pim_include(*,G) (-) pim_exclude(S,G) ) (-) lost_assert(*,G) (+) joins(S,G) ) ) OR (local_receiver_include(S,G,I) == TRUE AND (I_am_DR(I) OR (AssertWinner(S,G,I) == me))) OR ((RPF_interface(S) == I) AND (JoinDesired(S,G) == TRUE)) OR ((RPF_interface(RP(G)) == I) AND (JoinDesired(*,G) == TRUE) AND (SPTbit(S,G) == FALSE)) AssertTrackingDesired(S,G,I) is true on any interface in which an (S,G) assert might affect our behavior. */ int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; struct interface *ifp; ifp = ch->interface; if (!ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): null interface", __PRETTY_FUNCTION__, src_str, grp_str); return 0; /* false */ } pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return 0; /* false */ } /* I in joins(S,G) ? */ if (pim_macro_chisin_joins(ch)) return 1; /* true */ /* local_receiver_include(S,G,I) ? */ if (local_receiver_include(ch)) { /* I_am_DR(I) ? */ if (PIM_IFP_I_am_DR(pim_ifp)) return 1; /* true */ /* AssertWinner(S,G,I) == me ? */ if (ch->ifassert_winner.s_addr == pim_ifp->primary_address.s_addr) return 1; /* true */ } /* RPF_interface(S) == I ? */ if (ch->upstream->rpf.source_nexthop.interface == ifp) { /* JoinDesired(S,G) ? */ if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)) return 1; /* true */ } return 0; /* false */ } quagga-0.99.24.1/pimd/pim_rand.c0000644000175000017500000000306012476520570013121 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include "pim_rand.h" #include "pim_time.h" /* Quick and dirty random number generator from NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5). */ /* BEWARE: '_qseed_' is assigned! */ #define QRANDOM(_qseed_) ((_qseed_) = (((_qseed_) * 1664525L) + 1013904223L)) static long qpim_rand_seed; void pim_rand_init() { qpim_rand_seed = pim_time_monotonic_sec() ^ getpid(); } long pim_rand() { return QRANDOM(qpim_rand_seed); } int pim_rand_next(int min, int max) { long rand; assert(min <= max); /* FIXME better random generator ? */ rand = QRANDOM(qpim_rand_seed); if (rand < 0) rand = -rand; rand = rand % (1 + max - min) + min; assert(rand >= min); assert(rand <= max); return rand; } quagga-0.99.24.1/pimd/pim_rpf.c0000644000175000017500000002050012476520570012762 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "memory.h" #include "pimd.h" #include "pim_rpf.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_zlookup.h" #include "pim_ifchannel.h" static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr) { struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; struct interface *ifp; int first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, addr_str); return -1; } first_ifindex = nexthop_tab[0].ifindex; if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ } ifp = if_lookup_by_index(first_ifindex); if (!ifp) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find interface for ifindex %d (address %s)", __FILE__, __PRETTY_FUNCTION__, first_ifindex, addr_str); return -2; } if (!ifp->info) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", __PRETTY_FUNCTION__, ifp->name, first_ifindex, addr_str); /* debug warning only, do not return */ } if (PIM_DEBUG_PIM_TRACE) { char nexthop_str[100]; char addr_str[100]; pim_inet4_dump("", nexthop_tab[0].nexthop_addr, nexthop_str, sizeof(nexthop_str)); pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: found nexthop %s for address %s: interface %s ifindex=%d metric=%d pref=%d", __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str, ifp->name, first_ifindex, nexthop_tab[0].route_metric, nexthop_tab[0].protocol_distance); } /* update nextop data */ nexthop->interface = ifp; nexthop->mrib_nexthop_addr = nexthop_tab[0].nexthop_addr; nexthop->mrib_metric_preference = nexthop_tab[0].protocol_distance; nexthop->mrib_route_metric = nexthop_tab[0].route_metric; return 0; } static int nexthop_mismatch(const struct pim_nexthop *nh1, const struct pim_nexthop *nh2) { return (nh1->interface != nh2->interface) || (nh1->mrib_nexthop_addr.s_addr != nh2->mrib_nexthop_addr.s_addr) || (nh1->mrib_metric_preference != nh2->mrib_metric_preference) || (nh1->mrib_route_metric != nh2->mrib_route_metric); } enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr) { struct in_addr save_rpf_addr; struct pim_nexthop save_nexthop; struct pim_rpf *rpf = &up->rpf; save_nexthop = rpf->source_nexthop; /* detect change in pim_nexthop */ save_rpf_addr = rpf->rpf_addr; /* detect change in RPF'(S,G) */ if (pim_nexthop_lookup(&rpf->source_nexthop, up->source_addr)) { return PIM_RPF_FAILURE; } rpf->rpf_addr = pim_rpf_find_rpf_addr(up); if (PIM_INADDR_IS_ANY(rpf->rpf_addr)) { /* RPF'(S,G) not found */ char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s %s: RPF'(%s,%s) not found: won't send join upstream", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str); /* warning only */ } /* detect change in pim_nexthop */ if (nexthop_mismatch(&rpf->source_nexthop, &save_nexthop)) { /* if (PIM_DEBUG_PIM_EVENTS) */ { char src_str[100]; char grp_str[100]; char nhaddr_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, nhaddr_str, sizeof(nhaddr_str)); zlog_debug("%s %s: (S,G)=(%s,%s) source nexthop now is: interface=%s address=%s pref=%d metric=%d", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : "", nhaddr_str, rpf->source_nexthop.mrib_metric_preference, rpf->source_nexthop.mrib_route_metric); /* warning only */ } pim_upstream_update_join_desired(up); pim_upstream_update_could_assert(up); pim_upstream_update_my_assert_metric(up); } /* detect change in RPF_interface(S) */ if (save_nexthop.interface != rpf->source_nexthop.interface) { /* if (PIM_DEBUG_PIM_EVENTS) */ { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s %s: (S,G)=(%s,%s) RPF_interface(S) changed from %s to %s", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, save_nexthop.interface ? save_nexthop.interface->name : "", rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""); /* warning only */ } pim_upstream_rpf_interface_changed(up, save_nexthop.interface); } /* detect change in RPF'(S,G) */ if (save_rpf_addr.s_addr != rpf->rpf_addr.s_addr) { /* return old rpf to caller ? */ if (old_rpf_addr) *old_rpf_addr = save_rpf_addr; return PIM_RPF_CHANGED; } return PIM_RPF_OK; } /* RFC 4601: 4.1.6. State Summarization Macros neighbor RPF'(S,G) { if ( I_Am_Assert_Loser(S, G, RPF_interface(S) )) { return AssertWinner(S, G, RPF_interface(S) ) } else { return NBR( RPF_interface(S), MRIB.next_hop( S ) ) } } RPF'(*,G) and RPF'(S,G) indicate the neighbor from which data packets should be coming and to which joins should be sent on the RP tree and SPT, respectively. */ static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up) { struct pim_ifchannel *rpf_ch; struct pim_neighbor *neigh; struct in_addr rpf_addr; if (!up->rpf.source_nexthop.interface) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: missing RPF interface for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, src_str, grp_str); rpf_addr.s_addr = PIM_NET_INADDR_ANY; return rpf_addr; } rpf_ch = pim_ifchannel_find(up->rpf.source_nexthop.interface, up->source_addr, up->group_addr); if (rpf_ch) { if (rpf_ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { return rpf_ch->ifassert_winner; } } /* return NBR( RPF_interface(S), MRIB.next_hop( S ) ) */ neigh = pim_if_find_neighbor(up->rpf.source_nexthop.interface, up->rpf.source_nexthop.mrib_nexthop_addr); if (neigh) rpf_addr = neigh->source_addr; else rpf_addr.s_addr = PIM_NET_INADDR_ANY; return rpf_addr; } quagga-0.99.24.1/pimd/pim_upstream.c0000644000175000017500000004460012476520570014042 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "log.h" #include "zclient.h" #include "memory.h" #include "thread.h" #include "linklist.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_join.h" #include "pim_zlookup.h" #include "pim_upstream.h" #include "pim_ifchannel.h" #include "pim_neighbor.h" #include "pim_rpf.h" #include "pim_zebra.h" #include "pim_oil.h" #include "pim_macro.h" static void join_timer_start(struct pim_upstream *up); static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up); void pim_upstream_free(struct pim_upstream *up) { XFREE(MTYPE_PIM_UPSTREAM, up); } static void upstream_channel_oil_detach(struct pim_upstream *up) { if (up->channel_oil) { pim_channel_oil_del(up->channel_oil); up->channel_oil = 0; } } void pim_upstream_delete(struct pim_upstream *up) { THREAD_OFF(up->t_join_timer); upstream_channel_oil_detach(up); /* notice that listnode_delete() can't be moved into pim_upstream_free() because the later is called by list_delete_all_node() */ listnode_delete(qpim_upstream_list, up); pim_upstream_free(up); } static void send_join(struct pim_upstream *up) { zassert(up->join_state == PIM_UPSTREAM_JOINED); if (PIM_DEBUG_PIM_TRACE) { if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s: can't send join upstream: RPF'(%s,%s)=%s", __PRETTY_FUNCTION__, src_str, grp_str, rpf_str); /* warning only */ } } /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); } static int on_join_timer(struct thread *t) { struct pim_upstream *up; zassert(t); up = THREAD_ARG(t); zassert(up); send_join(up); up->t_join_timer = 0; join_timer_start(up); return 0; } static void join_timer_start(struct pim_upstream *up) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: starting %d sec timer for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, qpim_t_periodic, src_str, grp_str); } zassert(!up->t_join_timer); THREAD_TIMER_ON(master, up->t_join_timer, on_join_timer, up, qpim_t_periodic); } void pim_upstream_join_timer_restart(struct pim_upstream *up) { THREAD_OFF(up->t_join_timer); join_timer_start(up); } static void pim_upstream_join_timer_restart_msec(struct pim_upstream *up, int interval_msec) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: restarting %d msec timer for upstream (S,G)=(%s,%s)", __PRETTY_FUNCTION__, interval_msec, src_str, grp_str); } THREAD_OFF(up->t_join_timer); THREAD_TIMER_MSEC_ON(master, up->t_join_timer, on_join_timer, up, interval_msec); } void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime) { long t_joinsuppress_msec; long join_timer_remain_msec; t_joinsuppress_msec = MIN(pim_if_t_suppressed_msec(up->rpf.source_nexthop.interface), 1000 * holdtime); join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); zlog_debug("%s %s: detected Join(%s,%s) to RPF'(S,G)=%s: join_timer=%ld msec t_joinsuppress=%ld msec", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, rpf_str, join_timer_remain_msec, t_joinsuppress_msec); } if (join_timer_remain_msec < t_joinsuppress_msec) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s %s: suppressing Join(S,G)=(%s,%s) for %ld msec", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, t_joinsuppress_msec); } pim_upstream_join_timer_restart_msec(up, t_joinsuppress_msec); } } void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_upstream *up, struct in_addr rpf_addr) { long join_timer_remain_msec; int t_override_msec; join_timer_remain_msec = pim_time_timer_remain_msec(up->t_join_timer); t_override_msec = pim_if_t_override_msec(up->rpf.source_nexthop.interface); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; char rpf_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf_addr, rpf_str, sizeof(rpf_str)); zlog_debug("%s: to RPF'(%s,%s)=%s: join_timer=%ld msec t_override=%d msec", debug_label, src_str, grp_str, rpf_str, join_timer_remain_msec, t_override_msec); } if (join_timer_remain_msec > t_override_msec) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: decreasing (S,G)=(%s,%s) join timer to t_override=%d msec", debug_label, src_str, grp_str, t_override_msec); } pim_upstream_join_timer_restart_msec(up, t_override_msec); } } static void forward_on(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (pim_macro_chisin_oiflist(ch)) pim_forward_start(ch); } /* scan iface channel list */ } /* scan iflist */ } static void forward_off(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_forward_stop(ch); } /* scan iface channel list */ } /* scan iflist */ } static void pim_upstream_switch(struct pim_upstream *up, enum pim_upstream_state new_state) { enum pim_upstream_state old_state = up->join_state; zassert(old_state != new_state); up->join_state = new_state; up->state_transition = pim_time_monotonic_sec(); if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: PIM_UPSTREAM_%s: (S,G)=(%s,%s)", __PRETTY_FUNCTION__, ((new_state == PIM_UPSTREAM_JOINED) ? "JOINED" : "NOTJOINED"), src_str, grp_str); } pim_upstream_update_assert_tracking_desired(up); if (new_state == PIM_UPSTREAM_JOINED) { forward_on(up); send_join(up); join_timer_start(up); } else { forward_off(up); pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); zassert(up->t_join_timer); THREAD_OFF(up->t_join_timer); } } static struct pim_upstream *pim_upstream_new(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; up = XMALLOC(MTYPE_PIM_UPSTREAM, sizeof(*up)); if (!up) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*up)); return 0; } up->source_addr = source_addr; up->group_addr = group_addr; up->flags = 0; up->ref_count = 1; up->t_join_timer = 0; up->join_state = 0; up->state_transition = pim_time_monotonic_sec(); up->channel_oil = 0; up->rpf.source_nexthop.interface = 0; up->rpf.source_nexthop.mrib_nexthop_addr.s_addr = PIM_NET_INADDR_ANY; up->rpf.source_nexthop.mrib_metric_preference = qpim_infinite_assert_metric.metric_preference; up->rpf.source_nexthop.mrib_route_metric = qpim_infinite_assert_metric.route_metric; up->rpf.rpf_addr.s_addr = PIM_NET_INADDR_ANY; pim_rpf_update(up, 0); listnode_add(qpim_upstream_list, up); return up; } struct pim_upstream *pim_upstream_find(struct in_addr source_addr, struct in_addr group_addr) { struct listnode *up_node; struct pim_upstream *up; for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { if ( (source_addr.s_addr == up->source_addr.s_addr) && (group_addr.s_addr == up->group_addr.s_addr) ) { return up; } } return 0; } struct pim_upstream *pim_upstream_add(struct in_addr source_addr, struct in_addr group_addr) { struct pim_upstream *up; up = pim_upstream_find(source_addr, group_addr); if (up) { ++up->ref_count; } else { up = pim_upstream_new(source_addr, group_addr); } return up; } void pim_upstream_del(struct pim_upstream *up) { --up->ref_count; if (up->ref_count < 1) { pim_upstream_delete(up); } } /* Evaluate JoinDesired(S,G): JoinDesired(S,G) is true if there is a downstream (S,G) interface I in the set: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) JoinDesired(S,G) may be affected by changes in the following: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface See also pim_upstream_update_join_desired() below. */ int pim_upstream_evaluate_join_desired(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (pim_macro_ch_lost_assert(ch)) continue; /* keep searching */ if (pim_macro_chisin_joins_or_include(ch)) return 1; /* true */ } /* scan iface channel list */ } /* scan iflist */ return 0; /* false */ } /* See also pim_upstream_evaluate_join_desired() above. */ void pim_upstream_update_join_desired(struct pim_upstream *up) { int was_join_desired; /* boolean */ int is_join_desired; /* boolean */ was_join_desired = PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags); is_join_desired = pim_upstream_evaluate_join_desired(up); if (is_join_desired) PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(up->flags); else PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(up->flags); /* switched from false to true */ if (is_join_desired && !was_join_desired) { zassert(up->join_state == PIM_UPSTREAM_NOTJOINED); pim_upstream_switch(up, PIM_UPSTREAM_JOINED); return; } /* switched from true to false */ if (!is_join_desired && was_join_desired) { zassert(up->join_state == PIM_UPSTREAM_JOINED); pim_upstream_switch(up, PIM_UPSTREAM_NOTJOINED); return; } } /* RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) GenID changes The upstream (S,G) state machine remains in Joined state. If the Join Timer is set to expire in more than t_override seconds, reset it so that it expires after t_override seconds. */ void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr) { struct listnode *up_node; struct listnode *up_nextnode; struct pim_upstream *up; /* Scan all (S,G) upstreams searching for RPF'(S,G)=neigh_addr */ for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { if (PIM_DEBUG_PIM_TRACE) { char neigh_str[100]; char src_str[100]; char grp_str[100]; char rpf_addr_str[100]; pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); zlog_debug("%s: matching neigh=%s against upstream (S,G)=(%s,%s) joined=%d rpf_addr=%s", __PRETTY_FUNCTION__, neigh_str, src_str, grp_str, up->join_state == PIM_UPSTREAM_JOINED, rpf_addr_str); } /* consider only (S,G) upstream in Joined state */ if (up->join_state != PIM_UPSTREAM_JOINED) continue; /* match RPF'(S,G)=neigh_addr */ if (up->rpf.rpf_addr.s_addr != neigh_addr.s_addr) continue; pim_upstream_join_timer_decrease_to_t_override("RPF'(S,G) GenID change", up, neigh_addr); } } void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp) { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { struct listnode *chnode; struct listnode *chnextnode; struct pim_ifchannel *ch; struct pim_interface *pim_ifp; pim_ifp = ifp->info; if (!pim_ifp) continue; /* search all ifchannels */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { if ( /* RPF_interface(S) was NOT I */ (old_rpf_ifp == ch->interface) && /* RPF_interface(S) stopped being I */ (ch->upstream->rpf.source_nexthop.interface != ch->interface) ) { assert_action_a5(ch); } } /* PIM_IFASSERT_I_AM_LOSER */ pim_ifchannel_update_assert_tracking_desired(ch); } } } void pim_upstream_update_could_assert(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_could_assert(ch); } /* scan iface channel list */ } /* scan iflist */ } void pim_upstream_update_my_assert_metric(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_my_assert_metric(ch); } /* scan iface channel list */ } /* scan iflist */ } static void pim_upstream_update_assert_tracking_desired(struct pim_upstream *up) { struct listnode *ifnode; struct listnode *ifnextnode; struct listnode *chnode; struct listnode *chnextnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; /* scan all interfaces */ for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, chnode, chnextnode, ch)) { if (ch->upstream != up) continue; pim_ifchannel_update_assert_tracking_desired(ch); } /* scan iface channel list */ } /* scan iflist */ } quagga-0.99.24.1/pimd/pim_msg.c0000644000175000017500000000545712476520570012777 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "pimd.h" #include "pim_pim.h" #include "pim_msg.h" #include "pim_util.h" void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type) { uint16_t checksum; zassert(pim_msg_size >= PIM_PIM_MIN_LEN); /* * Write header */ *(uint8_t *) PIM_MSG_HDR_OFFSET_VERSION(pim_msg) = (PIM_PROTO_VERSION << 4) | pim_msg_type; *(uint8_t *) PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) = 0; /* * Compute checksum */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; checksum = in_cksum(pim_msg, pim_msg_size); *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = checksum; } uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_UCAST_SIZE = 6; if (buf_size < ENCODED_IPV4_UCAST_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ memcpy(buf+2, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_UCAST_SIZE; } uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_GROUP_SIZE = 8; if (buf_size < ENCODED_IPV4_GROUP_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = '\0'; /* reserved */ buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_GROUP_SIZE; } uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size, struct in_addr addr) { const int ENCODED_IPV4_SOURCE_SIZE = 8; if (buf_size < ENCODED_IPV4_SOURCE_SIZE) { return 0; } buf[0] = PIM_MSG_ADDRESS_FAMILY_IPV4; /* addr family */ buf[1] = '\0'; /* native encoding */ buf[2] = 4; /* reserved = 0 | S bit = 1 | W bit = 0 | R bit = 0 */ buf[3] = 32; /* mask len */ memcpy(buf+4, &addr, sizeof(struct in_addr)); return buf + ENCODED_IPV4_SOURCE_SIZE; } quagga-0.99.24.1/pimd/pim_assert.c0000644000175000017500000005553612476520570013515 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_int.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_hello.h" #include "pim_macro.h" #include "pim_assert.h" #include "pim_ifchannel.h" static int assert_action_a3(struct pim_ifchannel *ch); static void assert_action_a2(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); static void assert_action_a6(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); void pim_ifassert_winner_set(struct pim_ifchannel *ch, enum pim_ifassert_state new_state, struct in_addr winner, struct pim_assert_metric winner_metric) { int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr); int metric_changed = !pim_assert_metric_match(&ch->ifassert_winner_metric, &winner_metric); if (PIM_DEBUG_PIM_EVENTS) { if (ch->ifassert_state != new_state) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) assert state changed from %s to %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), pim_ifchannel_ifassert_name(new_state), ch->interface->name); } if (winner_changed) { char src_str[100]; char grp_str[100]; char was_str[100]; char winner_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", ch->ifassert_winner, was_str, sizeof(was_str)); pim_inet4_dump("", winner, winner_str, sizeof(winner_str)); zlog_debug("%s: (S,G)=(%s,%s) assert winner changed from %s to %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, was_str, winner_str, ch->interface->name); } } /* PIM_DEBUG_PIM_EVENTS */ ch->ifassert_state = new_state; ch->ifassert_winner = winner; ch->ifassert_winner_metric = winner_metric; ch->ifassert_creation = pim_time_monotonic_sec(); if (winner_changed || metric_changed) { pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } } static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static int preferred_assert(const struct pim_ifchannel *ch, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(recv_metric, &ch->ifassert_winner_metric); } static int acceptable_assert(const struct pim_assert_metric *my_metric, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(recv_metric, my_metric); } static int inferior_assert(const struct pim_assert_metric *my_metric, const struct pim_assert_metric *recv_metric) { return pim_assert_metric_better(my_metric, recv_metric); } static int cancel_assert(const struct pim_assert_metric *recv_metric) { return (recv_metric->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) && (recv_metric->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX); } static void if_could_assert_do_a1(const char *caller, struct pim_ifchannel *ch) { if (PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { if (assert_action_a1(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: %s: (S,G)=(%s,%s) assert_action_a1 failure on interface %s", __PRETTY_FUNCTION__, caller, src_str, grp_str, ch->interface->name); /* log warning only */ } } } static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr, struct pim_assert_metric recv_metric) { struct pim_ifchannel *ch; ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) failure creating channel on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ifp->name); return -1; } switch (ch->ifassert_state) { case PIM_IFASSERT_NOINFO: if (recv_metric.rpt_bit_flag) { /* RPT bit set */ if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); } else { /* RPT bit clear */ if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { if_could_assert_do_a1(__PRETTY_FUNCTION__, ch); } else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { if (PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)) { assert_action_a6(ch, recv_metric); } } } break; case PIM_IFASSERT_I_AM_WINNER: if (preferred_assert(ch, &recv_metric)) { assert_action_a2(ch, recv_metric); } else { if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ assert_action_a3(ch); } } break; case PIM_IFASSERT_I_AM_LOSER: if (recv_metric.ip_address.s_addr == ch->ifassert_winner.s_addr) { /* Assert from current winner */ if (cancel_assert(&recv_metric)) { assert_action_a5(ch); } else { if (inferior_assert(&ch->ifassert_my_metric, &recv_metric)) { assert_action_a5(ch); } else if (acceptable_assert(&ch->ifassert_my_metric, &recv_metric)) { if (!recv_metric.rpt_bit_flag) { assert_action_a2(ch, recv_metric); } } } } else if (preferred_assert(ch, &recv_metric)) { assert_action_a2(ch, recv_metric); } break; default: { char source_str[100]; char group_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ch->ifassert_state, ifp->name); } return -2; } return 0; } int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *buf, int buf_size) { struct prefix msg_group_addr; struct prefix msg_source_addr; struct pim_assert_metric msg_metric; int offset; uint8_t *curr; int curr_size; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); curr = buf; curr_size = buf_size; /* Parse assert group addr */ offset = pim_parse_addr_group(ifp->name, src_addr, &msg_group_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_group() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -1; } curr += offset; curr_size -= offset; /* Parse assert source addr */ offset = pim_parse_addr_ucast(ifp->name, src_addr, &msg_source_addr, curr, curr_size); if (offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -2; } curr += offset; curr_size -= offset; if (curr_size != 8) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: preference/metric size is not 8: size=%d from %s on interface %s", __PRETTY_FUNCTION__, curr_size, src_str, ifp->name); return -3; } /* Parse assert metric preference */ msg_metric.metric_preference = pim_read_uint32_host(curr); msg_metric.rpt_bit_flag = msg_metric.metric_preference & 0x80000000; /* save highest bit */ msg_metric.metric_preference &= ~0x80000000; /* clear highest bit */ curr += 4; /* Parse assert route metric */ msg_metric.route_metric = pim_read_uint32_host(curr); if (PIM_DEBUG_PIM_TRACE) { char neigh_str[100]; char source_str[100]; char group_str[100]; pim_inet4_dump("", src_addr, neigh_str, sizeof(neigh_str)); pim_inet4_dump("", msg_source_addr.u.prefix4, source_str, sizeof(source_str)); pim_inet4_dump("", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); zlog_debug("%s: from %s on %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", __PRETTY_FUNCTION__, neigh_str, ifp->name, source_str, group_str, msg_metric.metric_preference, msg_metric.route_metric, PIM_FORCE_BOOLEAN(msg_metric.rpt_bit_flag)); } msg_metric.ip_address = src_addr; return dispatch_assert(ifp, msg_source_addr.u.prefix4, msg_group_addr.u.prefix4, msg_metric); } /* RFC 4601: 4.6.3. Assert Metrics Assert metrics are defined as: When comparing assert_metrics, the rpt_bit_flag, metric_preference, and route_metric field are compared in order, where the first lower value wins. If all fields are equal, the primary IP address of the router that sourced the Assert message is used as a tie-breaker, with the highest IP address winning. */ int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2) { if (m1->rpt_bit_flag < m2->rpt_bit_flag) return 1; if (m1->rpt_bit_flag > m2->rpt_bit_flag) return 0; if (m1->metric_preference < m2->metric_preference) return 1; if (m1->metric_preference > m2->metric_preference) return 0; if (m1->route_metric < m2->route_metric) return 1; if (m1->route_metric > m2->route_metric) return 0; return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr); } int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2) { if (m1->rpt_bit_flag != m2->rpt_bit_flag) return 0; if (m1->metric_preference != m2->metric_preference) return 0; if (m1->route_metric != m2->route_metric) return 0; return m1->ip_address.s_addr == m2->ip_address.s_addr; } int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag) { uint8_t *buf_pastend = pim_msg + buf_size; uint8_t *pim_msg_curr; int pim_msg_size; int remain; pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* skip room for pim header */ /* Encode group */ remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: failure encoding group address %s: space left=%d", __PRETTY_FUNCTION__, group_str, remain); return -1; } /* Encode source */ remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure encoding source address %s: space left=%d", __PRETTY_FUNCTION__, source_str, remain); return -2; } /* Metric preference */ pim_write_uint32(pim_msg_curr, rpt_bit_flag ? metric_preference | 0x80000000 : metric_preference); pim_msg_curr += 4; /* Route metric */ pim_write_uint32(pim_msg_curr, route_metric); pim_msg_curr += 4; /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_ASSERT); return pim_msg_size; } static int pim_assert_do(struct pim_ifchannel *ch, struct pim_assert_metric metric) { struct interface *ifp; struct pim_interface *pim_ifp; uint8_t pim_msg[1000]; int pim_msg_size; ifp = ch->interface; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: pim not enabled on interface: %s", __PRETTY_FUNCTION__, ifp->name); return -1; } pim_msg_size = pim_assert_build_msg(pim_msg, sizeof(pim_msg), ifp, ch->group_addr, ch->source_addr, metric.metric_preference, metric.route_metric, metric.rpt_bit_flag); if (pim_msg_size < 1) { zlog_warn("%s: failure building PIM assert message: msg_size=%d", __PRETTY_FUNCTION__, pim_msg_size); return -2; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ pim_hello_require(ifp); if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: to %s: (S,G)=(%s,%s) pref=%u metric=%u rpt_bit=%u", __PRETTY_FUNCTION__, ifp->name, source_str, group_str, metric.metric_preference, metric.route_metric, PIM_FORCE_BOOLEAN(metric.rpt_bit_flag)); } if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { zlog_warn("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); return -3; } return 0; } int pim_assert_send(struct pim_ifchannel *ch) { return pim_assert_do(ch, ch->ifassert_my_metric); } /* RFC 4601: 4.6.4. AssertCancel Messages An AssertCancel(S,G) is an infinite metric assert with the RPT bit set that names S as the source. */ static int pim_assert_cancel(struct pim_ifchannel *ch) { struct pim_assert_metric metric; metric.rpt_bit_flag = 0; metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; metric.ip_address = ch->source_addr; return pim_assert_do(ch, metric); } static int on_assert_timer(struct thread *t) { struct pim_ifchannel *ch; struct interface *ifp; zassert(t); ch = THREAD_ARG(t); zassert(ch); ifp = ch->interface; zassert(ifp); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) timer expired on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); } ch->t_ifassert_timer = 0; switch (ch->ifassert_state) { case PIM_IFASSERT_I_AM_WINNER: zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ assert_action_a3(ch); break; case PIM_IFASSERT_I_AM_LOSER: assert_action_a5(ch); break; default: { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) invalid assert state %d on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ch->ifassert_state, ifp->name); } } return 0; } static void assert_timer_off(struct pim_ifchannel *ch) { struct interface *ifp; zassert(ch); ifp = ch->interface; zassert(ifp); if (PIM_DEBUG_PIM_TRACE) { if (ch->t_ifassert_timer) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) cancelling timer on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); } } THREAD_OFF(ch->t_ifassert_timer); zassert(!ch->t_ifassert_timer); } static void pim_assert_timer_set(struct pim_ifchannel *ch, int interval) { struct interface *ifp; zassert(ch); ifp = ch->interface; zassert(ifp); assert_timer_off(ch); if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) starting %u sec timer on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, interval, ifp->name); } THREAD_TIMER_ON(master, ch->t_ifassert_timer, on_assert_timer, ch, interval); } static void pim_assert_timer_reset(struct pim_ifchannel *ch) { pim_assert_timer_set(ch, PIM_ASSERT_TIME - PIM_ASSERT_OVERRIDE_INTERVAL); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A1: Send Assert(S,G). Set Assert Timer to (Assert_Time - Assert_Override_Interval). Store self as AssertWinner(S,G,I). Store spt_assert_metric(S,I) as AssertWinnerMetric(S,G,I). */ int assert_action_a1(struct pim_ifchannel *ch) { struct interface *ifp = ch->interface; struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -1; /* must return since pim_ifp is used below */ } /* Switch to I_AM_WINNER before performing action_a3 below */ pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_WINNER, pim_ifp->primary_address, pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address)); zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); /* a3 requirement */ if (assert_action_a3(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) assert_action_a3 failure on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); /* warning only */ } zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); return 0; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A2: Store new assert winner as AssertWinner(S,G,I) and assert winner metric as AssertWinnerMetric(S,G,I). Set Assert Timer to Assert_Time. */ static void assert_action_a2(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric) { pim_ifassert_winner_set(ch, PIM_IFASSERT_I_AM_LOSER, winner_metric.ip_address, winner_metric); pim_assert_timer_set(ch, PIM_ASSERT_TIME); zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A3: Send Assert(S,G). Set Assert Timer to (Assert_Time - Assert_Override_Interval). */ static int assert_action_a3(struct pim_ifchannel *ch) { zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); pim_assert_timer_reset(ch); if (pim_assert_send(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s) failure sending assert on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); return -1; } zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER); return 0; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A4: Send AssertCancel(S,G). Delete assert info (AssertWinner(S,G,I) and AssertWinnerMetric(S,G,I) will then return their default values). */ void assert_action_a4(struct pim_ifchannel *ch) { if (pim_assert_cancel(ch)) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: failure sending AssertCancel(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name); /* log warning only */ } assert_action_a5(ch); zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A5: Delete assert info (AssertWinner(S,G,I) and AssertWinnerMetric(S,G,I) will then return their default values). */ void assert_action_a5(struct pim_ifchannel *ch) { reset_ifassert_state(ch); zassert(ch->ifassert_state == PIM_IFASSERT_NOINFO); } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine (S,G) Assert State machine Actions A6: Store new assert winner as AssertWinner(S,G,I) and assert winner metric as AssertWinnerMetric(S,G,I). Set Assert Timer to Assert_Time. If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set SPTbit(S,G) to TRUE. */ static void assert_action_a6(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric) { assert_action_a2(ch, winner_metric); /* If (I is RPF_interface(S)) AND (UpstreamJPState(S,G) == true) set SPTbit(S,G) to TRUE. Notice: For PIM SSM, SPTbit(S,G) is already always true. */ zassert(ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER); } quagga-0.99.24.1/pimd/pim_join.c0000644000175000017500000003165112476520570013143 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_join.h" #include "pim_iface.h" #include "pim_hello.h" #include "pim_ifchannel.h" static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, struct in_addr group, struct in_addr source, uint8_t source_flags) { if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source, src_str, sizeof(src_str)); pim_inet4_dump("", group, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: join (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, neigh_str, ifp->name); } /* Restart join expiry timer */ pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, source, group, source_flags, holdtime); } static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, struct in_addr group, struct in_addr source, uint8_t source_flags) { if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source, src_str, sizeof(src_str)); pim_inet4_dump("", group, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh->source_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: prune (S,G)=(%s,%s) rpt=%d wc=%d upstream=%s holdtime=%d from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, source_flags & PIM_RPT_BIT_MASK, source_flags & PIM_WILDCARD_BIT_MASK, up_str, holdtime, neigh_str, ifp->name); } pim_ifchannel_prune(ifp, upstream, source, group, source_flags, holdtime); } int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { struct prefix msg_upstream_addr; uint8_t msg_num_groups; uint16_t msg_holdtime; int addr_offset; uint8_t *buf; uint8_t *pastend; int remain; int group; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); buf = tlv_buf; pastend = tlv_buf + tlv_buf_size; /* Parse ucast addr */ addr_offset = pim_parse_addr_ucast(ifp->name, src_addr, &msg_upstream_addr, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_ucast addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifp->name); return -1; } buf += addr_offset; /* Check upstream address family */ if (msg_upstream_addr.family != AF_INET) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: ignoring join/prune directed to unexpected addr family=%d from %s on %s", __PRETTY_FUNCTION__, msg_upstream_addr.family, src_str, ifp->name); } return -2; } remain = pastend - buf; if (remain < 4) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: short join/prune message buffer for group list: size=%d minimum=%d from %s on %s", __PRETTY_FUNCTION__, remain, 4, src_str, ifp->name); return -4; } ++buf; /* skip reserved byte */ msg_num_groups = *(const uint8_t *) buf; ++buf; msg_holdtime = ntohs(*(const uint16_t *) buf); ++buf; ++buf; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char upstream_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("", msg_upstream_addr.u.prefix4, upstream_str, sizeof(upstream_str)); zlog_warn("%s: join/prune upstream=%s groups=%d holdtime=%d from %s on %s", __PRETTY_FUNCTION__, upstream_str, msg_num_groups, msg_holdtime, src_str, ifp->name); } /* Scan groups */ for (group = 0; group < msg_num_groups; ++group) { struct prefix msg_group_addr; struct prefix msg_source_addr; uint8_t msg_source_flags; uint16_t msg_num_joined_sources; uint16_t msg_num_pruned_sources; int source; addr_offset = pim_parse_addr_group(ifp->name, src_addr, &msg_group_addr, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_group addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { return -5; } buf += addr_offset; remain = pastend - buf; if (remain < 4) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: short join/prune buffer for source list: size=%d minimum=%d from %s on %s", __PRETTY_FUNCTION__, remain, 4, src_str, ifp->name); return -6; } msg_num_joined_sources = ntohs(*(const uint16_t *) buf); buf += 2; msg_num_pruned_sources = ntohs(*(const uint16_t *) buf); buf += 2; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; char upstream_str[100]; char group_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); pim_inet4_dump("", msg_upstream_addr.u.prefix4, upstream_str, sizeof(upstream_str)); pim_inet4_dump("", msg_group_addr.u.prefix4, group_str, sizeof(group_str)); zlog_warn("%s: join/prune upstream=%s group=%s/%d join_src=%d prune_src=%d from %s on %s", __PRETTY_FUNCTION__, upstream_str, group_str, msg_group_addr.prefixlen, msg_num_joined_sources, msg_num_pruned_sources, src_str, ifp->name); } /* Scan joined sources */ for (source = 0; source < msg_num_joined_sources; ++source) { addr_offset = pim_parse_addr_source(ifp->name, src_addr, &msg_source_addr, &msg_source_flags, buf, pastend - buf); #if 0 zlog_warn("%s: pim_parse_addr_source addr_offset=%d", __PRETTY_FUNCTION__, addr_offset); #endif if (addr_offset < 1) { return -7; } buf += addr_offset; recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, msg_group_addr.u.prefix4, msg_source_addr.u.prefix4, msg_source_flags); } /* Scan pruned sources */ for (source = 0; source < msg_num_pruned_sources; ++source) { addr_offset = pim_parse_addr_source(ifp->name, src_addr, &msg_source_addr, &msg_source_flags, buf, pastend - buf); if (addr_offset < 1) { return -8; } buf += addr_offset; recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr.u.prefix4, msg_group_addr.u.prefix4, msg_source_addr.u.prefix4, msg_source_flags); } } /* scan groups */ return 0; } int pim_joinprune_send(struct interface *ifp, struct in_addr upstream_addr, struct in_addr source_addr, struct in_addr group_addr, int send_join) { struct pim_interface *pim_ifp; uint8_t pim_msg[1000]; const uint8_t *pastend = pim_msg + sizeof(pim_msg); uint8_t *pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; /* room for pim header */ int pim_msg_size; int remain; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; char dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: sending %s(S,G)=(%s,%s) to upstream=%s on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", source_str, group_str, dst_str, ifp->name); } if (PIM_INADDR_IS_ANY(upstream_addr)) { if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; char dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: %s(S,G)=(%s,%s): upstream=%s is myself on interface %s", __PRETTY_FUNCTION__, send_join ? "Join" : "Prune", source_str, group_str, dst_str, ifp->name); } return 0; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ pim_hello_require(ifp); /* Build PIM message */ remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, upstream_addr); if (!pim_msg_curr) { char dst_str[100]; pim_inet4_dump("", upstream_addr, dst_str, sizeof(dst_str)); zlog_warn("%s: failure encoding destination address %s: space left=%d", __PRETTY_FUNCTION__, dst_str, remain); return -3; } remain = pastend - pim_msg_curr; if (remain < 4) { zlog_warn("%s: group will not fit: space left=%d", __PRETTY_FUNCTION__, remain); return -4; } *pim_msg_curr = 0; /* reserved */ ++pim_msg_curr; *pim_msg_curr = 1; /* number of groups */ ++pim_msg_curr; *((uint16_t *) pim_msg_curr) = htons(PIM_JP_HOLDTIME); ++pim_msg_curr; ++pim_msg_curr; remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: failure encoding group address %s: space left=%d", __PRETTY_FUNCTION__, group_str, remain); return -5; } remain = pastend - pim_msg_curr; if (remain < 4) { zlog_warn("%s: sources will not fit: space left=%d", __PRETTY_FUNCTION__, remain); return -6; } /* number of joined sources */ *((uint16_t *) pim_msg_curr) = htons(send_join ? 1 : 0); ++pim_msg_curr; ++pim_msg_curr; /* number of pruned sources */ *((uint16_t *) pim_msg_curr) = htons(send_join ? 0 : 1); ++pim_msg_curr; ++pim_msg_curr; remain = pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { char source_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure encoding source address %s: space left=%d", __PRETTY_FUNCTION__, source_str, remain); return -7; } /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_JOIN_PRUNE); if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { zlog_warn("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); return -8; } return 0; } quagga-0.99.24.1/pimd/pim_ifchannel.c0000644000175000017500000006035312476520570014134 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "linklist.h" #include "thread.h" #include "memory.h" #include "pimd.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_ifchannel.h" #include "pim_zebra.h" #include "pim_time.h" #include "pim_msg.h" #include "pim_pim.h" #include "pim_join.h" #include "pim_rpf.h" #include "pim_macro.h" void pim_ifchannel_free(struct pim_ifchannel *ch) { zassert(!ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); zassert(!ch->t_ifassert_timer); XFREE(MTYPE_PIM_IFCHANNEL, ch); } void pim_ifchannel_delete(struct pim_ifchannel *ch) { struct pim_interface *pim_ifp; pim_ifp = ch->interface->info; zassert(pim_ifp); if (ch->ifjoin_state != PIM_IFJOIN_NOINFO) { pim_upstream_update_join_desired(ch->upstream); } pim_upstream_del(ch->upstream); THREAD_OFF(ch->t_ifjoin_expiry_timer); THREAD_OFF(ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifassert_timer); /* notice that listnode_delete() can't be moved into pim_ifchannel_free() because the later is called by list_delete_all_node() */ listnode_delete(pim_ifp->pim_ifchannel_list, ch); pim_ifchannel_free(ch); } #define IFCHANNEL_NOINFO(ch) \ ( \ ((ch)->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO) \ && \ ((ch)->ifjoin_state == PIM_IFJOIN_NOINFO) \ && \ ((ch)->ifassert_state == PIM_IFASSERT_NOINFO) \ ) static void delete_on_noinfo(struct pim_ifchannel *ch) { if (IFCHANNEL_NOINFO(ch)) { /* In NOINFO state, timers should have been cleared */ zassert(!ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); zassert(!ch->t_ifassert_timer); pim_ifchannel_delete(ch); } } void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state) { enum pim_ifjoin_state old_state = ch->ifjoin_state; if (old_state == new_state) { zlog_debug("%s calledby %s: non-transition on state %d (%s)", __PRETTY_FUNCTION__, caller, new_state, pim_ifchannel_ifjoin_name(new_state)); return; } zassert(old_state != new_state); ch->ifjoin_state = new_state; /* Transition to/from NOINFO ? */ if ( (old_state == PIM_IFJOIN_NOINFO) || (new_state == PIM_IFJOIN_NOINFO) ) { if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("PIM_IFCHANNEL_%s: (S,G)=(%s,%s) on interface %s", ((new_state == PIM_IFJOIN_NOINFO) ? "DOWN" : "UP"), src_str, grp_str, ch->interface->name); } /* Record uptime of state transition to/from NOINFO */ ch->ifjoin_creation = pim_time_monotonic_sec(); pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } } const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state) { switch (ifjoin_state) { case PIM_IFJOIN_NOINFO: return "NOINFO"; case PIM_IFJOIN_JOIN: return "JOIN"; case PIM_IFJOIN_PRUNE_PENDING: return "PRUNEP"; } return "ifjoin_bad_state"; } const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state) { switch (ifassert_state) { case PIM_IFASSERT_NOINFO: return "NOINFO"; case PIM_IFASSERT_I_AM_WINNER: return "WINNER"; case PIM_IFASSERT_I_AM_LOSER: return "LOSER"; } return "ifassert_bad_state"; } /* RFC 4601: 4.6.5. Assert State Macros AssertWinner(S,G,I) defaults to NULL and AssertWinnerMetric(S,G,I) defaults to Infinity when in the NoInfo state. */ void reset_ifassert_state(struct pim_ifchannel *ch) { THREAD_OFF(ch->t_ifassert_timer); pim_ifassert_winner_set(ch, PIM_IFASSERT_NOINFO, qpim_inaddr_any, qpim_infinite_assert_metric); } static struct pim_ifchannel *pim_ifchannel_new(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; struct pim_upstream *up; pim_ifp = ifp->info; zassert(pim_ifp); up = pim_upstream_add(source_addr, group_addr); if (!up) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_err("%s: could not attach upstream (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } ch = XMALLOC(MTYPE_PIM_IFCHANNEL, sizeof(*ch)); if (!ch) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*ch)); return 0; } ch->flags = 0; ch->upstream = up; ch->interface = ifp; ch->source_addr = source_addr; ch->group_addr = group_addr; ch->local_ifmembership = PIM_IFMEMBERSHIP_NOINFO; ch->ifjoin_state = PIM_IFJOIN_NOINFO; ch->t_ifjoin_expiry_timer = 0; ch->t_ifjoin_prune_pending_timer = 0; ch->ifjoin_creation = 0; /* Assert state */ ch->t_ifassert_timer = 0; reset_ifassert_state(ch); if (pim_macro_ch_could_assert_eval(ch)) PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); else PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); if (pim_macro_assert_tracking_desired_eval(ch)) PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); else PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); ch->ifassert_my_metric = pim_macro_ch_my_assert_metric_eval(ch); /* Attach to list */ listnode_add(pim_ifp->pim_ifchannel_list, ch); zassert(IFCHANNEL_NOINFO(ch)); return ch; } struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_interface *pim_ifp; struct listnode *ch_node; struct pim_ifchannel *ch; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: (S,G)=(%s,%s): multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { if ( (source_addr.s_addr == ch->source_addr.s_addr) && (group_addr.s_addr == ch->group_addr.s_addr) ) { return ch; } } return 0; } static void ifmembership_set(struct pim_ifchannel *ch, enum pim_ifmembership membership) { if (ch->local_ifmembership == membership) return; /* if (PIM_DEBUG_PIM_EVENTS) */ { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: (S,G)=(%s,%s) membership now is %s on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, membership == PIM_IFMEMBERSHIP_INCLUDE ? "INCLUDE" : "NOINFO", ch->interface->name); } ch->local_ifmembership = membership; pim_upstream_update_join_desired(ch->upstream); pim_ifchannel_update_could_assert(ch); pim_ifchannel_update_assert_tracking_desired(ch); } void pim_ifchannel_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); } } void pim_ifchannel_delete_on_noinfo(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { delete_on_noinfo(ch); } } struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; char src_str[100]; char grp_str[100]; ch = pim_ifchannel_find(ifp, source_addr, group_addr); if (ch) return ch; ch = pim_ifchannel_new(ifp, source_addr, group_addr); if (ch) return ch; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: pim_ifchannel_new() failure for (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return 0; } static void ifjoin_to_noinfo(struct pim_ifchannel *ch) { pim_forward_stop(ch); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_NOINFO); delete_on_noinfo(ch); } static int on_ifjoin_expiry_timer(struct thread *t) { struct pim_ifchannel *ch; zassert(t); ch = THREAD_ARG(t); zassert(ch); ch->t_ifjoin_expiry_timer = 0; zassert(ch->ifjoin_state == PIM_IFJOIN_JOIN); ifjoin_to_noinfo(ch); /* ch may have been deleted */ return 0; } static void prune_echo(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_interface *pim_ifp; struct in_addr neigh_dst_addr; pim_ifp = ifp->info; zassert(pim_ifp); neigh_dst_addr = pim_ifp->primary_address; if (PIM_DEBUG_PIM_EVENTS) { char source_str[100]; char group_str[100]; char neigh_dst_str[100]; pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", neigh_dst_addr, neigh_dst_str, sizeof(neigh_dst_str)); zlog_debug("%s: sending PruneEcho(S,G)=(%s,%s) to upstream=%s on interface %s", __PRETTY_FUNCTION__, source_str, group_str, neigh_dst_str, ifp->name); } pim_joinprune_send(ifp, neigh_dst_addr, source_addr, group_addr, 0 /* boolean: send_join=false (prune) */); } static int on_ifjoin_prune_pending_timer(struct thread *t) { struct pim_ifchannel *ch; int send_prune_echo; /* boolean */ struct interface *ifp; struct pim_interface *pim_ifp; struct in_addr ch_source; struct in_addr ch_group; zassert(t); ch = THREAD_ARG(t); zassert(ch); ch->t_ifjoin_prune_pending_timer = 0; zassert(ch->ifjoin_state == PIM_IFJOIN_PRUNE_PENDING); /* Send PruneEcho(S,G) ? */ ifp = ch->interface; pim_ifp = ifp->info; send_prune_echo = (listcount(pim_ifp->pim_neighbor_list) > 1); /* Save (S,G) */ ch_source = ch->source_addr; ch_group = ch->group_addr; ifjoin_to_noinfo(ch); /* from here ch may have been deleted */ if (send_prune_echo) prune_echo(ifp, ch_source, ch_group); return 0; } static void check_recv_upstream(int is_join, struct interface *recv_ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, int holdtime) { struct pim_upstream *up; /* Upstream (S,G) in Joined state ? */ up = pim_upstream_find(source_addr, group_addr); if (!up) return; if (up->join_state != PIM_UPSTREAM_JOINED) return; /* Upstream (S,G) in Joined state */ if (PIM_INADDR_IS_ANY(up->rpf.rpf_addr)) { /* RPF'(S,G) not found */ char src_str[100]; char grp_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s %s: RPF'(%s,%s) not found", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str); return; } /* upstream directed to RPF'(S,G) ? */ if (upstream.s_addr != up->rpf.rpf_addr.s_addr) { char src_str[100]; char grp_str[100]; char up_str[100]; char rpf_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", up->rpf.rpf_addr, rpf_str, sizeof(rpf_str)); zlog_warn("%s %s: (S,G)=(%s,%s) upstream=%s not directed to RPF'(S,G)=%s on interface %s", __FILE__, __PRETTY_FUNCTION__, src_str, grp_str, up_str, rpf_str, recv_ifp->name); return; } /* upstream directed to RPF'(S,G) */ if (is_join) { /* Join(S,G) to RPF'(S,G) */ pim_upstream_join_suppress(up, up->rpf.rpf_addr, holdtime); return; } /* Prune to RPF'(S,G) */ if (source_flags & PIM_RPT_BIT_MASK) { if (source_flags & PIM_WILDCARD_BIT_MASK) { /* Prune(*,G) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(*,G)", up, up->rpf.rpf_addr); return; } /* Prune(S,G,rpt) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(S,G,rpt)", up, up->rpf.rpf_addr); return; } /* Prune(S,G) to RPF'(S,G) */ pim_upstream_join_timer_decrease_to_t_override("Prune(S,G)", up, up->rpf.rpf_addr); } static int nonlocal_upstream(int is_join, struct interface *recv_ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *recv_pim_ifp; int is_local; /* boolean */ recv_pim_ifp = recv_ifp->info; zassert(recv_pim_ifp); is_local = (upstream.s_addr == recv_pim_ifp->primary_address.s_addr); if (PIM_DEBUG_PIM_TRACE) { char up_str[100]; char src_str[100]; char grp_str[100]; pim_inet4_dump("", upstream, up_str, sizeof(up_str)); pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); zlog_warn("%s: recv %s (S,G)=(%s,%s) to %s upstream=%s on %s", __PRETTY_FUNCTION__, is_join ? "join" : "prune", src_str, grp_str, is_local ? "local" : "non-local", up_str, recv_ifp->name); } if (is_local) return 0; /* Since recv upstream addr was not directed to our primary address, check if we should react to it in any way. */ check_recv_upstream(is_join, recv_ifp, upstream, source_addr, group_addr, source_flags, holdtime); return 1; /* non-local */ } void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; if (nonlocal_upstream(1 /* join */, ifp, upstream, source_addr, group_addr, source_flags, holdtime)) { return; } ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) return; /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine Transitions from "I am Assert Loser" State Receive Join(S,G) on Interface I We receive a Join(S,G) that has the Upstream Neighbor Address field set to my primary IP address on interface I. The action is to transition to NoInfo state, delete this (S,G) assert state (Actions A5 below), and allow the normal PIM Join/Prune mechanisms to operate. Notice: The nonlocal_upstream() test above ensures the upstream address of the join message is our primary address. */ if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { char src_str[100]; char grp_str[100]; char neigh_str[100]; pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", neigh_addr, neigh_str, sizeof(neigh_str)); zlog_warn("%s: Assert Loser recv Join(%s,%s) from %s on %s", __PRETTY_FUNCTION__, src_str, grp_str, neigh_str, ifp->name); assert_action_a5(ch); } pim_ifp = ifp->info; zassert(pim_ifp); switch (ch->ifjoin_state) { case PIM_IFJOIN_NOINFO: pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); if (pim_macro_chisin_oiflist(ch)) { pim_forward_start(ch); } break; case PIM_IFJOIN_JOIN: zassert(!ch->t_ifjoin_prune_pending_timer); /* In the JOIN state ch->t_ifjoin_expiry_timer may be NULL due to a previously received join message with holdtime=0xFFFF. */ if (ch->t_ifjoin_expiry_timer) { unsigned long remain = thread_timer_remain_second(ch->t_ifjoin_expiry_timer); if (remain > holdtime) { /* RFC 4601: 4.5.3. Receiving (S,G) Join/Prune Messages Transitions from Join State The (S,G) downstream state machine on interface I remains in Join state, and the Expiry Timer (ET) is restarted, set to maximum of its current value and the HoldTime from the triggering Join/Prune message. Conclusion: Do not change the ET if the current value is higher than the received join holdtime. */ return; } } THREAD_OFF(ch->t_ifjoin_expiry_timer); break; case PIM_IFJOIN_PRUNE_PENDING: zassert(!ch->t_ifjoin_expiry_timer); zassert(ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifjoin_prune_pending_timer); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_JOIN); break; } zassert(!IFCHANNEL_NOINFO(ch)); if (holdtime != 0xFFFF) { THREAD_TIMER_ON(master, ch->t_ifjoin_expiry_timer, on_ifjoin_expiry_timer, ch, holdtime); } } void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime) { struct pim_ifchannel *ch; int jp_override_interval_msec; if (nonlocal_upstream(0 /* prune */, ifp, upstream, source_addr, group_addr, source_flags, holdtime)) { return; } ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) return; switch (ch->ifjoin_state) { case PIM_IFJOIN_NOINFO: case PIM_IFJOIN_PRUNE_PENDING: /* nothing to do */ break; case PIM_IFJOIN_JOIN: { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(ch->t_ifjoin_expiry_timer); zassert(!ch->t_ifjoin_prune_pending_timer); THREAD_OFF(ch->t_ifjoin_expiry_timer); pim_ifchannel_ifjoin_switch(__PRETTY_FUNCTION__, ch, PIM_IFJOIN_PRUNE_PENDING); if (listcount(pim_ifp->pim_neighbor_list) > 1) { jp_override_interval_msec = pim_if_jp_override_interval_msec(ifp); } else { jp_override_interval_msec = 0; /* schedule to expire immediately */ /* If we called ifjoin_prune() directly instead, care should be taken not to use "ch" afterwards since it would be deleted. */ } THREAD_TIMER_MSEC_ON(master, ch->t_ifjoin_prune_pending_timer, on_ifjoin_prune_pending_timer, ch, jp_override_interval_msec); zassert(!ch->t_ifjoin_expiry_timer); zassert(ch->t_ifjoin_prune_pending_timer); } break; } } void pim_ifchannel_local_membership_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ pim_ifp = ifp->info; if (!pim_ifp) return; if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; ch = pim_ifchannel_add(ifp, source_addr, group_addr); if (!ch) { return; } ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); zassert(!IFCHANNEL_NOINFO(ch)); } void pim_ifchannel_local_membership_del(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* PIM enabled on interface? */ pim_ifp = ifp->info; if (!pim_ifp) return; if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; ch = pim_ifchannel_find(ifp, source_addr, group_addr); if (!ch) return; ifmembership_set(ch, PIM_IFMEMBERSHIP_NOINFO); delete_on_noinfo(ch); } void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch) { int old_couldassert = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)); int new_couldassert = PIM_FORCE_BOOLEAN(pim_macro_ch_could_assert_eval(ch)); if (new_couldassert == old_couldassert) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: CouldAssert(%s,%s,%s) changed from %d to %d", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, old_couldassert, new_couldassert); } if (new_couldassert) { /* CouldAssert(S,G,I) switched from FALSE to TRUE */ PIM_IF_FLAG_SET_COULD_ASSERT(ch->flags); } else { /* CouldAssert(S,G,I) switched from TRUE to FALSE */ PIM_IF_FLAG_UNSET_COULD_ASSERT(ch->flags); if (ch->ifassert_state == PIM_IFASSERT_I_AM_WINNER) { assert_action_a4(ch); } } pim_ifchannel_update_my_assert_metric(ch); } /* my_assert_metric may be affected by: CouldAssert(S,G) pim_ifp->primary_address rpf->source_nexthop.mrib_metric_preference; rpf->source_nexthop.mrib_route_metric; */ void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch) { struct pim_assert_metric my_metric_new = pim_macro_ch_my_assert_metric_eval(ch); if (pim_assert_metric_match(&my_metric_new, &ch->ifassert_my_metric)) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; char old_addr_str[100]; char new_addr_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", ch->ifassert_my_metric.ip_address, old_addr_str, sizeof(old_addr_str)); pim_inet4_dump("", my_metric_new.ip_address, new_addr_str, sizeof(new_addr_str)); zlog_debug("%s: my_assert_metric(%s,%s,%s) changed from %u,%u,%u,%s to %u,%u,%u,%s", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, ch->ifassert_my_metric.rpt_bit_flag, ch->ifassert_my_metric.metric_preference, ch->ifassert_my_metric.route_metric, old_addr_str, my_metric_new.rpt_bit_flag, my_metric_new.metric_preference, my_metric_new.route_metric, new_addr_str); } ch->ifassert_my_metric = my_metric_new; if (pim_assert_metric_better(&ch->ifassert_my_metric, &ch->ifassert_winner_metric)) { assert_action_a5(ch); } } void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch) { int old_atd = PIM_FORCE_BOOLEAN(PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags)); int new_atd = PIM_FORCE_BOOLEAN(pim_macro_assert_tracking_desired_eval(ch)); if (new_atd == old_atd) return; if (PIM_DEBUG_PIM_EVENTS) { char src_str[100]; char grp_str[100]; pim_inet4_dump("", ch->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", ch->group_addr, grp_str, sizeof(grp_str)); zlog_debug("%s: AssertTrackingDesired(%s,%s,%s) changed from %d to %d", __PRETTY_FUNCTION__, src_str, grp_str, ch->interface->name, old_atd, new_atd); } if (new_atd) { /* AssertTrackingDesired(S,G,I) switched from FALSE to TRUE */ PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(ch->flags); } else { /* AssertTrackingDesired(S,G,I) switched from TRUE to FALSE */ PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(ch->flags); if (ch->ifassert_state == PIM_IFASSERT_I_AM_LOSER) { assert_action_a5(ch); } } } quagga-0.99.24.1/pimd/pim_hello.c0000644000175000017500000003572112476520570013311 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_tlv.h" #include "pim_util.h" #include "pim_hello.h" #include "pim_iface.h" #include "pim_neighbor.h" #include "pim_upstream.h" static void on_trace(const char *label, struct interface *ifp, struct in_addr src) { if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src, src_str, sizeof(src_str)); zlog_debug("%s: from %s on %s", label, src_str, ifp->name); } } static void tlv_trace_bool(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, int value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%d", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint16(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint16_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint32(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint32_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%u", label, src_str, ifname, tlv_name, value); } } static void tlv_trace_uint32_hex(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, uint32_t value) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s=%08x", label, src_str, ifname, tlv_name, value); } } #if 0 static void tlv_trace(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s", label, src_str, ifname, tlv_name); } } #endif static void tlv_trace_list(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int isset, struct list *addr_list) { if (isset) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello option from %s on interface %s: %s size=%d list=%p", label, src_str, ifname, tlv_name, addr_list ? ((int) listcount(addr_list)) : -1, (void *) addr_list); } } #define FREE_ADDR_LIST \ if (hello_option_addr_list) { \ list_delete(hello_option_addr_list); \ } #define FREE_ADDR_LIST_THEN_RETURN(code) \ { \ FREE_ADDR_LIST \ return (code); \ } int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; uint8_t *tlv_curr; uint8_t *tlv_pastend; pim_hello_options hello_options = 0; /* bit array recording options found */ uint16_t hello_option_holdtime = 0; uint16_t hello_option_propagation_delay = 0; uint16_t hello_option_override_interval = 0; uint32_t hello_option_dr_priority = 0; uint32_t hello_option_generation_id = 0; struct list *hello_option_addr_list = 0; on_trace(__PRETTY_FUNCTION__, ifp, src_addr); pim_ifp = ifp->info; zassert(pim_ifp); ++pim_ifp->pim_ifstat_hello_recv; /* Parse PIM hello TLVs */ zassert(tlv_buf_size >= 0); tlv_curr = tlv_buf; tlv_pastend = tlv_buf + tlv_buf_size; while (tlv_curr < tlv_pastend) { uint16_t option_type; uint16_t option_len; int remain = tlv_pastend - tlv_curr; if (remain < PIM_TLV_MIN_SIZE) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: short PIM hello TLV size=%d < min=%d from %s on interface %s", __PRETTY_FUNCTION__, remain, PIM_TLV_MIN_SIZE, src_str, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-1); } option_type = PIM_TLV_GET_TYPE(tlv_curr); tlv_curr += PIM_TLV_TYPE_SIZE; option_len = PIM_TLV_GET_LENGTH(tlv_curr); tlv_curr += PIM_TLV_LENGTH_SIZE; if ((tlv_curr + option_len) > tlv_pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: long PIM hello TLV type=%d length=%d > left=%td from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, tlv_pastend - tlv_curr, src_str, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-2); } if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: parse left_size=%d: PIM hello TLV type=%d length=%d from %s on %s", __PRETTY_FUNCTION__, remain, option_type, option_len, src_str, ifp->name); } switch (option_type) { case PIM_MSG_OPTION_TYPE_HOLDTIME: if (pim_tlv_parse_holdtime(ifp->name, src_addr, &hello_options, &hello_option_holdtime, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-3); } break; case PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY: if (pim_tlv_parse_lan_prune_delay(ifp->name, src_addr, &hello_options, &hello_option_propagation_delay, &hello_option_override_interval, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-4); } break; case PIM_MSG_OPTION_TYPE_DR_PRIORITY: if (pim_tlv_parse_dr_priority(ifp->name, src_addr, &hello_options, &hello_option_dr_priority, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-5); } break; case PIM_MSG_OPTION_TYPE_GENERATION_ID: if (pim_tlv_parse_generation_id(ifp->name, src_addr, &hello_options, &hello_option_generation_id, option_len, tlv_curr)) { FREE_ADDR_LIST_THEN_RETURN(-6); } break; case PIM_MSG_OPTION_TYPE_ADDRESS_LIST: if (pim_tlv_parse_addr_list(ifp->name, src_addr, &hello_options, &hello_option_addr_list, option_len, tlv_curr)) { return -7; } break; case PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH: if (PIM_DEBUG_PIM_TRACE || PIM_DEBUG_PIM_HELLO) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: ignoring PIM hello dense-mode state refresh TLV option type=%d length=%d from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, src_str, ifp->name); } break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: ignoring unknown PIM hello TLV type=%d length=%d from %s on interface %s", __PRETTY_FUNCTION__, option_type, option_len, src_str, ifp->name); } } tlv_curr += option_len; } /* Check received PIM hello options */ if (PIM_DEBUG_PIM_TRACE) { tlv_trace_uint16(__PRETTY_FUNCTION__, "holdtime", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME), hello_option_holdtime); tlv_trace_uint16(__PRETTY_FUNCTION__, "propagation_delay", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), hello_option_propagation_delay); tlv_trace_uint16(__PRETTY_FUNCTION__, "override_interval", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), hello_option_override_interval); tlv_trace_bool(__PRETTY_FUNCTION__, "can_disable_join_suppression", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY), PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)); tlv_trace_uint32(__PRETTY_FUNCTION__, "dr_priority", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY), hello_option_dr_priority); tlv_trace_uint32_hex(__PRETTY_FUNCTION__, "generation_id", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID), hello_option_generation_id); tlv_trace_list(__PRETTY_FUNCTION__, "address_list", ifp->name, src_addr, PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_ADDRESS_LIST), hello_option_addr_list); } if (!PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello missing holdtime from %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } /* New neighbor? */ neigh = pim_neighbor_find(ifp, src_addr); if (!neigh) { /* Add as new neighbor */ neigh = pim_neighbor_add(ifp, src_addr, hello_options, hello_option_holdtime, hello_option_propagation_delay, hello_option_override_interval, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list); if (!neigh) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: failure creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-8); } /* actual addr list has been saved under neighbor */ return 0; } /* Received generation ID ? */ if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_GENERATION_ID)) { /* GenID mismatch ? */ if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) || (hello_option_generation_id != neigh->generation_id)) { /* GenID changed */ pim_upstream_rpf_genid_changed(neigh->source_addr); /* GenID mismatch, then replace neighbor */ if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: GenId mismatch new=%08x old=%08x: replacing neighbor %s on %s", __PRETTY_FUNCTION__, hello_option_generation_id, neigh->generation_id, src_str, ifp->name); } pim_upstream_rpf_genid_changed(neigh->source_addr); pim_neighbor_delete(ifp, neigh, "GenID mismatch"); neigh = pim_neighbor_add(ifp, src_addr, hello_options, hello_option_holdtime, hello_option_propagation_delay, hello_option_override_interval, hello_option_dr_priority, hello_option_generation_id, hello_option_addr_list); if (!neigh) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: failure re-creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); FREE_ADDR_LIST_THEN_RETURN(-9); } /* actual addr list is saved under neighbor */ return 0; } /* GenId mismatch: replace neighbor */ } /* GenId received */ /* Update existing neighbor */ pim_neighbor_update(neigh, hello_options, hello_option_holdtime, hello_option_dr_priority, hello_option_addr_list); /* actual addr list is saved under neighbor */ return 0; } int pim_hello_build_tlv(const char *ifname, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, int can_disable_join_suppression, struct list *ifconnected) { uint8_t *curr = tlv_buf; uint8_t *pastend = tlv_buf + tlv_buf_size; uint8_t *tmp; /* * Append options */ /* Holdtime */ curr = pim_tlv_append_uint16(curr, pastend, PIM_MSG_OPTION_TYPE_HOLDTIME, holdtime); if (!curr) { zlog_warn("%s: could not set PIM hello Holdtime option for interface %s", __PRETTY_FUNCTION__, ifname); return -1; } /* LAN Prune Delay */ tmp = pim_tlv_append_2uint16(curr, pastend, PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY, propagation_delay, override_interval); if (!tmp) { zlog_warn("%s: could not set PIM LAN Prune Delay option for interface %s", __PRETTY_FUNCTION__, ifname); return -1; } if (can_disable_join_suppression) { *((uint8_t*)(curr) + 4) |= 0x80; /* enable T bit */ } curr = tmp; /* DR Priority */ curr = pim_tlv_append_uint32(curr, pastend, PIM_MSG_OPTION_TYPE_DR_PRIORITY, dr_priority); if (!curr) { zlog_warn("%s: could not set PIM hello DR Priority option for interface %s", __PRETTY_FUNCTION__, ifname); return -2; } /* Generation ID */ curr = pim_tlv_append_uint32(curr, pastend, PIM_MSG_OPTION_TYPE_GENERATION_ID, generation_id); if (!curr) { zlog_warn("%s: could not set PIM hello Generation ID option for interface %s", __PRETTY_FUNCTION__, ifname); return -3; } /* Secondary Address List */ if (ifconnected) { curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifconnected); if (!curr) { zlog_warn("%s: could not set PIM hello Secondary Address List option for interface %s", __PRETTY_FUNCTION__, ifname); return -4; } } return curr - tlv_buf; } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ void pim_hello_require(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->pim_ifstat_hello_sent) return; pim_hello_restart_now(ifp); /* Send hello and restart timer */ } quagga-0.99.24.1/pimd/pim_neighbor.c0000644000175000017500000004676112476520570014011 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "memory.h" #include "pimd.h" #include "pim_neighbor.h" #include "pim_time.h" #include "pim_str.h" #include "pim_iface.h" #include "pim_pim.h" #include "pim_upstream.h" #include "pim_ifchannel.h" static void dr_election_by_addr(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); pim_ifp->pim_dr_addr = pim_ifp->primary_address; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: on interface %s", __PRETTY_FUNCTION__, ifp->name); } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) { pim_ifp->pim_dr_addr = neigh->source_addr; } } } static void dr_election_by_pri(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; uint32_t dr_pri; pim_ifp = ifp->info; zassert(pim_ifp); pim_ifp->pim_dr_addr = pim_ifp->primary_address; dr_pri = pim_ifp->pim_dr_priority; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: dr pri %u on interface %s", __PRETTY_FUNCTION__, dr_pri, ifp->name); } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: neigh pri %u addr %x if dr addr %x", __PRETTY_FUNCTION__, neigh->dr_priority, ntohl(neigh->source_addr.s_addr), ntohl(pim_ifp->pim_dr_addr.s_addr)); } if ( (neigh->dr_priority > dr_pri) || ( (neigh->dr_priority == dr_pri) && (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) ) ) { pim_ifp->pim_dr_addr = neigh->source_addr; dr_pri = neigh->dr_priority; } } } /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ void pim_if_dr_election(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr old_dr_addr; ++pim_ifp->pim_dr_election_count; old_dr_addr = pim_ifp->pim_dr_addr; if (pim_ifp->pim_dr_num_nondrpri_neighbors) { dr_election_by_addr(ifp); } else { dr_election_by_pri(ifp); } /* DR changed ? */ if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) { /* if (PIM_DEBUG_PIM_EVENTS) */ { char dr_old_str[100]; char dr_new_str[100]; pim_inet4_dump("", old_dr_addr, dr_old_str, sizeof(dr_old_str)); pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str)); zlog_debug("%s: DR was %s now is %s on interface %s", __PRETTY_FUNCTION__, dr_old_str, dr_new_str, ifp->name); } pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */ ++pim_ifp->pim_dr_election_changes; pim_if_update_join_desired(pim_ifp); pim_if_update_could_assert(ifp); pim_if_update_assert_tracking_desired(ifp); } } static void update_dr_priority(struct pim_neighbor *neigh, pim_hello_options hello_options, uint32_t dr_priority) { pim_hello_options will_set_pri; /* boolean */ pim_hello_options bit_flip; /* boolean */ pim_hello_options pri_change; /* boolean */ will_set_pri = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY); bit_flip = ( will_set_pri != PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ); if (bit_flip) { struct pim_interface *pim_ifp = neigh->interface->info; /* update num. of neighbors without dr_pri */ if (will_set_pri) { --pim_ifp->pim_dr_num_nondrpri_neighbors; } else { ++pim_ifp->pim_dr_num_nondrpri_neighbors; } } pri_change = ( bit_flip || (neigh->dr_priority != dr_priority) ); if (will_set_pri) { neigh->dr_priority = dr_priority; } else { neigh->dr_priority = 0; /* cosmetic unset */ } if (pri_change) { /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(neigh->interface); // router's own DR Priority changes } } static int on_neighbor_timer(struct thread *t) { struct pim_neighbor *neigh; struct interface *ifp; char msg[100]; zassert(t); neigh = THREAD_ARG(t); zassert(neigh); ifp = neigh->interface; if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s", neigh->holdtime, src_str, ifp->name); } neigh->t_expire_timer = 0; snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime); pim_neighbor_delete(ifp, neigh, msg); /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(ifp); // neighbor times out return 0; } static void neighbor_timer_off(struct pim_neighbor *neigh) { if (PIM_DEBUG_PIM_TRACE) { if (neigh->t_expire_timer) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("%s: cancelling timer for neighbor %s on %s", __PRETTY_FUNCTION__, src_str, neigh->interface->name); } } THREAD_OFF(neigh->t_expire_timer); zassert(!neigh->t_expire_timer); } void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime) { neigh->holdtime = holdtime; neighbor_timer_off(neigh); /* 0xFFFF is request for no holdtime */ if (neigh->holdtime == 0xFFFF) { return; } if (PIM_DEBUG_PIM_TRACE) { char src_str[100]; pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_debug("%s: starting %u sec timer for neighbor %s on %s", __PRETTY_FUNCTION__, neigh->holdtime, src_str, neigh->interface->name); } THREAD_TIMER_ON(master, neigh->t_expire_timer, on_neighbor_timer, neigh, neigh->holdtime); } static struct pim_neighbor *pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; char src_str[100]; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh)); if (!neigh) { zlog_err("%s: PIM XMALLOC(%zu) failure", __PRETTY_FUNCTION__, sizeof(*neigh)); return 0; } neigh->creation = pim_time_monotonic_sec(); neigh->source_addr = source_addr; neigh->hello_options = hello_options; neigh->propagation_delay_msec = propagation_delay; neigh->override_interval_msec = override_interval; neigh->dr_priority = dr_priority; neigh->generation_id = generation_id; neigh->prefix_list = addr_list; neigh->t_expire_timer = 0; neigh->interface = ifp; pim_neighbor_timer_reset(neigh, holdtime); pim_inet4_dump("", source_addr, src_str, sizeof(src_str)); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("%s: creating PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str, ifp->name); if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) { pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec; } if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) { pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { /* update num. of neighbors without hello option lan_delay */ ++pim_ifp->pim_number_of_nonlandelay_neighbors; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)) { /* update num. of neighbors without hello option dr_pri */ ++pim_ifp->pim_dr_num_nondrpri_neighbors; } /* RFC 4601: 4.3.2. DR Election A router's idea of the current DR on an interface can change when a PIM Hello message is received, when a neighbor times out, or when a router's own DR Priority changes. */ pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election... /* RFC 4601: 4.3.1. Sending Hello Messages To allow new or rebooting routers to learn of PIM neighbors quickly, when a Hello message is received from a new neighbor, or a Hello message with a new GenID is received from an existing neighbor, a new Hello message should be sent on this interface after a randomized delay between 0 and Triggered_Hello_Delay. */ pim_hello_restart_triggered(neigh->interface); return neigh; } static void delete_prefix_list(struct pim_neighbor *neigh) { if (neigh->prefix_list) { #ifdef DUMP_PREFIX_LIST struct listnode *p_node; struct prefix *p; char addr_str[10]; int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1; int i = 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) { pim_inet4_dump("", p->u.prefix4, addr_str, sizeof(addr_str)); zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]", __PRETTY_FUNCTION__, (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p, addr_str, i, list_size); ++i; } #endif list_delete(neigh->prefix_list); neigh->prefix_list = 0; } } void pim_neighbor_free(struct pim_neighbor *neigh) { zassert(!neigh->t_expire_timer); delete_prefix_list(neigh); XFREE(MTYPE_PIM_NEIGHBOR, neigh); } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct listnode *node; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) { if (source_addr.s_addr == neigh->source_addr.s_addr) { return neigh; } } return 0; } struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list) { struct pim_interface *pim_ifp; struct pim_neighbor *neigh; neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime, propagation_delay, override_interval, dr_priority, generation_id, addr_list); if (!neigh) { return 0; } pim_ifp = ifp->info; zassert(pim_ifp); listnode_add(pim_ifp->pim_neighbor_list, neigh); return neigh; } static uint16_t find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp, struct pim_neighbor *highest_neigh) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct pim_neighbor *neigh; uint16_t next_highest_delay_msec; pim_ifp = ifp->info; zassert(pim_ifp); next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { if (neigh == highest_neigh) continue; if (neigh->propagation_delay_msec > next_highest_delay_msec) next_highest_delay_msec = neigh->propagation_delay_msec; } return next_highest_delay_msec; } static uint16_t find_neighbors_next_highest_override_interval_msec(struct interface *ifp, struct pim_neighbor *highest_neigh) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct pim_neighbor *neigh; uint16_t next_highest_interval_msec; pim_ifp = ifp->info; zassert(pim_ifp); next_highest_interval_msec = pim_ifp->pim_override_interval_msec; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { if (neigh == highest_neigh) continue; if (neigh->override_interval_msec > next_highest_interval_msec) next_highest_interval_msec = neigh->override_interval_msec; } return next_highest_interval_msec; } void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message) { struct pim_interface *pim_ifp; char src_str[100]; pim_ifp = ifp->info; zassert(pim_ifp); pim_inet4_dump("", neigh->source_addr, src_str, sizeof(src_str)); zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", src_str, ifp->name, delete_message); neighbor_timer_off(neigh); pim_if_assert_on_neighbor_down(ifp, neigh->source_addr); if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY)) { /* update num. of neighbors without hello option lan_delay */ --pim_ifp->pim_number_of_nonlandelay_neighbors; } if (!PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)) { /* update num. of neighbors without dr_pri */ --pim_ifp->pim_dr_num_nondrpri_neighbors; } zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec); zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec); if (pim_if_lan_delay_enabled(ifp)) { /* will delete a neighbor with highest propagation delay? */ if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) { /* then find the next highest propagation delay */ pim_ifp->pim_neighbors_highest_propagation_delay_msec = find_neighbors_next_highest_propagation_delay_msec(ifp, neigh); } /* will delete a neighbor with highest override interval? */ if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) { /* then find the next highest propagation delay */ pim_ifp->pim_neighbors_highest_override_interval_msec = find_neighbors_next_highest_override_interval_msec(ifp, neigh); } } if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: deleting PIM neighbor %s on interface %s", __PRETTY_FUNCTION__, src_str, ifp->name); } listnode_delete(pim_ifp->pim_neighbor_list, neigh); pim_neighbor_free(neigh); } void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message) { struct pim_interface *pim_ifp; struct listnode *neigh_node; struct listnode *neigh_nextnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node, neigh_nextnode, neigh)) { pim_neighbor_delete(ifp, neigh, delete_message); } } struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, struct in_addr addr) { struct listnode *node; struct prefix *p; if (!neigh->prefix_list) return 0; for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) { if (p->family == AF_INET) { if (addr.s_addr == p->u.prefix4.s_addr) { return p; } } } return 0; } /* RFC 4601: 4.3.4. Maintaining Secondary Address Lists All the advertised secondary addresses in received Hello messages must be checked against those previously advertised by all other PIM neighbors on that interface. If there is a conflict and the same secondary address was previously advertised by another neighbor, then only the most recently received mapping MUST be maintained, and an error message SHOULD be logged to the administrator in a rate-limited manner. */ static void delete_from_neigh_addr(struct interface *ifp, struct list *addr_list, struct in_addr neigh_addr) { struct listnode *addr_node; struct prefix *addr; struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); zassert(addr_list); /* Scan secondary address list */ for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) { struct listnode *neigh_node; struct pim_neighbor *neigh; if (addr->family != AF_INET) continue; /* Scan neighbors */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) { { struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4); if (p) { char addr_str[100]; char this_neigh_str[100]; char other_neigh_str[100]; pim_inet4_dump("", addr->u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("", neigh_addr, this_neigh_str, sizeof(this_neigh_str)); pim_inet4_dump("", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str)); zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s", addr_str, this_neigh_str, other_neigh_str, ifp->name); listnode_delete(neigh->prefix_list, p); prefix_free(p); } } } /* scan neighbors */ } /* scan addr list */ } void pim_neighbor_update(struct pim_neighbor *neigh, pim_hello_options hello_options, uint16_t holdtime, uint32_t dr_priority, struct list *addr_list) { struct pim_interface *pim_ifp = neigh->interface->info; /* Received holdtime ? */ if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) { pim_neighbor_timer_reset(neigh, holdtime); } else { pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } #ifdef DUMP_PREFIX_LIST zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d", __PRETTY_FUNCTION__, (unsigned) neigh->prefix_list, neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1, (unsigned) addr_list, addr_list ? (int) listcount(addr_list) : -1); #endif if (neigh->prefix_list == addr_list) { if (addr_list) { zlog_err("%s: internal error: trying to replace same prefix list=%p", __PRETTY_FUNCTION__, (void *) addr_list); } } else { /* Delete existing secondary address list */ delete_prefix_list(neigh); } if (addr_list) { delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr); } /* Replace secondary address list */ neigh->prefix_list = addr_list; update_dr_priority(neigh, hello_options, dr_priority); /* Copy flags */ neigh->hello_options = hello_options; } quagga-0.99.24.1/pimd/pim_tlv.c0000644000175000017500000004712012476520570013007 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "prefix.h" #include "pimd.h" #include "pim_int.h" #include "pim_tlv.h" #include "pim_str.h" #include "pim_msg.h" uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value) { uint16_t option_len = 2; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; } *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; *(uint16_t *) buf = htons(option_value); buf += option_len; return buf; } uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2) { uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; } *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; *(uint16_t *) buf = htons(option_value1); buf += 2; *(uint16_t *) buf = htons(option_value2); buf += 2; return buf; } uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value) { uint16_t option_len = 4; if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) { zlog_warn("%s: buffer overflow: left=%zd needed=%d", __PRETTY_FUNCTION__, buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len)); return 0; } *(uint16_t *) buf = htons(option_type); buf += 2; *(uint16_t *) buf = htons(option_len); buf += 2; pim_write_uint32(buf, option_value); buf += option_len; return buf; } #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected) { struct listnode *node; uint16_t option_len = 0; uint8_t *curr; node = listhead(ifconnected); /* Empty address list ? */ if (!node) { return buf; } /* Skip first address (primary) */ node = listnextnode(node); /* Scan secondary address list */ curr = buf + 4; /* skip T and L */ for (; node; node = listnextnode(node)) { struct connected *ifc = listgetdata(node); struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if ((curr + ucast_ipv4_encoding_len) > buf_pastend) { zlog_warn("%s: buffer overflow: left=%zd needed=%zu", __PRETTY_FUNCTION__, buf_pastend - curr, ucast_ipv4_encoding_len); return 0; } /* Write encoded unicast IPv4 address */ *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ ++curr; *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ ++curr; memcpy(curr, &p->u.prefix4, sizeof(struct in_addr)); curr += sizeof(struct in_addr); option_len += ucast_ipv4_encoding_len; } if (PIM_DEBUG_PIM_TRACE) { zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %zu", __PRETTY_FUNCTION__, option_len / ucast_ipv4_encoding_len); } if (option_len < 1) { /* Empty secondary unicast IPv4 address list */ return buf; } /* * Write T and L */ *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); *(uint16_t *) (buf + 2) = htons(option_len); return curr; } static int check_tlv_length(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, int correct_len, int option_len) { if (option_len != correct_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", label, tlv_name, option_len, correct_len, src_str, ifname); return -1; } return 0; } static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint16_t new, uint16_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, const char *ifname, struct in_addr src_addr, pim_hello_options options, pim_hello_options opt_mask, uint32_t new, uint32_t old) { if (PIM_OPTION_IS_SET(options, opt_mask)) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", label, tlv_name, new, old, src_str, ifname); } } int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "holdtime"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint16_t), option_len)) { return -1; } check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_HOLDTIME, PIM_TLV_GET_HOLDTIME(tlv_curr), *hello_option_holdtime); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); return 0; } int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr) { if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", ifname, src_addr, *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), *hello_option_propagation_delay); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); } else { PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); } ++tlv_curr; ++tlv_curr; *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); return 0; } int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "dr_priority"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_DR_PRIORITY, PIM_TLV_GET_DR_PRIORITY(tlv_curr), *hello_option_dr_priority); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); return 0; } int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr) { const char *label = "generation_id"; if (check_tlv_length(__PRETTY_FUNCTION__, label, ifname, src_addr, sizeof(uint32_t), option_len)) { return -1; } check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, ifname, src_addr, *hello_options, PIM_OPTION_MASK_GENERATION_ID, PIM_TLV_GET_GENERATION_ID(tlv_curr), *hello_option_generation_id); PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); return 0; } int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size) { const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; if (buf_size < ucast_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, ucast_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s", __PRETTY_FUNCTION__, type, src_str, ifname); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s", __PRETTY_FUNCTION__, family, src_str, ifname); return -4; } } return addr - buf; } int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; int mask_len; if (buf_size < grp_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, grp_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; //++addr; ++addr; /* skip b_reserved_z fields */ mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown group address encoding type=%d from %s on %s", __PRETTY_FUNCTION__, type, src_str, ifname); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown group address encoding family=%d from %s on %s", __PRETTY_FUNCTION__, family, src_str, ifname); return -4; } } return addr - buf; } int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, const uint8_t *buf, int buf_size) { const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ const uint8_t *addr; const uint8_t *pastend; int family; int type; int mask_len; if (buf_size < src_encoding_min_len) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s", __PRETTY_FUNCTION__, buf_size, src_encoding_min_len, src_str, ifname); return -1; } addr = buf; pastend = buf + buf_size; family = *addr++; type = *addr++; *flags = *addr++; mask_len = *addr++; switch (family) { case PIM_MSG_ADDRESS_FAMILY_IPV4: if (type) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, type, src_str, ifname, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -2; } if ((addr + sizeof(struct in_addr)) > pastend) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s", __PRETTY_FUNCTION__, pastend - addr, sizeof(struct in_addr), src_str, ifname); return -3; } p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); p->prefixlen = mask_len; /* RFC 4601: 4.9.1 Encoded Source and Group Address Formats Encoded-Source Address The mask length MUST be equal to the mask length in bits for the given Address Family and Encoding Type (32 for IPv4 native and 128 for IPv6 native). A router SHOULD ignore any messages received with any other mask length. */ if (p->prefixlen != 32) { char src_str[100]; pim_inet4_dump("", p->u.prefix4, src_str, sizeof(src_str)); zlog_warn("%s: IPv4 bad source address mask: %s/%d", __PRETTY_FUNCTION__, src_str, p->prefixlen); return -4; } addr += sizeof(struct in_addr); break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", __PRETTY_FUNCTION__, family, src_str, ifname, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); return -5; } } return addr - buf; } #define FREE_ADDR_LIST(hello_option_addr_list) \ { \ if (hello_option_addr_list) { \ list_delete(hello_option_addr_list); \ hello_option_addr_list = 0; \ } \ } int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr) { const uint8_t *addr; const uint8_t *pastend; zassert(hello_option_addr_list); /* Scan addr list */ addr = tlv_curr; pastend = tlv_curr + option_len; while (addr < pastend) { struct prefix tmp; int addr_offset; /* Parse ucast addr */ addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp, addr, pastend - addr); if (addr_offset < 1) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", __PRETTY_FUNCTION__, src_str, ifname); FREE_ADDR_LIST(*hello_option_addr_list); return -1; } addr += addr_offset; /* Debug */ if (PIM_DEBUG_PIM_TRACE) { switch (tmp.family) { case AF_INET: { char addr_str[100]; char src_str[100]; pim_inet4_dump("", tmp.u.prefix4, addr_str, sizeof(addr_str)); pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", __PRETTY_FUNCTION__, *hello_option_addr_list ? ((int) listcount(*hello_option_addr_list)) : -1, addr_str, src_str, ifname); } break; default: { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", __PRETTY_FUNCTION__, *hello_option_addr_list ? ((int) listcount(*hello_option_addr_list)) : -1, src_str, ifname); } } } /* Exclude neighbor's primary address if incorrectly included in the secondary address list */ if (tmp.family == AF_INET) { if (tmp.u.prefix4.s_addr == src_addr.s_addr) { char src_str[100]; pim_inet4_dump("", src_addr, src_str, sizeof(src_str)); zlog_warn("%s: ignoring primary address in secondary list from %s on %s", __PRETTY_FUNCTION__, src_str, ifname); continue; } } /* Allocate list if needed */ if (!*hello_option_addr_list) { *hello_option_addr_list = list_new(); if (!*hello_option_addr_list) { zlog_err("%s %s: failure: hello_option_addr_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return -2; } (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; } /* Attach addr to list */ { struct prefix *p; p = prefix_new(); if (!p) { zlog_err("%s %s: failure: prefix_new()", __FILE__, __PRETTY_FUNCTION__); FREE_ADDR_LIST(*hello_option_addr_list); return -3; } p->family = tmp.family; p->u.prefix4 = tmp.u.prefix4; listnode_add(*hello_option_addr_list, p); } } /* while (addr < pastend) */ /* Mark hello option */ PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); return 0; } quagga-0.99.24.1/pimd/pim_pim.c0000644000175000017500000004640212476520570012771 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "thread.h" #include "memory.h" #include "pimd.h" #include "pim_pim.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_sock.h" #include "pim_str.h" #include "pim_util.h" #include "pim_tlv.h" #include "pim_neighbor.h" #include "pim_hello.h" #include "pim_join.h" #include "pim_assert.h" #include "pim_msg.h" #include "pim_rand.h" static int on_pim_hello_send(struct thread *t); static int pim_hello_send(struct interface *ifp, uint16_t holdtime); static void sock_close(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; if (PIM_DEBUG_PIM_TRACE) { if (pim_ifp->t_pim_sock_read) { zlog_debug("Cancelling READ event for PIM socket fd=%d on interface %s", pim_ifp->pim_sock_fd, ifp->name); } } THREAD_OFF(pim_ifp->t_pim_sock_read); if (PIM_DEBUG_PIM_TRACE) { if (pim_ifp->t_pim_hello_timer) { zlog_debug("Cancelling PIM hello timer for interface %s", ifp->name); } } THREAD_OFF(pim_ifp->t_pim_hello_timer); if (PIM_DEBUG_PIM_TRACE) { zlog_debug("Deleting PIM socket fd=%d on interface %s", pim_ifp->pim_sock_fd, ifp->name); } if (close(pim_ifp->pim_sock_fd)) { zlog_warn("Failure closing PIM socket fd=%d on interface %s: errno=%d: %s", pim_ifp->pim_sock_fd, ifp->name, errno, safe_strerror(errno)); } pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_creation = 0; zassert(pim_ifp->pim_sock_fd < 0); zassert(!pim_ifp->t_pim_sock_read); zassert(!pim_ifp->t_pim_hello_timer); zassert(!pim_ifp->pim_sock_creation); } void pim_sock_delete(struct interface *ifp, const char *delete_message) { zlog_info("PIM INTERFACE DOWN: on interface %s: %s", ifp->name, delete_message); if (!ifp->info) { zlog_err("%s: %s: but PIM not enabled on interface %s (!)", __PRETTY_FUNCTION__, delete_message, ifp->name); return; } /* RFC 4601: 4.3.1. Sending Hello Messages Before an interface goes down or changes primary IP address, a Hello message with a zero HoldTime should be sent immediately (with the old IP address if the IP address changed). */ pim_hello_send(ifp, 0 /* zero-sec holdtime */); pim_neighbor_delete_all(ifp, delete_message); sock_close(ifp); } int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len) { struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ char src_str[100]; char dst_str[100]; uint8_t *pim_msg; int pim_msg_len; uint8_t pim_version; uint8_t pim_type; uint16_t pim_checksum; /* received checksum */ uint16_t checksum; /* computed checksum */ struct pim_neighbor *neigh; if (!ifp->info) { zlog_warn("%s: PIM not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (len < sizeof(*ip_hdr)) { zlog_warn("PIM packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } ip_hdr = (struct ip *) buf; pim_inet4_dump("", ip_hdr->ip_src, src_str, sizeof(src_str)); pim_inet4_dump("", ip_hdr->ip_dst, dst_str, sizeof(dst_str)); ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", src_str, dst_str, ifp->name, len, ip_hlen, ip_hdr->ip_p); } if (ip_hdr->ip_p != PIM_IP_PROTO_PIM) { zlog_warn("IP packet protocol=%d is not PIM=%d", ip_hdr->ip_p, PIM_IP_PROTO_PIM); return -1; } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } pim_msg = buf + ip_hlen; pim_msg_len = len - ip_hlen; if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_len); } if (pim_msg_len < PIM_PIM_MIN_LEN) { zlog_warn("PIM message size=%d shorter than minimum=%d", pim_msg_len, PIM_PIM_MIN_LEN); return -1; } pim_version = PIM_MSG_HDR_GET_VERSION(pim_msg); pim_type = PIM_MSG_HDR_GET_TYPE(pim_msg); if (pim_version != PIM_PROTO_VERSION) { zlog_warn("Ignoring PIM pkt from %s with unsupported version: %d", ifp->name, pim_version); return -1; } /* save received checksum */ pim_checksum = PIM_MSG_HDR_GET_CHECKSUM(pim_msg); /* for computing checksum */ *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) = 0; checksum = in_cksum(pim_msg, pim_msg_len); if (checksum != pim_checksum) { zlog_warn("Ignoring PIM pkt from %s with invalid checksum: received=%x calculated=%x", ifp->name, pim_checksum, checksum); return -1; } if (PIM_DEBUG_PIM_PACKETS) { zlog_debug("Recv PIM packet from %s to %s on %s: ttl=%d pim_version=%d pim_type=%d pim_msg_size=%d checksum=%x", src_str, dst_str, ifp->name, ip_hdr->ip_ttl, pim_version, pim_type, pim_msg_len, checksum); } if (pim_type == PIM_MSG_TYPE_HELLO) { int result = pim_hello_recv(ifp, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); if (!result) { pim_if_dr_election(ifp); /* PIM Hello message is received */ } return result; } neigh = pim_neighbor_find(ifp, ip_hdr->ip_src); if (!neigh) { zlog_warn("%s %s: non-hello PIM message type=%d from non-neighbor %s on %s", __FILE__, __PRETTY_FUNCTION__, pim_type, src_str, ifp->name); return -1; } switch (pim_type) { case PIM_MSG_TYPE_JOIN_PRUNE: return pim_joinprune_recv(ifp, neigh, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); case PIM_MSG_TYPE_ASSERT: return pim_assert_recv(ifp, neigh, ip_hdr->ip_src, pim_msg + PIM_MSG_HEADER_LEN, pim_msg_len - PIM_MSG_HEADER_LEN); default: zlog_warn("%s %s: unsupported PIM message type=%d from %s on %s", __FILE__, __PRETTY_FUNCTION__, pim_type, src_str, ifp->name); } return -1; } static void pim_sock_read_on(struct interface *ifp); static int pim_sock_read(struct thread *t) { struct interface *ifp; struct pim_interface *pim_ifp; int fd; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); uint8_t buf[PIM_PIM_BUFSIZE_READ]; int len; int ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); ifp = THREAD_ARG(t); zassert(ifp); fd = THREAD_FD(t); pim_ifp = ifp->info; zassert(pim_ifp); zassert(fd == pim_ifp->pim_sock_fd); len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { zlog_warn("Failure receiving IP PIM packet on fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); goto done; } if (PIM_DEBUG_PIM_PACKETS) { char from_str[100]; char to_str[100]; if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) sprintf(to_str, ""); zlog_debug("Recv IP PIM pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", len, from_str, to_str, fd, ifindex, ifp->ifindex); } if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { pim_pkt_dump(__PRETTY_FUNCTION__, buf, len); } #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ if (ifindex != (int) ifp->ifindex) { char from_str[100]; char to_str[100]; struct interface *recv_ifp; if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) sprintf(to_str, ""); recv_ifp = if_lookup_by_index(ifindex); if (recv_ifp) { zassert(ifindex == (int) recv_ifp->ifindex); } #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_warn("Interface mismatch: recv PIM pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", from_str, to_str, fd, ifindex, recv_ifp ? recv_ifp->name : "", ifp->ifindex, ifp->name); #endif goto done; } #endif int fail = pim_pim_packet(ifp, buf, len); if (fail) { zlog_warn("%s: pim_pim_packet() return=%d", __PRETTY_FUNCTION__, fail); goto done; } result = 0; /* good */ done: pim_sock_read_on(ifp); if (result) { ++pim_ifp->pim_ifstat_hello_recvfail; } return result; } static void pim_sock_read_on(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); zassert(ifp->info); pim_ifp = ifp->info; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("Scheduling READ event on PIM socket fd=%d", pim_ifp->pim_sock_fd); } pim_ifp->t_pim_sock_read = 0; zassert(!pim_ifp->t_pim_sock_read); THREAD_READ_ON(master, pim_ifp->t_pim_sock_read, pim_sock_read, ifp, pim_ifp->pim_sock_fd); } static int pim_sock_open(struct in_addr ifaddr, int ifindex) { int fd; fd = pim_socket_mcast(IPPROTO_PIM, ifaddr, 0 /* loop=false */); if (fd < 0) return -1; if (pim_socket_join(fd, qpim_all_pim_routers_addr, ifaddr, ifindex)) { return -2; } return fd; } void pim_ifstat_reset(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { return; } pim_ifp->pim_ifstat_start = pim_time_monotonic_sec(); pim_ifp->pim_ifstat_hello_sent = 0; pim_ifp->pim_ifstat_hello_sendfail = 0; pim_ifp->pim_ifstat_hello_recv = 0; pim_ifp->pim_ifstat_hello_recvfail = 0; } void pim_sock_reset(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); zassert(ifp->info); pim_ifp = ifp->info; pim_ifp->primary_address = pim_find_primary_addr(ifp); pim_ifp->pim_sock_fd = -1; pim_ifp->pim_sock_creation = 0; pim_ifp->t_pim_sock_read = 0; pim_ifp->t_pim_hello_timer = 0; pim_ifp->pim_hello_period = PIM_DEFAULT_HELLO_PERIOD; pim_ifp->pim_default_holdtime = -1; /* unset: means 3.5 * pim_hello_period */ pim_ifp->pim_triggered_hello_delay = PIM_DEFAULT_TRIGGERED_HELLO_DELAY; pim_ifp->pim_dr_priority = PIM_DEFAULT_DR_PRIORITY; pim_ifp->pim_propagation_delay_msec = PIM_DEFAULT_PROPAGATION_DELAY_MSEC; pim_ifp->pim_override_interval_msec = PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; if (PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION) { PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); } else { PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options); } /* neighbors without lan_delay */ pim_ifp->pim_number_of_nonlandelay_neighbors = 0; pim_ifp->pim_neighbors_highest_propagation_delay_msec = 0; pim_ifp->pim_neighbors_highest_override_interval_msec = 0; /* DR Election */ pim_ifp->pim_dr_election_last = 0; /* timestamp */ pim_ifp->pim_dr_election_count = 0; pim_ifp->pim_dr_election_changes = 0; pim_ifp->pim_dr_num_nondrpri_neighbors = 0; /* neighbors without dr_pri */ pim_ifp->pim_dr_addr = pim_ifp->primary_address; pim_ifstat_reset(ifp); } int pim_msg_send(int fd, struct in_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname) { ssize_t sent; struct sockaddr_in to; socklen_t tolen; if (PIM_DEBUG_PIM_PACKETS) { char dst_str[100]; pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: msg_size=%d checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, pim_msg_size, *(uint16_t *) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)); } #if 0 memset(&to, 0, sizeof(to)); #endif to.sin_family = AF_INET; to.sin_addr = dst; #if 0 to.sin_port = htons(0); #endif tolen = sizeof(to); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { pim_pkt_dump(__PRETTY_FUNCTION__, pim_msg, pim_msg_size); } sent = sendto(fd, pim_msg, pim_msg_size, MSG_DONTWAIT, &to, tolen); if (sent != (ssize_t) pim_msg_size) { int e = errno; char dst_str[100]; pim_inet4_dump("", dst, dst_str, sizeof(dst_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s on %s: fd=%d msg_size=%d: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: fd=%d msg_size=%d: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, fd, pim_msg_size, sent); } return -1; } return 0; } static int hello_send(struct interface *ifp, uint16_t holdtime) { uint8_t pim_msg[PIM_PIM_BUFSIZE_WRITE]; struct pim_interface *pim_ifp; int pim_tlv_size; int pim_msg_size; pim_ifp = ifp->info; if (PIM_DEBUG_PIM_PACKETS || PIM_DEBUG_PIM_HELLO) { char dst_str[100]; pim_inet4_dump("", qpim_all_pim_routers_addr, dst_str, sizeof(dst_str)); zlog_debug("%s: to %s on %s: holdt=%u prop_d=%u overr_i=%u dis_join_supp=%d dr_prio=%u gen_id=%08x addrs=%d", __PRETTY_FUNCTION__, dst_str, ifp->name, holdtime, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, listcount(ifp->connected)); } pim_tlv_size = pim_hello_build_tlv(ifp->name, pim_msg + PIM_PIM_MIN_LEN, sizeof(pim_msg) - PIM_PIM_MIN_LEN, holdtime, pim_ifp->pim_dr_priority, pim_ifp->pim_generation_id, pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options), ifp->connected); if (pim_tlv_size < 0) { return -1; } pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; zassert(pim_msg_size >= PIM_PIM_MIN_LEN); zassert(pim_msg_size <= PIM_PIM_BUFSIZE_WRITE); pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO); if (pim_msg_send(pim_ifp->pim_sock_fd, qpim_all_pim_routers_addr, pim_msg, pim_msg_size, ifp->name)) { zlog_warn("%s: could not send PIM message on interface %s", __PRETTY_FUNCTION__, ifp->name); return -2; } return 0; } static int pim_hello_send(struct interface *ifp, uint16_t holdtime) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (hello_send(ifp, holdtime)) { ++pim_ifp->pim_ifstat_hello_sendfail; zlog_warn("Could not send PIM hello on interface %s", ifp->name); return -1; } ++pim_ifp->pim_ifstat_hello_sent; return 0; } static void hello_resched(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (PIM_DEBUG_PIM_TRACE) { zlog_debug("Rescheduling %d sec hello on interface %s", pim_ifp->pim_hello_period, ifp->name); } THREAD_OFF(pim_ifp->t_pim_hello_timer); THREAD_TIMER_ON(master, pim_ifp->t_pim_hello_timer, on_pim_hello_send, ifp, pim_ifp->pim_hello_period); } /* Periodic hello timer */ static int on_pim_hello_send(struct thread *t) { struct pim_interface *pim_ifp; struct interface *ifp; zassert(t); ifp = THREAD_ARG(t); zassert(ifp); pim_ifp = ifp->info; /* * Schedule next hello */ pim_ifp->t_pim_hello_timer = 0; hello_resched(ifp); /* * Send hello */ return pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } /* RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. */ void pim_hello_restart_now(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); /* * Reset next hello timer */ hello_resched(ifp); /* * Immediately send hello */ pim_hello_send(ifp, PIM_IF_DEFAULT_HOLDTIME(pim_ifp)); } /* RFC 4601: 4.3.1. Sending Hello Messages To allow new or rebooting routers to learn of PIM neighbors quickly, when a Hello message is received from a new neighbor, or a Hello message with a new GenID is received from an existing neighbor, a new Hello message should be sent on this interface after a randomized delay between 0 and Triggered_Hello_Delay. */ void pim_hello_restart_triggered(struct interface *ifp) { struct pim_interface *pim_ifp; int triggered_hello_delay_msec; int random_msec; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); triggered_hello_delay_msec = 1000 * pim_ifp->pim_triggered_hello_delay; if (pim_ifp->t_pim_hello_timer) { long remain_msec = pim_time_timer_remain_msec(pim_ifp->t_pim_hello_timer); if (remain_msec <= triggered_hello_delay_msec) { /* Rescheduling hello would increase the delay, then it's faster to just wait for the scheduled periodic hello. */ return; } THREAD_OFF(pim_ifp->t_pim_hello_timer); pim_ifp->t_pim_hello_timer = 0; } zassert(!pim_ifp->t_pim_hello_timer); random_msec = pim_rand_next(0, triggered_hello_delay_msec); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug("Scheduling %d msec triggered hello on interface %s", random_msec, ifp->name); } THREAD_TIMER_MSEC_ON(master, pim_ifp->t_pim_hello_timer, on_pim_hello_send, ifp, random_msec); } int pim_sock_add(struct interface *ifp) { struct pim_interface *pim_ifp; struct in_addr ifaddr; pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->pim_sock_fd >= 0) { zlog_warn("Can't recreate existing PIM socket fd=%d for interface %s", pim_ifp->pim_sock_fd, ifp->name); return -1; } ifaddr = pim_ifp->primary_address; pim_ifp->pim_sock_fd = pim_sock_open(ifaddr, ifp->ifindex); if (pim_ifp->pim_sock_fd < 0) { zlog_warn("Could not open PIM socket on interface %s", ifp->name); return -2; } pim_ifp->t_pim_sock_read = 0; pim_ifp->pim_sock_creation = pim_time_monotonic_sec(); pim_ifp->pim_generation_id = pim_rand() & (int64_t) 0xFFFFFFFF; zlog_info("PIM INTERFACE UP: on interface %s ifindex=%d", ifp->name, ifp->ifindex); /* * Start receiving PIM messages */ pim_sock_read_on(ifp); /* * Start sending PIM hello's */ pim_hello_restart_triggered(ifp); return 0; } quagga-0.99.24.1/pimd/pim_zlookup.c0000644000175000017500000003125512476520570013707 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "log.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "thread.h" #include "pimd.h" #include "pim_pim.h" #include "pim_str.h" #include "pim_zlookup.h" extern int zclient_debug; static void zclient_lookup_sched(struct zclient *zlookup, int delay); /* Connect to zebra for nexthop lookup. */ static int zclient_lookup_connect(struct thread *t) { struct zclient *zlookup; zlookup = THREAD_ARG(t); zlookup->t_connect = NULL; if (zlookup->sock >= 0) { return 0; } if (zclient_socket_connect(zlookup) < 0) { ++zlookup->fail; zlog_warn("%s: failure connecting zclient socket: failures=%d", __PRETTY_FUNCTION__, zlookup->fail); } else { zlookup->fail = 0; /* reset counter on connection */ } zassert(!zlookup->t_connect); if (zlookup->sock < 0) { /* Since last connect failed, retry within 10 secs */ zclient_lookup_sched(zlookup, 10); return -1; } return 0; } /* Schedule connection with delay. */ static void zclient_lookup_sched(struct zclient *zlookup, int delay) { zassert(!zlookup->t_connect); THREAD_TIMER_ON(master, zlookup->t_connect, zclient_lookup_connect, zlookup, delay); zlog_notice("%s: zclient lookup connection scheduled for %d seconds", __PRETTY_FUNCTION__, delay); } /* Schedule connection for now. */ static void zclient_lookup_sched_now(struct zclient *zlookup) { zassert(!zlookup->t_connect); zlookup->t_connect = thread_add_event(master, zclient_lookup_connect, zlookup, 0); zlog_notice("%s: zclient lookup immediate connection scheduled", __PRETTY_FUNCTION__); } /* Schedule reconnection, if needed. */ static void zclient_lookup_reconnect(struct zclient *zlookup) { if (zlookup->t_connect) { return; } zclient_lookup_sched_now(zlookup); } static void zclient_lookup_failed(struct zclient *zlookup) { if (zlookup->sock >= 0) { if (close(zlookup->sock)) { zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock, errno, safe_strerror(errno)); } zlookup->sock = -1; } zclient_lookup_reconnect(zlookup); } struct zclient *zclient_lookup_new() { struct zclient *zlookup; zlookup = zclient_new(); if (!zlookup) { zlog_err("%s: zclient_new() failure", __PRETTY_FUNCTION__); return 0; } zlookup->sock = -1; zlookup->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ); zlookup->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ); zlookup->t_connect = 0; zclient_lookup_sched_now(zlookup); zlog_notice("%s: zclient lookup socket initialized", __PRETTY_FUNCTION__); return zlookup; } static int zclient_read_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { int num_ifindex = 0; struct stream *s; const uint16_t MIN_LEN = 14; /* getc=1 getc=1 getw=2 getipv4=4 getc=1 getl=4 getc=1 */ uint16_t length, len; u_char marker; u_char version; uint16_t command; int nbytes; struct in_addr raddr; uint8_t distance; uint32_t metric; int nexthop_num; int i; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } s = zlookup->ibuf; stream_reset(s); nbytes = stream_read(s, zlookup->sock, 2); if (nbytes < 2) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d", __FILE__, __PRETTY_FUNCTION__, nbytes); zclient_lookup_failed(zlookup); return -1; } length = stream_getw(s); len = length - 2; if (len < MIN_LEN) { zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d", __FILE__, __PRETTY_FUNCTION__, len, MIN_LEN); zclient_lookup_failed(zlookup); return -2; } nbytes = stream_read(s, zlookup->sock, len); if (nbytes < (length - 2)) { zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d", __FILE__, __PRETTY_FUNCTION__, nbytes, len); zclient_lookup_failed(zlookup); return -3; } marker = stream_getc(s); version = stream_getc(s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return -4; } command = stream_getw(s); if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) { zlog_err("%s: socket %d command mismatch: %d", __func__, zlookup->sock, command); return -5; } raddr.s_addr = stream_get_ipv4(s); if (raddr.s_addr != addr.s_addr) { char addr_str[100]; char raddr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", raddr, raddr_str, sizeof(raddr_str)); zlog_warn("%s: address mismatch: addr=%s raddr=%s", __PRETTY_FUNCTION__, addr_str, raddr_str); /* warning only */ } distance = stream_getc(s); metric = stream_getl(s); nexthop_num = stream_getc(s); if (nexthop_num < 1) { zlog_err("%s: socket %d bad nexthop_num=%d", __func__, zlookup->sock, nexthop_num); return -6; } len -= MIN_LEN; for (i = 0; i < nexthop_num; ++i) { enum nexthop_types_t nexthop_type; if (len < 1) { zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d", __func__, zlookup->sock, len); return -7; } nexthop_type = stream_getc(s); --len; switch (nexthop_type) { case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: case ZEBRA_NEXTHOP_IPV4_IFINDEX: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { if (len < 4) { zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d", __func__, zlookup->sock, len); return -8; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); len -= 4; } else { nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY; } nexthop_tab[num_ifindex].ifindex = stream_getl(s); nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; ++num_ifindex; break; case ZEBRA_NEXTHOP_IPV4: if (num_ifindex >= tab_size) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s", __FILE__, __PRETTY_FUNCTION__, (num_ifindex + 1), tab_size, addr_str); return num_ifindex; } nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s); len -= 4; nexthop_tab[num_ifindex].ifindex = 0; nexthop_tab[num_ifindex].protocol_distance = distance; nexthop_tab[num_ifindex].route_metric = metric; { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_warn("%s %s: zebra returned recursive nexthop %s for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_str, addr_str); } ++num_ifindex; break; default: /* do nothing */ { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s", __FILE__, __PRETTY_FUNCTION__, nexthop_type, addr_str); } break; } } return num_ifindex; } static int zclient_lookup_nexthop_once(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr) { struct stream *s; int ret; if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: addr=%s", __PRETTY_FUNCTION__, addr_str); } /* Check socket. */ if (zlookup->sock < 0) { zlog_err("%s %s: zclient lookup socket is not connected", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -1; } s = zlookup->obuf; stream_reset(s); zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB); stream_put_in_addr(s, &addr); stream_putw_at(s, 0, stream_get_endp(s)); ret = writen(zlookup->sock, s->data, stream_get_endp(s)); if (ret < 0) { zlog_err("%s %s: writen() failure writing to zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -2; } if (ret == 0) { zlog_err("%s %s: connection closed on zclient lookup socket", __FILE__, __PRETTY_FUNCTION__); zclient_lookup_failed(zlookup); return -3; } return zclient_read_nexthop(zlookup, nexthop_tab, tab_size, addr); } int zclient_lookup_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup) { int lookup; uint32_t route_metric = 0xFFFFFFFF; uint8_t protocol_distance = 0xFF; for (lookup = 0; lookup < max_lookup; ++lookup) { int num_ifindex; int first_ifindex; struct in_addr nexthop_addr; num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr); if (num_ifindex < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, addr_str); return -1; } if (lookup < 1) { /* this is the non-recursive lookup - save original metric/distance */ route_metric = nexthop_tab[0].route_metric; protocol_distance = nexthop_tab[0].protocol_distance; } /* FIXME: Non-recursive nexthop ensured only for first ifindex. However, recursive route lookup should really be fixed in zebra daemon. See also TODO T24. */ first_ifindex = nexthop_tab[0].ifindex; nexthop_addr = nexthop_tab[0].nexthop_addr; if (first_ifindex > 0) { /* found: first ifindex is non-recursive nexthop */ if (lookup > 0) { /* Report non-recursive success after first lookup */ char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_info("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, first_ifindex, addr_str, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); /* use last address as nexthop address */ nexthop_tab[0].nexthop_addr = addr; /* report original route metric/distance */ nexthop_tab[0].route_metric = route_metric; nexthop_tab[0].protocol_distance = protocol_distance; } return num_ifindex; } { char addr_str[100]; char nexthop_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); pim_inet4_dump("", nexthop_addr, nexthop_str, sizeof(nexthop_str)); zlog_warn("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, nexthop_str, addr_str, nexthop_tab[0].protocol_distance, nexthop_tab[0].route_metric); } addr = nexthop_addr; /* use nexthop addr for recursive lookup */ } /* for (max_lookup) */ char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, lookup, max_lookup, addr_str); return -2; } quagga-0.99.24.1/pimd/pim_oil.c0000644000175000017500000000723612476520570012771 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "linklist.h" #include "pimd.h" #include "pim_oil.h" #include "pim_str.h" #include "pim_iface.h" void pim_channel_oil_free(struct channel_oil *c_oil) { XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil); } static void pim_channel_oil_delete(struct channel_oil *c_oil) { /* notice that listnode_delete() can't be moved into pim_channel_oil_free() because the later is called by list_delete_all_node() */ listnode_delete(qpim_channel_oil_list, c_oil); pim_channel_oil_free(c_oil); } static struct channel_oil *channel_oil_new(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; struct interface *ifp_in; ifp_in = pim_if_find_by_vif_index(input_vif_index); if (!ifp_in) { /* warning only */ char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", __PRETTY_FUNCTION__, source_str, group_str, input_vif_index); } c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil)); if (!c_oil) { zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } c_oil->oil.mfcc_mcastgrp = group_addr; c_oil->oil.mfcc_origin = source_addr; c_oil->oil.mfcc_parent = input_vif_index; c_oil->oil_ref_count = 1; zassert(c_oil->oil_size == 0); return c_oil; } static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; c_oil = channel_oil_new(group_addr, source_addr, input_vif_index); if (!c_oil) { zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil)); return 0; } listnode_add(qpim_channel_oil_list, c_oil); return c_oil; } static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr, struct in_addr source_addr) { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) && (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr)) return c_oil; } return 0; } struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index) { struct channel_oil *c_oil; c_oil = pim_find_channel_oil(group_addr, source_addr); if (c_oil) { ++c_oil->oil_ref_count; return c_oil; } return pim_add_channel_oil(group_addr, source_addr, input_vif_index); } void pim_channel_oil_del(struct channel_oil *c_oil) { --c_oil->oil_ref_count; if (c_oil->oil_ref_count < 1) { pim_channel_oil_delete(c_oil); } } quagga-0.99.24.1/pimd/pim_time.c0000644000175000017500000000706212476520570013141 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "log.h" #include "thread.h" #include "pim_time.h" static int gettime_monotonic(struct timeval *tv) { int result; result = gettimeofday(tv, 0); if (result) { zlog_err("%s: gettimeofday() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); } return result; } /* pim_time_monotonic_sec(): number of seconds since some unspecified starting point */ int64_t pim_time_monotonic_sec() { struct timeval now_tv; if (gettime_monotonic(&now_tv)) { zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } return now_tv.tv_sec; } /* pim_time_monotonic_dsec(): number of deciseconds since some unspecified starting point */ int64_t pim_time_monotonic_dsec() { struct timeval now_tv; int64_t now_dsec; if (gettime_monotonic(&now_tv)) { zlog_err("%s: gettime_monotonic() failure: errno=%d: %s", __PRETTY_FUNCTION__, errno, safe_strerror(errno)); return -1; } now_dsec = ((int64_t) now_tv.tv_sec) * 10 + ((int64_t) now_tv.tv_usec) / 100000; return now_dsec; } int pim_time_mmss(char *buf, int buf_size, long sec) { long mm; int wr; zassert(buf_size >= 5); mm = sec / 60; sec %= 60; wr = snprintf(buf, buf_size, "%02ld:%02ld", mm, sec); return wr != 8; } static int pim_time_hhmmss(char *buf, int buf_size, long sec) { long hh; long mm; int wr; zassert(buf_size >= 8); hh = sec / 3600; sec %= 3600; mm = sec / 60; sec %= 60; wr = snprintf(buf, buf_size, "%02ld:%02ld:%02ld", hh, mm, sec); return wr != 8; } void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t_timer) { if (t_timer) { pim_time_mmss(buf, buf_size, thread_timer_remain_second(t_timer)); } else { snprintf(buf, buf_size, "--:--"); } } void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t_timer) { if (t_timer) { pim_time_hhmmss(buf, buf_size, thread_timer_remain_second(t_timer)); } else { snprintf(buf, buf_size, "--:--:--"); } } void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec) { zassert(buf_size >= 8); pim_time_hhmmss(buf, buf_size, uptime_sec); } void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin) { if (begin > 0) pim_time_uptime(buf, buf_size, now - begin); else snprintf(buf, buf_size, "--:--:--"); } long pim_time_timer_remain_msec(struct thread *t_timer) { /* FIXME: Actually fetch msec resolution from thread */ /* no timer thread running means timer has expired: return 0 */ return t_timer ? 1000 * thread_timer_remain_second(t_timer) : 0; } quagga-0.99.24.1/pimd/pim_util.c0000644000175000017500000000527112476520570013160 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "pim_util.h" /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) If QQIC < 128, QQI = QQIC If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ Since exp=0..7 then (exp+3)=3..10, then QQI has one of the following bit patterns: exp=0: QQI = 0000.0000.1MMM.M000 exp=1: QQI = 0000.0001.MMMM.0000 ... exp=6: QQI = 001M.MMM0.0000.0000 exp=7: QQI = 01MM.MM00.0000.0000 --------- --------- 0x4 0x0 0x0 0x0 */ uint8_t igmp_msg_encode16to8(uint16_t value) { uint8_t code; if (value < 128) { code = value; } else { uint16_t mask = 0x4000; uint8_t exp; uint16_t mant; for (exp = 7; exp > 0; --exp) { if (mask & value) break; mask >>= 1; } mant = 0x000F & (value >> (exp + 3)); code = ((uint8_t) 1 << 7) | ((uint8_t) exp << 4) | (uint8_t) mant; } return code; } /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) If QQIC < 128, QQI = QQIC If QQIC >= 128, QQI = (mant | 0x10) << (exp + 3) 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ */ uint16_t igmp_msg_decode8to16(uint8_t code) { uint16_t value; if (code < 128) { value = code; } else { uint16_t mant = (code & 0x0F); uint8_t exp = (code & 0x70) >> 4; value = (mant | 0x10) << (exp + 3); } return value; } void pim_pkt_dump(const char *label, const uint8_t *buf, int size) { char dump_buf[1000]; int i = 0; int j = 0; for (; i < size; ++i, j += 2) { int left = sizeof(dump_buf) - j; if (left < 4) { if (left > 1) { strcat(dump_buf + j, "!"); /* mark as truncated */ } break; } snprintf(dump_buf + j, left, "%02x", buf[i]); } zlog_debug("%s: pkt dump size=%d: %s", label, size, dump_buf); } quagga-0.99.24.1/pimd/pim_mroute.c0000644000175000017500000002625012476520570013516 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "privs.h" #include "pimd.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_time.h" #include "pim_iface.h" #include "pim_macro.h" /* GLOBAL VARS */ extern struct zebra_privs_t pimd_privs; static void mroute_read_on(void); static int pim_mroute_set(int fd, int enable) { int err; int opt = enable ? MRT_INIT : MRT_DONE; socklen_t opt_len = sizeof(opt); err = setsockopt(fd, IPPROTO_IP, opt, &opt, opt_len); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,%s=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, enable ? "MRT_INIT" : "MRT_DONE", opt, e, safe_strerror(e)); errno = e; return -1; } #if 0 zlog_info("%s %s: setsockopt(fd=%d,IPPROTO_IP,MRT_INIT,opt=%d): ok", __FILE__, __PRETTY_FUNCTION__, fd, opt); #endif return 0; } int pim_mroute_msg(int fd, const char *buf, int buf_size) { struct interface *ifp; const struct ip *ip_hdr; const struct igmpmsg *msg; const char *upcall; char src_str[100]; char grp_str[100]; ip_hdr = (const struct ip *) buf; /* kernel upcall must have protocol=0 */ if (ip_hdr->ip_p) { /* this is not a kernel upcall */ #ifdef PIM_UNEXPECTED_KERNEL_UPCALL zlog_warn("%s: not a kernel upcall proto=%d msg_size=%d", __PRETTY_FUNCTION__, ip_hdr->ip_p, buf_size); #endif return 0; } msg = (const struct igmpmsg *) buf; switch (msg->im_msgtype) { case IGMPMSG_NOCACHE: upcall = "NOCACHE"; break; case IGMPMSG_WRONGVIF: upcall = "WRONGVIF"; break; case IGMPMSG_WHOLEPKT: upcall = "WHOLEPKT"; break; default: upcall = ""; } ifp = pim_if_find_by_vif_index(msg->im_vif); pim_inet4_dump("", msg->im_src, src_str, sizeof(src_str)); pim_inet4_dump("", msg->im_dst, grp_str, sizeof(grp_str)); if (msg->im_msgtype == IGMPMSG_WRONGVIF) { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; /* Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. RFC 4601 4.8.2. PIM-SSM-Only Routers iif is the incoming interface of the packet. if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } */ if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: WRONGVIF from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", __PRETTY_FUNCTION__, fd, src_str, grp_str, ifp ? ifp->name : "", msg->im_vif); } if (!ifp) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find input interface for input_vif_index=%d", __PRETTY_FUNCTION__, src_str, grp_str, msg->im_vif); return -1; } pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) multicast not enabled on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -2; } ch = pim_ifchannel_find(ifp, msg->im_src, msg->im_dst); if (!ch) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) could not find channel on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -3; } /* RFC 4601: 4.6.1. (S,G) Assert Message State Machine Transitions from NoInfo State An (S,G) data packet arrives on interface I, AND CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an downstream interface that is in our (S,G) outgoing interface list. We optimistically assume that we will be the assert winner for this (S,G), and so we transition to the "I am Assert Winner" state and perform Actions A1 (below), which will initiate the assert negotiation for (S,G). */ if (ch->ifassert_state != PIM_IFASSERT_NOINFO) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) channel is not on Assert NoInfo state for interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -4; } if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) interface %s is not downstream for channel", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -5; } if (assert_action_a1(ch)) { zlog_warn("%s: WRONGVIF (S,G)=(%s,%s) assert_action_a1 failure on interface %s", __PRETTY_FUNCTION__, src_str, grp_str, ifp->name); return -6; } return 0; } /* IGMPMSG_WRONGVIF */ zlog_warn("%s: kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%s,%s) on %s vifi=%d", __PRETTY_FUNCTION__, upcall, msg->im_msgtype, ip_hdr->ip_p, fd, src_str, grp_str, ifp ? ifp->name : "", msg->im_vif); return 0; } static int mroute_read_msg(int fd) { const int msg_min_size = MAX(sizeof(struct ip), sizeof(struct igmpmsg)); char buf[1000]; int rd; if (((int) sizeof(buf)) < msg_min_size) { zlog_err("%s: fd=%d: buf size=%zu lower than msg_min=%d", __PRETTY_FUNCTION__, fd, sizeof(buf), msg_min_size); return -1; } rd = read(fd, buf, sizeof(buf)); if (rd < 0) { zlog_warn("%s: failure reading fd=%d: errno=%d: %s", __PRETTY_FUNCTION__, fd, errno, safe_strerror(errno)); return -2; } if (rd < msg_min_size) { zlog_warn("%s: short message reading fd=%d: read=%d msg_min=%d", __PRETTY_FUNCTION__, fd, rd, msg_min_size); return -3; } return pim_mroute_msg(fd, buf, rd); } static int mroute_read(struct thread *t) { int fd; int result; zassert(t); zassert(!THREAD_ARG(t)); fd = THREAD_FD(t); zassert(fd == qpim_mroute_socket_fd); result = mroute_read_msg(fd); /* Keep reading */ qpim_mroute_socket_reader = 0; mroute_read_on(); return result; } static void mroute_read_on() { zassert(!qpim_mroute_socket_reader); zassert(PIM_MROUTE_IS_ENABLED); THREAD_READ_ON(master, qpim_mroute_socket_reader, mroute_read, 0, qpim_mroute_socket_fd); } static void mroute_read_off() { THREAD_OFF(qpim_mroute_socket_reader); } int pim_mroute_socket_enable() { int fd; if (PIM_MROUTE_IS_ENABLED) return -1; if ( pimd_privs.change (ZPRIVS_RAISE) ) zlog_err ("pim_mroute_socket_enable: could not raise privs, %s", safe_strerror (errno) ); fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); if ( pimd_privs.change (ZPRIVS_LOWER) ) zlog_err ("pim_mroute_socket_enable: could not lower privs, %s", safe_strerror (errno) ); if (fd < 0) { zlog_warn("Could not create mroute socket: errno=%d: %s", errno, safe_strerror(errno)); return -2; } if (pim_mroute_set(fd, 1)) { zlog_warn("Could not enable mroute on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return -3; } qpim_mroute_socket_fd = fd; qpim_mroute_socket_creation = pim_time_monotonic_sec(); mroute_read_on(); zassert(PIM_MROUTE_IS_ENABLED); return 0; } int pim_mroute_socket_disable() { if (PIM_MROUTE_IS_DISABLED) return -1; if (pim_mroute_set(qpim_mroute_socket_fd, 0)) { zlog_warn("Could not disable mroute on socket fd=%d: errno=%d: %s", qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -2; } if (close(qpim_mroute_socket_fd)) { zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s", qpim_mroute_socket_fd, errno, safe_strerror(errno)); return -3; } mroute_read_off(); qpim_mroute_socket_fd = -1; zassert(PIM_MROUTE_IS_DISABLED); return 0; } /* For each network interface (e.g., physical or a virtual tunnel) that would be used for multicast forwarding, a corresponding multicast interface must be added to the kernel. */ int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr) { struct vifctl vc; int err; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = vif_index; vc.vifc_flags = 0; vc.vifc_threshold = PIM_MROUTE_MIN_TTL; vc.vifc_rate_limit = 0; memcpy(&vc.vifc_lcl_addr, &ifaddr, sizeof(vc.vifc_lcl_addr)); #ifdef PIM_DVMRP_TUNNEL if (vc.vifc_flags & VIFF_TUNNEL) { memcpy(&vc.vifc_rmt_addr, &vif_remote_addr, sizeof(vc.vifc_rmt_addr)); } #endif err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_VIF, (void*) &vc, sizeof(vc)); if (err) { char ifaddr_str[100]; int e = errno; pim_inet4_dump("", ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_VIF,vif_index=%d,ifaddr=%s): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, ifaddr_str, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_del_vif(int vif_index) { struct vifctl vc; int err; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } memset(&vc, 0, sizeof(vc)); vc.vifc_vifi = vif_index; err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_VIF, (void*) &vc, sizeof(vc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_VIF,vif_index=%d): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, vif_index, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_add(struct mfcctl *mc) { int err; qpim_mroute_add_last = pim_time_monotonic_sec(); ++qpim_mroute_add_events; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_ADD_MFC, mc, sizeof(*mc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_ADD_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, e, safe_strerror(e)); errno = e; return -2; } return 0; } int pim_mroute_del(struct mfcctl *mc) { int err; qpim_mroute_del_last = pim_time_monotonic_sec(); ++qpim_mroute_del_events; if (PIM_MROUTE_IS_DISABLED) { zlog_warn("%s: global multicast is disabled", __PRETTY_FUNCTION__); return -1; } err = setsockopt(qpim_mroute_socket_fd, IPPROTO_IP, MRT_DEL_MFC, mc, sizeof(*mc)); if (err) { int e = errno; zlog_warn("%s %s: failure: setsockopt(fd=%d,IPPROTO_IP,MRT_DEL_MFC): errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, qpim_mroute_socket_fd, e, safe_strerror(e)); errno = e; return -2; } return 0; } quagga-0.99.24.1/pimd/pim_str.c0000644000175000017500000000250212476520570013005 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include #include #include "log.h" #include "pim_str.h" void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size) { int save_errno = errno; if (!inet_ntop(AF_INET, &addr, buf, buf_size)) { int e = errno; zlog_warn("pim_inet4_dump: inet_ntop(AF_INET,buf_size=%d): errno=%d: %s", buf_size, e, safe_strerror(e)); if (onfail) snprintf(buf, buf_size, "%s", onfail); } errno = save_errno; } quagga-0.99.24.1/pimd/pim_igmpv3.c0000644000175000017500000014572712476520570013423 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "pimd.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_str.h" #include "pim_util.h" #include "pim_time.h" #include "pim_zebra.h" #include "pim_oil.h" static void group_retransmit_timer_on(struct igmp_group *group); static long igmp_group_timer_remain_msec(struct igmp_group *group); static long igmp_source_timer_remain_msec(struct igmp_source *source); static void group_query_send(struct igmp_group *group); static void source_query_send_by_flag(struct igmp_group *group, int num_sources_tosend); static void on_trace(const char *label, struct interface *ifp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { if (PIM_DEBUG_IGMP_TRACE) { char from_str[100]; char group_str[100]; pim_inet4_dump("", from, from_str, sizeof(from_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("%s: from %s on %s: group=%s sources=%d", label, from_str, ifp->name, group_str, num_sources); } } int igmp_group_compat_mode(const struct igmp_sock *igmp, const struct igmp_group *group) { struct pim_interface *pim_ifp; int64_t now_dsec; long older_host_present_interval_dsec; zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; /* RFC 3376: 8.13. Older Host Present Interval This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one Query Response Interval). older_host_present_interval_dsec = \ igmp->querier_robustness_variable * \ 10 * igmp->querier_query_interval + \ pim_ifp->query_max_response_time_dsec; */ older_host_present_interval_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); now_dsec = pim_time_monotonic_dsec(); if (now_dsec < 1) { /* broken timer logged by pim_time_monotonic_dsec() */ return 3; } if ((now_dsec - group->last_igmp_v1_report_dsec) < older_host_present_interval_dsec) return 1; /* IGMPv1 */ if ((now_dsec - group->last_igmp_v2_report_dsec) < older_host_present_interval_dsec) return 2; /* IGMPv2 */ return 3; /* IGMPv3 */ } void igmp_group_reset_gmi(struct igmp_group *group) { long group_membership_interval_msec; struct pim_interface *pim_ifp; struct igmp_sock *igmp; struct interface *ifp; igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; /* RFC 3376: 8.4. Group Membership Interval The Group Membership Interval is the amount of time that must pass before a multicast router decides there are no more members of a group or a particular source on a network. This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one Query Response Interval). group_membership_interval_msec = querier_robustness_variable * (1000 * querier_query_interval) + 100 * query_response_interval_dsec; */ group_membership_interval_msec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s", group_str, group_membership_interval_msec / 1000, group_membership_interval_msec % 1000, ifp->name); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(group->group_filtermode_isexcl); igmp_group_timer_on(group, group_membership_interval_msec, ifp->name); } static int igmp_source_timer(struct thread *t) { struct igmp_source *source; struct igmp_group *group; zassert(t); source = THREAD_ARG(t); zassert(source); group = source->source_group; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("%s: Source timer expired for group %s source %s on %s", __PRETTY_FUNCTION__, group_str, source_str, group->group_igmp_sock->interface->name); } zassert(source->t_source_timer); source->t_source_timer = 0; /* RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules Group Filter-Mode Source Timer Value Action ----------- ------------------ ------ INCLUDE TIMER == 0 Suggest to stop forwarding traffic from source and remove source record. If there are no more source records for the group, delete group record. EXCLUDE TIMER == 0 Suggest to not forward traffic from source (DO NOT remove record) Source timer switched from (T > 0) to (T == 0): disable forwarding. */ zassert(!source->t_source_timer); if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ igmp_source_forward_stop(source); } else { /* INCLUDE mode */ /* igmp_source_delete() will stop forwarding source */ igmp_source_delete(source); /* If there are no more source records for the group, delete group record. */ if (!listcount(group->group_source_list)) { igmp_group_delete_empty_include(group); } } return 0; } static void source_timer_off(struct igmp_group *group, struct igmp_source *source) { if (!source->t_source_timer) return; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Cancelling TIMER event for group %s source %s on %s", group_str, source_str, group->group_igmp_sock->interface->name); } THREAD_OFF(source->t_source_timer); zassert(!source->t_source_timer); } static void igmp_source_timer_on(struct igmp_group *group, struct igmp_source *source, long interval_msec) { source_timer_off(group, source); if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s", interval_msec / 1000, interval_msec % 1000, group_str, source_str, group->group_igmp_sock->interface->name); } THREAD_TIMER_MSEC_ON(master, source->t_source_timer, igmp_source_timer, source, interval_msec); zassert(source->t_source_timer); /* RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules Source timer switched from (T == 0) to (T > 0): enable forwarding. */ igmp_source_forward_start(source); } void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group, struct igmp_source *source) { long group_membership_interval_msec; struct pim_interface *pim_ifp; struct interface *ifp; ifp = igmp->interface; pim_ifp = ifp->info; group_membership_interval_msec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Resetting source %s timer to GMI=%ld.%03ld sec for group %s on %s", source_str, group_membership_interval_msec / 1000, group_membership_interval_msec % 1000, group_str, ifp->name); } igmp_source_timer_on(group, source, group_membership_interval_msec); } static void source_mark_delete_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DO_DELETE(src->source_flags); } } static void source_mark_send_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DO_SEND(src->source_flags); } } static int source_mark_send_flag_by_timer(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; int num_marked_sources = 0; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { /* Is source timer running? */ if (src->t_source_timer) { IGMP_SOURCE_DO_SEND(src->source_flags); ++num_marked_sources; } else { IGMP_SOURCE_DONT_SEND(src->source_flags); } } return num_marked_sources; } static void source_clear_send_flag(struct list *source_list) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DONT_SEND(src->source_flags); } } /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) { zassert(group->group_filtermode_isexcl); if (listcount(group->group_source_list) < 1) { igmp_anysource_forward_start(group); } } void igmp_source_free(struct igmp_source *source) { /* make sure there is no source timer running */ zassert(!source->t_source_timer); XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source); } static void source_channel_oil_detach(struct igmp_source *source) { if (source->source_channel_oil) { pim_channel_oil_del(source->source_channel_oil); source->source_channel_oil = 0; } } /* igmp_source_delete: stop fowarding, and delete the source igmp_source_forward_stop: stop fowarding, but keep the source */ void igmp_source_delete(struct igmp_source *source) { struct igmp_group *group; group = source->source_group; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s", source_str, group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); } source_timer_off(group, source); igmp_source_forward_stop(source); /* sanity check that forwarding has been disabled */ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s", __PRETTY_FUNCTION__, source_str, group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); /* warning only */ } source_channel_oil_detach(source); /* notice that listnode_delete() can't be moved into igmp_source_free() because the later is called by list_delete_all_node() */ listnode_delete(group->group_source_list, source); igmp_source_free(source); if (group->group_filtermode_isexcl) { group_exclude_fwd_anysrc_ifempty(group); } } static void source_delete_by_flag(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (IGMP_SOURCE_TEST_DELETE(src->source_flags)) igmp_source_delete(src); } void igmp_source_delete_expired(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (!src->t_source_timer) igmp_source_delete(src); } struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, struct in_addr src_addr) { struct listnode *src_node; struct igmp_source *src; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) if (src_addr.s_addr == src->source_addr.s_addr) return src; return 0; } static struct igmp_source *source_new(struct igmp_group *group, struct in_addr src_addr, const char *ifname) { struct igmp_source *src; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", src_addr, source_str, sizeof(source_str)); zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s", source_str, group_str, group->group_igmp_sock->fd, ifname); } src = XMALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src)); if (!src) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; /* error, not found, could not create */ } src->t_source_timer = 0; src->source_group = group; /* back pointer */ src->source_addr = src_addr; src->source_creation = pim_time_monotonic_sec(); src->source_flags = 0; src->source_query_retransmit_count = 0; src->source_channel_oil = 0; listnode_add(group->group_source_list, src); zassert(!src->t_source_timer); /* source timer == 0 */ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); return src; } static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp, struct igmp_group *group, struct in_addr src_addr, const char *ifname) { struct igmp_source *src; src = igmp_find_source_by_addr(group, src_addr); if (src) { return src; } src = source_new(group, src_addr, ifname); if (!src) { return 0; } return src; } static void allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; int i; /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return; } /* scan received sources */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; source = add_source_by_addr(igmp, group, *src_addr, ifp->name); if (!source) { continue; } /* RFC 3376: 6.4.1. Reception of Current-State Records When receiving IS_IN reports for groups in EXCLUDE mode is sources should be moved from set with (timers = 0) to set with (timers > 0). igmp_source_reset_gmi() below, resetting the source timers to GMI, accomplishes this. */ igmp_source_reset_gmi(igmp, group, source); } /* scan received sources */ } void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr, num_sources, sources); allow(igmp, from, group_addr, num_sources, sources); } static void isex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int i; /* EXCLUDE mode */ zassert(group->group_filtermode_isexcl); /* E.1: set deletion flag for known sources (X,Y) */ source_mark_delete_flag(group->group_source_list); /* scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* E.2: lookup reported source from (A) in (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* E.4: if not found, create source with timer=GMI: (A-X-Y) */ source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ igmp_source_reset_gmi(group->group_igmp_sock, group, source); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ } } /* scan received sources */ /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */ source_delete_by_flag(group->group_source_list); } static void isex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int i; /* INCLUDE mode */ zassert(!group->group_filtermode_isexcl); /* I.1: set deletion flag for known sources (A) */ source_mark_delete_flag(group->group_source_list); /* scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* I.2: lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* I.3: if found, clear deletion flag (A*B) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* I.4: if not found, create source with timer=0 (B-A) */ source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* (B-A) timer=0 */ } } /* scan received sources */ /* I.5: delete all sources marked with deletion flag (A-B) */ source_delete_by_flag(group->group_source_list); group->group_filtermode_isexcl = 1; /* boolean=true */ zassert(group->group_filtermode_isexcl); group_exclude_fwd_anysrc_ifempty(group); } void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ isex_excl(group, num_sources, sources); } else { /* INCLUDE mode */ isex_incl(group, num_sources, sources); zassert(group->group_filtermode_isexcl); } zassert(group->group_filtermode_isexcl); igmp_group_reset_gmi(group); } static void toin_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend = listcount(group->group_source_list); int i; /* Set SEND flag for all known sources (A) */ source_mark_send_flag(group->group_source_list); /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* If found, clear SEND flag (A*B) */ IGMP_SOURCE_DONT_SEND(source->source_flags); --num_sources_tosend; } else { /* If not found, create new source */ source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } } /* (B)=GMI */ igmp_source_reset_gmi(igmp, group, source); } /* Send sources marked with SEND flag: Q(G,A-B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } static void toin_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { struct igmp_sock *igmp = group->group_igmp_sock; int num_sources_tosend; int i; /* Set SEND flag for X (sources with timer > 0) */ num_sources_tosend = source_mark_send_flag_by_timer(group->group_source_list); /* Scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (A) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { if (source->t_source_timer) { /* If found and timer running, clear SEND flag (X*A) */ IGMP_SOURCE_DONT_SEND(source->source_flags); --num_sources_tosend; } } else { /* If not found, create new source */ source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } } /* (A)=GMI */ igmp_source_reset_gmi(igmp, group, source); } /* Send sources marked with SEND flag: Q(G,X-A) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } /* Send Q(G) */ group_query_send(group); } void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ toin_excl(group, num_sources, sources); } else { /* INCLUDE mode */ toin_incl(group, num_sources, sources); } } static void toex_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; zassert(!group->group_filtermode_isexcl); /* Set DELETE flag for all known sources (A) */ source_mark_delete_flag(group->group_source_list); /* Clear off SEND flag from all known sources (A) */ source_clear_send_flag(group->group_source_list); /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* Lookup reported source (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* If found, clear deletion flag: (A*B) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); /* and set SEND flag (A*B) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } else { /* If source not found, create source with timer=0: (B-A)=0 */ source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* (B-A) timer=0 */ } } /* Scan received sources (B) */ group->group_filtermode_isexcl = 1; /* boolean=true */ /* Delete all sources marked with DELETE flag (A-B) */ source_delete_by_flag(group->group_source_list); /* Send sources marked with SEND flag: Q(G,A*B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } zassert(group->group_filtermode_isexcl); group_exclude_fwd_anysrc_ifempty(group); } static void toex_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* set DELETE flag for all known sources (X,Y) */ source_mark_delete_flag(group->group_source_list); /* clear off SEND flag from all known sources (X,Y) */ source_clear_send_flag(group->group_source_list); /* scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* if found, clear off DELETE flag from reported source (A) */ IGMP_SOURCE_DONT_DELETE(source->source_flags); } else { /* if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ group_timer_msec = igmp_group_timer_remain_msec(group); igmp_source_timer_on(group, source, group_timer_msec); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ /* make sure source is created with DELETE flag unset */ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); } /* make sure reported source has DELETE flag unset */ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags)); if (source->t_source_timer) { /* if source timer>0 mark SEND flag: Q(G,A-Y) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* scan received sources (A) */ /* delete all sources marked with DELETE flag: Delete (X-A) Delete (Y-A) */ source_delete_by_flag(group->group_source_list); /* send sources marked with SEND flag: Q(G,A-Y) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ toex_excl(group, num_sources, sources); } else { /* INCLUDE mode */ toex_incl(group, num_sources, sources); zassert(group->group_filtermode_isexcl); } zassert(group->group_filtermode_isexcl); /* Group Timer=GMI */ igmp_group_reset_gmi(group); } void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr, num_sources, sources); allow(igmp, from, group_addr, num_sources, sources); } /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries When transmitting a group specific query, if the group timer is larger than LMQT, the "Suppress Router-Side Processing" bit is set in the query message. */ static void group_retransmit_group(struct igmp_group *group) { char query_buf[PIM_IGMP_BUFSIZE_WRITE]; struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ int s_flag; igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries When transmitting a group specific query, if the group timer is larger than LMQT, the "Suppress Router-Side Processing" bit is set in the query message. */ s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d", group_str, igmp->interface->name, s_flag, group->group_specific_query_retransmit_count); } /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources_tosend */, group->group_addr /* dst_addr */, group->group_addr /* group_addr */, pim_ifp->igmp_specific_query_max_response_time_dsec, s_flag, igmp->querier_robustness_variable, igmp->querier_query_interval); } /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries When building a group and source specific query for a group G, two separate query messages are sent for the group. The first one has the "Suppress Router-Side Processing" bit set and contains all the sources with retransmission state and timers greater than LMQT. The second has the "Suppress Router-Side Processing" bit clear and contains all the sources with retransmission state and timers lower or equal to LMQT. If either of the two calculated messages does not contain any sources, then its transmission is suppressed. */ static int group_retransmit_sources(struct igmp_group *group, int send_with_sflag_set) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ char query_buf1[PIM_IGMP_BUFSIZE_WRITE]; /* 1 = with s_flag set */ char query_buf2[PIM_IGMP_BUFSIZE_WRITE]; /* 2 = with s_flag clear */ int query_buf1_max_sources; int query_buf2_max_sources; struct in_addr *source_addr1; struct in_addr *source_addr2; int num_sources_tosend1; int num_sources_tosend2; struct listnode *src_node; struct igmp_source *src; int num_retransmit_sources_left = 0; query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* Scan all group sources */ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { /* Source has retransmission state? */ if (src->source_query_retransmit_count < 1) continue; if (--src->source_query_retransmit_count > 0) { ++num_retransmit_sources_left; } /* Copy source address into appropriate query buffer */ if (igmp_source_timer_remain_msec(src) > lmqt_msec) { *source_addr1 = src->source_addr; ++source_addr1; } else { *source_addr2 = src->source_addr; ++source_addr2; } } num_sources_tosend1 = source_addr1 - (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d", group_str, igmp->interface->name, num_sources_tosend1, num_sources_tosend2, send_with_sflag_set, num_retransmit_sources_left); } if (num_sources_tosend1 > 0) { /* Send group-and-source-specific query with s_flag set and all sources with timers greater than LMQT. */ if (send_with_sflag_set) { query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2; if (num_sources_tosend1 > query_buf1_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend1, sizeof(query_buf1), query_buf1_max_sources); } else { /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf1, sizeof(query_buf1), num_sources_tosend1, group->group_addr, group->group_addr, pim_ifp->igmp_specific_query_max_response_time_dsec, 1 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); } } /* send_with_sflag_set */ } if (num_sources_tosend2 > 0) { /* Send group-and-source-specific query with s_flag clear and all sources with timers lower or equal to LMQT. */ query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2; if (num_sources_tosend2 > query_buf2_max_sources) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)", __PRETTY_FUNCTION__, group_str, igmp->interface->name, num_sources_tosend2, sizeof(query_buf2), query_buf2_max_sources); } else { /* RFC3376: 4.1.12. IP Destination Addresses for Queries Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ pim_igmp_send_membership_query(group, igmp->fd, igmp->interface->name, query_buf2, sizeof(query_buf2), num_sources_tosend2, group->group_addr, group->group_addr, pim_ifp->igmp_specific_query_max_response_time_dsec, 0 /* s_flag */, igmp->querier_robustness_variable, igmp->querier_query_interval); } } return num_retransmit_sources_left; } static int igmp_group_retransmit(struct thread *t) { struct igmp_group *group; int num_retransmit_sources_left; int send_with_sflag_set; /* boolean */ zassert(t); group = THREAD_ARG(t); zassert(group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("group_retransmit_timer: group %s on %s", group_str, group->group_igmp_sock->interface->name); } /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */ if (group->group_specific_query_retransmit_count > 0) { /* Retransmit group-specific queries (RFC3376: 6.6.3.1) */ group_retransmit_group(group); --group->group_specific_query_retransmit_count; /* RFC3376: 6.6.3.2 If a group specific query is scheduled to be transmitted at the same time as a group and source specific query for the same group, then transmission of the group and source specific message with the "Suppress Router-Side Processing" bit set may be suppressed. */ send_with_sflag_set = 0; /* boolean=false */ } else { send_with_sflag_set = 1; /* boolean=true */ } /* Retransmit group-and-source-specific queries (RFC3376: 6.6.3.2) */ num_retransmit_sources_left = group_retransmit_sources(group, send_with_sflag_set); group->t_group_query_retransmit_timer = 0; /* Keep group retransmit timer running if there is any retransmit counter pending */ if ((num_retransmit_sources_left > 0) || (group->group_specific_query_retransmit_count > 0)) { group_retransmit_timer_on(group); } return 0; } /* group_retransmit_timer_on: if group retransmit timer isn't running, starts it; otherwise, do nothing */ static void group_retransmit_timer_on(struct igmp_group *group) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; long lmqi_msec; /* Last Member Query Interval */ /* if group retransmit timer is running, do nothing */ if (group->t_group_query_retransmit_timer) { return; } igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s", lmqi_msec / 1000, lmqi_msec % 1000, group_str, igmp->interface->name); } THREAD_TIMER_MSEC_ON(master, group->t_group_query_retransmit_timer, igmp_group_retransmit, group, lmqi_msec); } static long igmp_group_timer_remain_msec(struct igmp_group *group) { return pim_time_timer_remain_msec(group->t_group_timer); } static long igmp_source_timer_remain_msec(struct igmp_source *source) { return pim_time_timer_remain_msec(source->t_source_timer); } /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries */ static void group_query_send(struct igmp_group *group) { long lmqc; /* Last Member Query Count */ lmqc = group->group_igmp_sock->querier_robustness_variable; /* lower group timer to lmqt */ igmp_group_timer_lower_to_lmqt(group); /* reset retransmission counter */ group->group_specific_query_retransmit_count = lmqc; /* immediately send group specific query (decrease retransmit counter by 1)*/ group_retransmit_group(group); /* make sure group retransmit timer is running */ group_retransmit_timer_on(group); } /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries */ static void source_query_send_by_flag(struct igmp_group *group, int num_sources_tosend) { struct igmp_sock *igmp; struct pim_interface *pim_ifp; struct listnode *src_node; struct igmp_source *src; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ zassert(num_sources_tosend > 0); igmp = group->group_igmp_sock; pim_ifp = igmp->interface->info; lmqc = igmp->querier_robustness_variable; lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries (...) for each of the sources in X of group G, with source timer larger than LMQT: o Set number of retransmissions for each source to [Last Member Query Count]. o Lower source timer to LMQT. */ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { if (IGMP_SOURCE_TEST_SEND(src->source_flags)) { /* source "src" in X of group G */ if (igmp_source_timer_remain_msec(src) > lmqt_msec) { src->source_query_retransmit_count = lmqc; igmp_source_timer_lower_to_lmqt(src); } } } /* send group-and-source specific queries */ group_retransmit_sources(group, 1 /* send_with_sflag_set=true */); /* make sure group retransmit timer is running */ group_retransmit_timer_on(group); } static void block_excl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* 1. clear off SEND flag from all known sources (X,Y) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (X,Y) */ source = igmp_find_source_by_addr(group, *src_addr); if (!source) { /* 3: if not found, create source with Group Timer: (A-X-Y)=Group Timer */ long group_timer_msec; source = source_new(group, *src_addr, group->group_igmp_sock->interface->name); if (!source) { /* ugh, internal malloc failure, skip source */ continue; } zassert(!source->t_source_timer); /* timer == 0 */ group_timer_msec = igmp_group_timer_remain_msec(group); igmp_source_timer_on(group, source, group_timer_msec); zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */ } if (source->t_source_timer) { /* 4. if source timer>0 mark SEND flag: Q(G,A-Y) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* 5. send sources marked with SEND flag: Q(G,A-Y) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } static void block_incl(struct igmp_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; int i; /* 1. clear off SEND flag from all known sources (B) */ source_clear_send_flag(group->group_source_list); /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { struct igmp_source *source; struct in_addr *src_addr; src_addr = sources + i; /* lookup reported source (A) in known sources (B) */ source = igmp_find_source_by_addr(group, *src_addr); if (source) { /* 3. if found (A*B), mark SEND flag: Q(G,A*B) */ IGMP_SOURCE_DO_SEND(source->source_flags); ++num_sources_tosend; } } /* 4. send sources marked with SEND flag: Q(G,A*B) */ if (num_sources_tosend > 0) { source_query_send_by_flag(group, num_sources_tosend); } } void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; struct igmp_group *group; on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources, sources); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return; } if (group->group_filtermode_isexcl) { /* EXCLUDE mode */ block_excl(group, num_sources, sources); } else { /* INCLUDE mode */ block_incl(group, num_sources, sources); } } void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) { struct igmp_sock *igmp; struct interface *ifp; struct pim_interface *pim_ifp; char *ifname; int lmqi_dsec; /* Last Member Query Interval */ int lmqc; /* Last Member Query Count */ int lmqt_msec; /* Last Member Query Time */ /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ if (!group->group_filtermode_isexcl) { return; } igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; ifname = ifp->name; lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", __PRETTY_FUNCTION__, group_str, ifname, lmqc, lmqi_dsec, lmqt_msec); } zassert(group->group_filtermode_isexcl); igmp_group_timer_on(group, lmqt_msec, ifname); } void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) { struct igmp_group *group; struct igmp_sock *igmp; struct interface *ifp; struct pim_interface *pim_ifp; char *ifname; int lmqi_dsec; /* Last Member Query Interval */ int lmqc; /* Last Member Query Count */ int lmqt_msec; /* Last Member Query Time */ group = source->source_group; igmp = group->group_igmp_sock; ifp = igmp->interface; pim_ifp = ifp->info; ifname = ifp->name; lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; lmqc = igmp->querier_robustness_variable; lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec", __PRETTY_FUNCTION__, group_str, source_str, ifname, lmqc, lmqi_dsec, lmqt_msec); } igmp_source_timer_on(group, source, lmqt_msec); } /* Copy sources to message: struct in_addr *sources = (struct in_addr *)(query_buf + IGMP_V3_SOURCES_OFFSET); if (num_sources > 0) { struct listnode *node; struct igmp_source *src; int i = 0; for (ALL_LIST_ELEMENTS_RO(source_list, node, src)) { sources[i++] = src->source_addr; } } */ void pim_igmp_send_membership_query(struct igmp_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval) { ssize_t msg_size; uint8_t max_resp_code; uint8_t qqic; ssize_t sent; struct sockaddr_in to; socklen_t tolen; uint16_t checksum; zassert(num_sources >= 0); msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2); if (msg_size > query_buf_size) { zlog_err("%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d", __FILE__, __PRETTY_FUNCTION__, msg_size, query_buf_size); return; } s_flag = PIM_FORCE_BOOLEAN(s_flag); zassert((s_flag == 0) || (s_flag == 1)); max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec); qqic = igmp_msg_encode16to8(querier_query_interval); /* RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) If non-zero, the QRV field contains the [Robustness Variable] value used by the querier, i.e., the sender of the Query. If the querier's [Robustness Variable] exceeds 7, the maximum value of the QRV field, the QRV is set to zero. */ if (querier_robustness_variable > 7) { querier_robustness_variable = 0; } query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY; query_buf[1] = max_resp_code; *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ memcpy(query_buf+4, &group_addr, sizeof(struct in_addr)); query_buf[8] = (s_flag << 3) | querier_robustness_variable; query_buf[9] = qqic; *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources); checksum = in_cksum(query_buf, msg_size); *(uint16_t *)(query_buf + IGMP_V3_CHECKSUM_OFFSET) = checksum; if (PIM_DEBUG_IGMP_PACKETS) { char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("%s: to %s on %s: group=%s sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x checksum=%x", __PRETTY_FUNCTION__, dst_str, ifname, group_str, num_sources, msg_size, s_flag, querier_robustness_variable, querier_query_interval, qqic, checksum); } #if 0 memset(&to, 0, sizeof(to)); #endif to.sin_family = AF_INET; to.sin_addr = dst_addr; #if 0 to.sin_port = htons(0); #endif tolen = sizeof(to); sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT, &to, tolen); if (sent != (ssize_t) msg_size) { int e = errno; char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); if (sent < 0) { zlog_warn("%s: sendto() failure to %s on %s: group=%s msg_size=%zd: errno=%d: %s", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, e, safe_strerror(e)); } else { zlog_warn("%s: sendto() partial to %s on %s: group=%s msg_size=%zd: sent=%zd", __PRETTY_FUNCTION__, dst_str, ifname, group_str, msg_size, sent); } return; } /* s_flag sanity test: s_flag must be set for general queries RFC 3376: 6.6.1. Timer Updates When a router sends or receives a query with a clear Suppress Router-Side Processing flag, it must update its timers to reflect the correct timeout values for the group or sources being queried. General queries don't trigger timer update. */ if (!s_flag) { /* general query? */ if (PIM_INADDR_IS_ANY(group_addr)) { char dst_str[100]; char group_str[100]; pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!", __PRETTY_FUNCTION__, dst_str, ifname, group_str, num_sources); } } } quagga-0.99.24.1/pimd/pim_zebra.c0000644000175000017500000012240112476520570013301 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "zebra/rib.h" #include "if.h" #include "log.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "pimd.h" #include "pim_pim.h" #include "pim_zebra.h" #include "pim_iface.h" #include "pim_str.h" #include "pim_oil.h" #include "pim_rpf.h" #include "pim_time.h" #include "pim_join.h" #include "pim_zlookup.h" #include "pim_ifchannel.h" #undef PIM_DEBUG_IFADDR_DUMP #define PIM_DEBUG_IFADDR_DUMP static int fib_lookup_if_vif_index(struct in_addr addr); static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask); static void zclient_broken(struct zclient *zclient) { struct listnode *ifnode; struct interface *ifp; zlog_warn("%s %s: broken zclient connection", __FILE__, __PRETTY_FUNCTION__); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { pim_if_addr_del_all(ifp); } /* upon return, zclient will discard connected addresses */ } /* Router-id update message from zebra. */ static int pim_router_id_update_zebra(int command, struct zclient *zclient, zebra_size_t length) { struct prefix router_id; zebra_router_id_update_read(zclient->ibuf, &router_id); return 0; } static int pim_zebra_if_add(int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; /* zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c */ ifp = zebra_interface_add_read(zclient->ibuf); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (if_is_operative(ifp)) pim_if_addr_add_all(ifp); return 0; } static int pim_zebra_if_del(int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; /* zebra api adds/dels interfaces using the same call interface_add_read below, see comments in lib/zclient.c comments in lib/zclient.c seem to indicate that calling zebra_interface_add_read is the correct call, but that results in an attemted out of bounds read which causes pimd to assert. Other clients use zebra_interface_state_read and it appears to work just fine. */ ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) return 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); return 0; } static int pim_zebra_if_state_up(int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; /* zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) return 0; zlog_info("INTERFACE UP: %s ifindex=%d", ifp->name, ifp->ifindex); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (if_is_operative(ifp)) { /* pim_if_addr_add_all() suffices for bringing up both IGMP and PIM */ pim_if_addr_add_all(ifp); } return 0; } static int pim_zebra_if_state_down(int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; /* zebra api notifies interface up/down events by using the same call zebra_interface_state_read below, see comments in lib/zclient.c */ ifp = zebra_interface_state_read(zclient->ibuf); if (!ifp) return 0; zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp->name, ifp->ifindex); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) { /* pim_if_addr_del_all() suffices for shutting down IGMP, but not for shutting down PIM */ pim_if_addr_del_all(ifp); /* pim_sock_delete() closes the socket, stops read and timer threads, and kills all neighbors. */ if (ifp->info) { pim_sock_delete(ifp, "link down"); } } return 0; } #ifdef PIM_DEBUG_IFADDR_DUMP static void dump_if_address(struct interface *ifp) { struct connected *ifc; struct listnode *node; zlog_debug("%s %s: interface %s addresses:", __FILE__, __PRETTY_FUNCTION__, ifp->name); for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; zlog_debug("%s %s: interface %s address %s %s", __FILE__, __PRETTY_FUNCTION__, ifp->name, inet_ntoa(p->u.prefix4), CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } } #endif static int pim_zebra_if_address_add(int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; struct prefix *p; zassert(command == ZEBRA_INTERFACE_ADDRESS_ADD); /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...) will add address to interface list by calling connected_add_by_prefix() */ c = zebra_interface_address_read(command, zclient->ibuf); if (!c) return 0; p = c->address; if (p->family != AF_INET) return 0; if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug("%s: %s connected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) { /* trying to add primary address */ struct in_addr primary_addr = pim_find_primary_addr(c->ifp); if (primary_addr.s_addr != p->u.prefix4.s_addr) { /* but we had a primary address already */ char buf[BUFSIZ]; char old[100]; prefix2str(p, buf, BUFSIZ); pim_inet4_dump("", primary_addr, old, sizeof(old)); zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s", __PRETTY_FUNCTION__, c->ifp->name, old, buf); SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY); } } pim_if_addr_add(c); return 0; } static int pim_zebra_if_address_del(int command, struct zclient *client, zebra_size_t length) { struct connected *c; struct prefix *p; zassert(command == ZEBRA_INTERFACE_ADDRESS_DELETE); /* zebra api notifies address adds/dels events by using the same call interface_add_read below, see comments in lib/zclient.c zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...) will remove address from interface list by calling connected_delete_by_prefix() */ c = zebra_interface_address_read(command, client->ibuf); if (!c) return 0; p = c->address; if (p->family != AF_INET) return 0; if (PIM_DEBUG_ZEBRA) { char buf[BUFSIZ]; prefix2str(p, buf, BUFSIZ); zlog_debug("%s: %s disconnected IP address %s flags %u %s", __PRETTY_FUNCTION__, c->ifp->name, buf, c->flags, CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); #ifdef PIM_DEBUG_IFADDR_DUMP dump_if_address(c->ifp); #endif } pim_if_addr_del(c, 0); return 0; } static void scan_upstream_rpf_cache() { struct listnode *up_node; struct listnode *up_nextnode; struct pim_upstream *up; for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) { struct in_addr old_rpf_addr; enum pim_rpf_result rpf_result; rpf_result = pim_rpf_update(up, &old_rpf_addr); if (rpf_result == PIM_RPF_FAILURE) continue; if (rpf_result == PIM_RPF_CHANGED) { if (up->join_state == PIM_UPSTREAM_JOINED) { /* RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) changes not due to an Assert The upstream (S,G) state machine remains in Joined state. Send Join(S,G) to the new upstream neighbor, which is the new value of RPF'(S,G). Send Prune(S,G) to the old upstream neighbor, which is the old value of RPF'(S,G). Set the Join Timer (JT) to expire after t_periodic seconds. */ /* send Prune(S,G) to the old upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, old_rpf_addr, up->source_addr, up->group_addr, 0 /* prune */); /* send Join(S,G) to the current upstream neighbor */ pim_joinprune_send(up->rpf.source_nexthop.interface, up->rpf.rpf_addr, up->source_addr, up->group_addr, 1 /* join */); pim_upstream_join_timer_restart(up); } /* up->join_state == PIM_UPSTREAM_JOINED */ /* FIXME can join_desired actually be changed by pim_rpf_update() returning PIM_RPF_CHANGED ? */ pim_upstream_update_join_desired(up); } /* PIM_RPF_CHANGED */ } /* for (qpim_upstream_list) */ } void pim_scan_oil() { struct listnode *node; struct listnode *nextnode; struct channel_oil *c_oil; qpim_scan_oil_last = pim_time_monotonic_sec(); ++qpim_scan_oil_events; for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) { int old_vif_index; int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin); if (input_iface_vif_index < 1) { char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); continue; } if (input_iface_vif_index == c_oil->oil.mfcc_parent) { /* RPF unchanged */ continue; } if (PIM_DEBUG_ZEBRA) { struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, new_iif ? new_iif->name : "", input_iface_vif_index); } /* new iif loops to existing oif ? */ if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) { struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); if (PIM_DEBUG_ZEBRA) { char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, new_iif ? new_iif->name : "", input_iface_vif_index); } del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY); } /* update iif vif_index */ old_vif_index = c_oil->oil.mfcc_parent; c_oil->oil.mfcc_parent = input_iface_vif_index; /* update kernel multicast forwarding cache (MFC) */ if (pim_mroute_add(&c_oil->oil)) { /* just log warning */ struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index); struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index); char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, old_iif ? old_iif->name : "", c_oil->oil.mfcc_parent, new_iif ? new_iif->name : "", input_iface_vif_index); continue; } } /* for (qpim_channel_oil_list) */ } static int on_rpf_cache_refresh(struct thread *t) { zassert(t); zassert(qpim_rpf_cache_refresher); qpim_rpf_cache_refresher = 0; /* update PIM protocol state */ scan_upstream_rpf_cache(); /* update kernel multicast forwarding cache (MFC) */ pim_scan_oil(); qpim_rpf_cache_refresh_last = pim_time_monotonic_sec(); ++qpim_rpf_cache_refresh_events; return 0; } static void sched_rpf_cache_refresh() { ++qpim_rpf_cache_refresh_requests; if (qpim_rpf_cache_refresher) { /* Refresh timer is already running */ return; } /* Start refresh timer */ if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: triggering %ld msec timer", __PRETTY_FUNCTION__, qpim_rpf_cache_refresh_delay_msec); } THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher, on_rpf_cache_refresh, 0, qpim_rpf_cache_refresh_delay_msec); } static int redist_read_ipv4_route(int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; int min_len = 4; if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min=%d", __FILE__, __PRETTY_FUNCTION__, length, min_len); return -1; } s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc(s); api.flags = stream_getc(s); api.message = stream_getc(s); /* IPv4 prefix length. */ memset(&p, 0, sizeof(struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc(s); min_len += PSIZE(p.prefixlen) + CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 + CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0; if (PIM_DEBUG_ZEBRA) { zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); } if (length < min_len) { zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s", __FILE__, __PRETTY_FUNCTION__, length, min_len, CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "", CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : ""); return -1; } /* IPv4 prefix. */ stream_get(&p.prefix, s, PSIZE(p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc(s); nexthop.s_addr = stream_get_ipv4(s); } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc(s); ifindex = stream_getl(s); } api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? stream_getc(s) : 0; api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? stream_getl(s) : 0; switch (command) { case ZEBRA_IPV4_ROUTE_ADD: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: add %s %s/%d " "nexthop %s ifindex %ld metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; case ZEBRA_IPV4_ROUTE_DELETE: if (PIM_DEBUG_ZEBRA) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("%s: delete %s %s/%d " "nexthop %s ifindex %ld metric%s %u distance%s %u", __PRETTY_FUNCTION__, zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), ifindex, CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss", api.metric, CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss", api.distance); } break; default: zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command); return -1; } sched_rpf_cache_refresh(); return 0; } void pim_zebra_init(char *zebra_sock_path) { int i; if (zebra_sock_path) zclient_serv_path_set(zebra_sock_path); #ifdef HAVE_TCP_ZEBRA zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT); #else zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get()); #endif /* Socket for receiving updates from Zebra daemon */ qpim_zclient_update = zclient_new(); qpim_zclient_update->router_id_update = pim_router_id_update_zebra; qpim_zclient_update->interface_add = pim_zebra_if_add; qpim_zclient_update->interface_delete = pim_zebra_if_del; qpim_zclient_update->interface_up = pim_zebra_if_state_up; qpim_zclient_update->interface_down = pim_zebra_if_state_down; qpim_zclient_update->interface_address_add = pim_zebra_if_address_add; qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del; qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route; qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route; zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM); if (PIM_DEBUG_PIM_TRACE) { zlog_info("zclient_init cleared redistribution request"); } zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM); /* Request all redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == qpim_zclient_update->redist_default) continue; qpim_zclient_update->redist[i] = 1; if (PIM_DEBUG_PIM_TRACE) { zlog_debug("%s: requesting redistribution for %s (%i)", __PRETTY_FUNCTION__, zebra_route_string(i), i); } } /* Request default information */ qpim_zclient_update->default_information = 1; if (PIM_DEBUG_PIM_TRACE) { zlog_info("%s: requesting default information redistribution", __PRETTY_FUNCTION__); zlog_notice("%s: zclient update socket initialized", __PRETTY_FUNCTION__); } zassert(!qpim_zclient_lookup); qpim_zclient_lookup = zclient_lookup_new(); zassert(qpim_zclient_lookup); } void igmp_anysource_forward_start(struct igmp_group *group) { /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ zassert(group->group_filtermode_isexcl); zassert(listcount(group->group_source_list) < 1); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("%s %s: UNIMPLEMENTED", __FILE__, __PRETTY_FUNCTION__); } } void igmp_anysource_forward_stop(struct igmp_group *group) { /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0)); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("%s %s: UNIMPLEMENTED", __FILE__, __PRETTY_FUNCTION__); } } static int fib_lookup_if_vif_index(struct in_addr addr) { struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE]; int num_ifindex; int vif_index; int first_ifindex; num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab, PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr, PIM_NEXTHOP_LOOKUP_MAX); if (num_ifindex < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: could not find nexthop ifindex for address %s", __FILE__, __PRETTY_FUNCTION__, addr_str); return -1; } first_ifindex = nexthop_tab[0].ifindex; if (num_ifindex > 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)", __FILE__, __PRETTY_FUNCTION__, num_ifindex, addr_str, first_ifindex); /* debug warning only, do not return */ } if (PIM_DEBUG_ZEBRA) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s", __FILE__, __PRETTY_FUNCTION__, first_ifindex, ifindex2ifname(first_ifindex), addr_str); } vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex); if (vif_index < 1) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s", __FILE__, __PRETTY_FUNCTION__, vif_index, addr_str); return -2; } zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); if (vif_index > qpim_mroute_oif_highest_vif_index) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s", __FILE__, __PRETTY_FUNCTION__, vif_index, qpim_mroute_oif_highest_vif_index, addr_str); zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?", __FILE__, __PRETTY_FUNCTION__, ifindex2ifname(vif_index), vif_index); return -3; } return vif_index; } static int add_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask) { struct pim_interface *pim_ifp; int old_ttl; zassert(channel_oil); pim_ifp = oif->info; if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } if (pim_ifp->mroute_vif_index < 1) { zlog_warn("%s %s: interface %s vif_index=%d < 1", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index); return -1; } #ifdef PIM_ENFORCE_LOOPFREE_MFC /* Prevent creating MFC entry with OIF=IIF. This is a protection against implementation mistakes. PIM protocol implicitely ensures loopfree multicast topology. IGMP must be protected against adding looped MFC entries created by both source and receiver attached to the same interface. See TODO T22. */ if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -2; } #endif zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); /* Prevent single protocol from subscribing same interface to channel (S,G) multiple times */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); return -3; } /* Allow other protocol to request subscription of same interface to channel (S,G) multiple times, by silently ignoring further requests */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { /* Check the OIF really exists before returning, and only log warning otherwise */ if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); } return 0; } old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; if (old_ttl > 0) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -4; } channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL; if (pim_mroute_add(&channel_oil->oil)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; return -5; } channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec(); ++channel_oil->oil_size; channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask; if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } return 0; } static int del_oif(struct channel_oil *channel_oil, struct interface *oif, uint32_t proto_mask) { struct pim_interface *pim_ifp; int old_ttl; zassert(channel_oil); pim_ifp = oif->info; zassert(pim_ifp->mroute_vif_index >= 1); zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS); zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index); if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } /* Prevent single protocol from unsubscribing same interface from channel (S,G) multiple times */ if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); return -2; } /* Mark that protocol is no longer interested in this OIF */ channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask; /* Allow multiple protocols to unsubscribe same interface from channel (S,G) multiple times, by silently ignoring requests while there is at least one protocol interested in the channel */ if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) { /* Check the OIF keeps existing before returning, and only log warning otherwise */ if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, proto_mask, oif->name, pim_ifp->mroute_vif_index, channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index], source_str, group_str); } return 0; } old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]; if (old_ttl < 1) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); return -3; } channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0; if (pim_mroute_add(&channel_oil->oil)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, oif->name, pim_ifp->mroute_vif_index, source_str, group_str); channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl; return -4; } --channel_oil->oil_size; if (channel_oil->oil_size < 1) { if (pim_mroute_del(&channel_oil->oil)) { /* just log a warning in case of failure */ char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } if (PIM_DEBUG_MROUTE) { char group_str[100]; char source_str[100]; pim_inet4_dump("", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str)); zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE", __FILE__, __PRETTY_FUNCTION__, source_str, group_str, proto_mask, oif->name, pim_ifp->mroute_vif_index); } return 0; } void igmp_source_forward_start(struct igmp_source *source) { struct igmp_group *group; int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); } /* Prevent IGMP interface from installing multicast route multiple times */ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { return; } group = source->source_group; if (!source->source_channel_oil) { struct pim_interface *pim_oif; int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr); if (input_iface_vif_index < 1) { char source_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not find input interface for source %s", __FILE__, __PRETTY_FUNCTION__, source_str); return; } /* Protect IGMP against adding looped MFC entries created by both source and receiver attached to the same interface. See TODO T22. */ pim_oif = source->source_group->group_igmp_sock->interface->info; if (!pim_oif) { zlog_warn("%s: multicast not enabled on oif=%s ?", __PRETTY_FUNCTION__, source->source_group->group_igmp_sock->interface->name); return; } if (pim_oif->mroute_vif_index < 1) { zlog_warn("%s %s: oif=%s vif_index=%d < 1", __FILE__, __PRETTY_FUNCTION__, source->source_group->group_igmp_sock->interface->name, pim_oif->mroute_vif_index); return; } if (input_iface_vif_index == pim_oif->mroute_vif_index) { /* ignore request for looped MFC entry */ if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, input_iface_vif_index); } return; } source->source_channel_oil = pim_channel_oil_add(group->group_addr, source->source_addr, input_iface_vif_index); if (!source->source_channel_oil) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); return; } } result = add_oif(source->source_channel_oil, group->group_igmp_sock->interface, PIM_OIF_FLAG_PROTO_IGMP); if (result) { zlog_warn("%s: add_oif() failed with return=%d", __func__, result); return; } /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. */ pim_ifchannel_local_membership_add(group->group_igmp_sock->interface, source->source_addr, group->group_addr); IGMP_SOURCE_DO_FORWARDING(source->source_flags); } /* igmp_source_forward_stop: stop fowarding, but keep the source igmp_source_delete: stop fowarding, and delete the source */ void igmp_source_forward_stop(struct igmp_source *source) { struct igmp_group *group; int result; if (PIM_DEBUG_IGMP_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", source->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", source->source_group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d", __PRETTY_FUNCTION__, source_str, group_str, source->source_group->group_igmp_sock->fd, source->source_group->group_igmp_sock->interface->name, IGMP_SOURCE_TEST_FORWARDING(source->source_flags)); } /* Prevent IGMP interface from removing multicast route multiple times */ if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) { return; } group = source->source_group; /* It appears that in certain circumstances that igmp_source_forward_stop is called when IGMP forwarding was not enabled in oif_flags for this outgoing interface. Possibly because of multiple calls. When that happens, we enter the below if statement and this function returns early which in turn triggers the calling function to assert. Making the call to del_oif and ignoring the return code fixes the issue without ill effect, similar to pim_forward_stop below. */ result = del_oif(source->source_channel_oil, group->group_igmp_sock->interface, PIM_OIF_FLAG_PROTO_IGMP); if (result) { zlog_warn("%s: del_oif() failed with return=%d", __func__, result); return; } /* Feed IGMPv3-gathered local membership information into PIM per-interface (S,G) state. */ pim_ifchannel_local_membership_del(group->group_igmp_sock->interface, source->source_addr, group->group_addr); IGMP_SOURCE_DONT_FORWARDING(source->source_flags); } void pim_forward_start(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); } if (!up->channel_oil) { int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr); if (input_iface_vif_index < 1) { char source_str[100]; pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not find input interface for source %s", __FILE__, __PRETTY_FUNCTION__, source_str); return; } up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr, input_iface_vif_index); if (!up->channel_oil) { char group_str[100]; char source_str[100]; pim_inet4_dump("", up->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", up->source_addr, source_str, sizeof(source_str)); zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); return; } } add_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM); } void pim_forward_stop(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: (S,G)=(%s,%s) oif=%s", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); } if (!up->channel_oil) { char source_str[100]; char group_str[100]; pim_inet4_dump("", ch->source_addr, source_str, sizeof(source_str)); pim_inet4_dump("", ch->group_addr, group_str, sizeof(group_str)); zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL", __PRETTY_FUNCTION__, source_str, group_str, ch->interface->name); return; } del_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM); } quagga-0.99.24.1/pimd/pim_sock.c0000644000175000017500000002440512476520570013142 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include "pim_mroute.h" #include #include #include #include #include #include #include #include #include #include "log.h" #include "privs.h" #include "pimd.h" #include "pim_sock.h" #include "pim_str.h" #include "pim_igmp_join.h" /* GLOBAL VARS */ extern struct zebra_privs_t pimd_privs; int pim_socket_raw(int protocol) { int fd; if ( pimd_privs.change (ZPRIVS_RAISE) ) zlog_err ("pim_sockek_raw: could not raise privs, %s", safe_strerror (errno) ); fd = socket(AF_INET, SOCK_RAW, protocol); if ( pimd_privs.change (ZPRIVS_LOWER) ) zlog_err ("pim_socket_raw: could not lower privs, %s", safe_strerror (errno) ); if (fd < 0) { zlog_warn("Could not create raw socket: errno=%d: %s", errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } return fd; } int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop) { int fd; fd = pim_socket_raw(protocol); if (fd < 0) { zlog_warn("Could not create multicast socket: errno=%d: %s", errno, safe_strerror(errno)); return PIM_SOCK_ERR_SOCKET; } /* Needed to obtain destination address from recvmsg() */ { #if defined(HAVE_IP_PKTINFO) /* Linux IP_PKTINFO */ int opt = 1; if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt))) { zlog_warn("Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); } #elif defined(HAVE_IP_RECVDSTADDR) /* BSD IP_RECVDSTADDR */ int opt = 1; if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt))) { zlog_warn("Could not set IP_RECVDSTADDR on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); } #else zlog_err("%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()", __FILE__, __PRETTY_FUNCTION__); close(fd); return PIM_SOCK_ERR_DSTADDR; #endif } /* Set router alert (RFC 2113) for all IGMP messages (RFC 3376 4. Message Formats)*/ if (protocol == IPPROTO_IGMP) { char ra[4]; ra[0] = 148; ra[1] = 4; ra[2] = 0; ra[3] = 0; if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, ra, 4)) { zlog_warn("Could not set Router Alert Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_RA; } } { int reuse = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &reuse, sizeof(reuse))) { zlog_warn("Could not set Reuse Address Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_REUSE; } } { const int MTTL = 1; int ttl = MTTL; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *) &ttl, sizeof(ttl))) { zlog_warn("Could not set multicast TTL=%d on socket fd=%d: errno=%d: %s", MTTL, fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_TTL; } } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *) &loop, sizeof(loop))) { zlog_warn("Could not %s Multicast Loopback Option on socket fd=%d: errno=%d: %s", loop ? "enable" : "disable", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_LOOP; } if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, (void *) &ifaddr, sizeof(ifaddr))) { zlog_warn("Could not set Outgoing Interface Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_IFACE; } { long flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { zlog_warn("Could not get fcntl(F_GETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_GETFL; } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) { zlog_warn("Could not set fcntl(F_SETFL,O_NONBLOCK) on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); close(fd); return PIM_SOCK_ERR_NONBLOCK_SETFL; } } return fd; } int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, int ifindex) { int ret; #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX struct ip_mreqn opt; #else struct ip_mreq opt; #endif opt.imr_multiaddr = group; #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX opt.imr_address = ifaddr; opt.imr_ifindex = ifindex; #else opt.imr_interface = ifaddr; #endif ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &opt, sizeof(opt)); if (ret) { char group_str[100]; char ifaddr_str[100]; if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) sprintf(group_str, ""); if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) sprintf(ifaddr_str, ""); zlog_err("Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s", fd, group_str, ifaddr_str, errno, safe_strerror(errno)); return ret; } if (PIM_DEBUG_TRACE) { char group_str[100]; char ifaddr_str[100]; if (!inet_ntop(AF_INET, &group, group_str , sizeof(group_str))) sprintf(group_str, ""); if (!inet_ntop(AF_INET, &ifaddr, ifaddr_str , sizeof(ifaddr_str))) sprintf(ifaddr_str, ""); zlog_debug("Socket fd=%d joined group %s on interface address %s", fd, group_str, ifaddr_str); } return ret; } int pim_socket_join_source(int fd, int ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname) { if (pim_igmp_join_source(fd, ifindex, group_addr, source_addr)) { int e = errno; char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, fd, group_str, source_str, ifindex, ifname, e, safe_strerror(e)); return -1; } return 0; } int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, int *ifindex) { struct msghdr msgh; struct cmsghdr *cmsg; struct iovec iov; char cbuf[1000]; int err; /* * IP_PKTINFO / IP_RECVDSTADDR don't yield sin_port. * Use getsockname() to get sin_port. */ if (to) { struct sockaddr_in si; socklen_t si_len = sizeof(si); ((struct sockaddr_in *) to)->sin_family = AF_INET; if (pim_socket_getsockname(fd, (struct sockaddr *) &si, &si_len)) { ((struct sockaddr_in *) to)->sin_port = ntohs(0); ((struct sockaddr_in *) to)->sin_addr.s_addr = ntohl(0); } else { ((struct sockaddr_in *) to)->sin_port = si.sin_port; ((struct sockaddr_in *) to)->sin_addr = si.sin_addr; } if (tolen) *tolen = sizeof(si); } memset(&msgh, 0, sizeof(struct msghdr)); iov.iov_base = buf; iov.iov_len = len; msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); msgh.msg_name = from; msgh.msg_namelen = fromlen ? *fromlen : 0; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; err = recvmsg(fd, &msgh, 0); if (err < 0) return err; if (fromlen) *fromlen = msgh.msg_namelen; for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { #ifdef HAVE_IP_PKTINFO if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg); if (to) ((struct sockaddr_in *) to)->sin_addr = i->ipi_addr; if (tolen) *tolen = sizeof(struct sockaddr_in); if (ifindex) *ifindex = i->ipi_ifindex; if (to && PIM_DEBUG_PACKETS) { char to_str[100]; pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: HAVE_IP_PKTINFO to=%s,%d", __PRETTY_FUNCTION__, to_str, ntohs(to->sin_port)); } break; } #endif #ifdef HAVE_IP_RECVDSTADDR if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) { struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg); if (to) ((struct sockaddr_in *) to)->sin_addr = *i; if (tolen) *tolen = sizeof(struct sockaddr_in); if (to && PIM_DEBUG_PACKETS) { char to_str[100]; pim_inet4_dump("", to->sin_addr, to_str, sizeof(to_str)); zlog_debug("%s: HAVE_IP_RECVDSTADDR to=%s,%d", __PRETTY_FUNCTION__, to_str, ntohs(to->sin_port)); } break; } #endif #if defined(HAVE_IP_RECVIF) && defined(CMSG_IFINDEX) if (cmsg->cmsg_type == IP_RECVIF) if (ifindex) *ifindex = CMSG_IFINDEX(cmsg); #endif } /* for (cmsg) */ return err; /* len */ } int pim_socket_mcastloop_get(int fd) { int loop; socklen_t loop_len = sizeof(loop); if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, &loop_len)) { int e = errno; zlog_warn("Could not get Multicast Loopback Option on socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); errno = e; return PIM_SOCK_ERR_LOOP; } return loop; } int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen) { if (getsockname(fd, name, namelen)) { int e = errno; zlog_warn("Could not get Socket Name for socket fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); errno = e; return PIM_SOCK_ERR_NAME; } return PIM_SOCK_ERR_NONE; } quagga-0.99.24.1/pimd/pim_igmp.c0000644000175000017500000012175512476520570013145 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "memory.h" #include "pimd.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_iface.h" #include "pim_sock.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_util.h" #include "pim_time.h" #include "pim_zebra.h" #define IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE (1) #define IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE (2) #define IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE (3) #define IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE (4) #define IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES (5) #define IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES (6) static void group_timer_off(struct igmp_group *group); static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr); static int igmp_sock_open(struct in_addr ifaddr, int ifindex, uint32_t pim_options) { int fd; int join = 0; struct in_addr group; fd = pim_socket_mcast(IPPROTO_IGMP, ifaddr, 1 /* loop=true */); if (fd < 0) return -1; if (PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(pim_options)) { if (inet_aton(PIM_ALL_ROUTERS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) ++join; } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_ROUTERS, errno, safe_strerror(errno)); } } /* IGMP routers periodically send IGMP general queries to AllSystems=224.0.0.1 IGMP routers must receive general queries for querier election. */ if (inet_aton(PIM_ALL_SYSTEMS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) ++join; } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_SYSTEMS, errno, safe_strerror(errno)); } if (inet_aton(PIM_ALL_IGMP_ROUTERS, &group)) { if (!pim_socket_join(fd, group, ifaddr, ifindex)) { ++join; } } else { zlog_warn("%s %s: IGMP socket fd=%d interface %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, fd, inet_ntoa(ifaddr), PIM_ALL_IGMP_ROUTERS, errno, safe_strerror(errno)); } if (!join) { zlog_err("IGMP socket fd=%d could not join any group on interface address %s", fd, inet_ntoa(ifaddr)); close(fd); fd = -1; } return fd; } #undef IGMP_SOCK_DUMP #ifdef IGMP_SOCK_DUMP static void igmp_sock_dump(array_t *igmp_sock_array) { int size = array_size(igmp_sock_array); for (int i = 0; i < size; ++i) { struct igmp_sock *igmp = array_get(igmp_sock_array, i); zlog_debug("%s %s: [%d/%d] igmp_addr=%s fd=%d", __FILE__, __PRETTY_FUNCTION__, i, size, inet_ntoa(igmp->ifaddr), igmp->fd); } } #endif struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct in_addr ifaddr) { struct listnode *sock_node; struct igmp_sock *igmp; #ifdef IGMP_SOCK_DUMP igmp_sock_dump(igmp_sock_list); #endif for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) if (ifaddr.s_addr == igmp->ifaddr.s_addr) return igmp; return 0; } struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd) { struct listnode *sock_node; struct igmp_sock *igmp; for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) if (fd == igmp->fd) return igmp; return 0; } static int pim_igmp_other_querier_expire(struct thread *t) { struct igmp_sock *igmp; zassert(t); igmp = THREAD_ARG(t); zassert(igmp); zassert(igmp->t_other_querier_timer); zassert(!igmp->t_igmp_query_timer); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: Querier %s resuming", __PRETTY_FUNCTION__, ifaddr_str); } igmp->t_other_querier_timer = 0; /* We are the current querier, then re-start sending general queries. */ pim_igmp_general_query_on(igmp); return 0; } void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) { long other_querier_present_interval_msec; struct pim_interface *pim_ifp; zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; if (igmp->t_other_querier_timer) { /* There is other querier present already, then reset the other-querier-present timer. */ if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s resetting TIMER event for Other-Querier-Present", ifaddr_str); } THREAD_OFF(igmp->t_other_querier_timer); zassert(!igmp->t_other_querier_timer); } else { /* We are the current querier, then stop sending general queries: igmp->t_igmp_query_timer = 0; */ pim_igmp_general_query_off(igmp); } /* Since this socket is starting the other-querier-present timer, there should not be periodic query timer for this socket. */ zassert(!igmp->t_igmp_query_timer); /* RFC 3376: 8.5. Other Querier Present Interval The Other Querier Present Interval is the length of time that must pass before a multicast router decides that there is no longer another multicast router which should be the querier. This value MUST be ((the Robustness Variable) times (the Query Interval)) plus (one half of one Query Response Interval). other_querier_present_interval_msec = \ igmp->querier_robustness_variable * \ 1000 * igmp->querier_query_interval + \ 100 * (pim_ifp->query_max_response_time_dsec >> 1); */ other_querier_present_interval_msec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s scheduling %ld.%03ld sec TIMER event for Other-Querier-Present", ifaddr_str, other_querier_present_interval_msec / 1000, other_querier_present_interval_msec % 1000); } THREAD_TIMER_MSEC_ON(master, igmp->t_other_querier_timer, pim_igmp_other_querier_expire, igmp, other_querier_present_interval_msec); } void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_other_querier_timer) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("IGMP querier %s fd=%d cancelling other-querier-present TIMER event on %s", ifaddr_str, igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_other_querier_timer); zassert(!igmp->t_other_querier_timer); } static int recv_igmp_query(struct igmp_sock *igmp, int query_version, int max_resp_code, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp; struct pim_interface *pim_ifp; uint8_t resv_s_qrv = 0; uint8_t s_flag = 0; uint8_t qrv = 0; struct in_addr group_addr; uint16_t recv_checksum; uint16_t checksum; int i; //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); ifp = igmp->interface; pim_ifp = ifp->info; recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP query v%d from %s on %s: checksum mismatch: received=%x computed=%x", query_version, from_str, ifp->name, recv_checksum, checksum); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_debug("Recv IGMP query v%d from %s on %s: size=%d checksum=%x group=%s", query_version, from_str, ifp->name, igmp_msg_len, checksum, group_str); } /* RFC 3376: 6.6.2. Querier Election When a router receives a query with a lower IP address, it sets the Other-Querier-Present timer to Other Querier Present Interval and ceases to send queries on the network if it was the previously elected querier. */ if (ntohl(from.s_addr) < ntohl(igmp->ifaddr.s_addr)) { if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: local address %s (%u) lost querier election to %s (%u)", ifp->name, ifaddr_str, ntohl(igmp->ifaddr.s_addr), from_str, ntohl(from.s_addr)); } pim_igmp_other_querier_timer_on(igmp); } if (query_version == 3) { /* RFC 3376: 4.1.6. QRV (Querier's Robustness Variable) Routers adopt the QRV value from the most recently received Query as their own [Robustness Variable] value, unless that most recently received QRV was zero, in which case the receivers use the default [Robustness Variable] value specified in section 8.1 or a statically configured value. */ resv_s_qrv = igmp_msg[8]; qrv = 7 & resv_s_qrv; igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable; } /* RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) Multicast routers that are not the current querier adopt the QQI value from the most recently received Query as their own [Query Interval] value, unless that most recently received QQI was zero, in which case the receiving routers use the default. */ if (igmp->t_other_querier_timer && query_version == 3) { /* other querier present */ uint8_t qqic; uint16_t qqi; qqic = igmp_msg[9]; qqi = igmp_msg_decode8to16(qqic); igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)", ifaddr_str, qqi ? "recv-non-default" : "default", igmp->querier_query_interval, qqic, from_str); } } /* RFC 3376: 6.6.1. Timer Updates When a router sends or receives a query with a clear Suppress Router-Side Processing flag, it must update its timers to reflect the correct timeout values for the group or sources being queried. General queries don't trigger timer update. */ if (query_version == 3) { s_flag = (1 << 3) & resv_s_qrv; } else { /* Neither V1 nor V2 have this field. Pimd should really go into * a compatibility mode here and run as V2 (or V1) but it doesn't * so for now, lets just set the flag to suppress these timer updates. */ s_flag = 1; } if (!s_flag) { /* s_flag is clear */ if (PIM_INADDR_IS_ANY(group_addr)) { /* this is a general query */ /* log that general query should have the s_flag set */ zlog_warn("General IGMP query v%d from %s on %s: Suppress Router-Side Processing flag is clear", query_version, from_str, ifp->name); } else { struct igmp_group *group; /* this is a non-general query: perform timer updates */ group = find_group_by_addr(igmp, group_addr); if (group) { int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET)); /* RFC 3376: 6.6.1. Timer Updates Query Q(G,A): Source Timer for sources in A are lowered to LMQT Query Q(G): Group Timer is lowered to LMQT */ if (recv_num_sources < 1) { /* Query Q(G): Group Timer is lowered to LMQT */ igmp_group_timer_lower_to_lmqt(group); } else { /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */ /* Scan sources in query and lower their timers to LMQT */ struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET); for (i = 0; i < recv_num_sources; ++i) { //struct in_addr src_addr = sources[i]; //struct igmp_source *src = igmp_find_source_by_addr(group, src_addr); struct in_addr src_addr; struct igmp_source *src; memcpy(&src_addr, sources + i, sizeof(struct in_addr)); src = igmp_find_source_by_addr(group, src_addr); if (src) { igmp_source_timer_lower_to_lmqt(src); } } } } else { char group_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); zlog_warn("IGMP query v%d from %s on %s: could not find group %s for timer update", query_version, from_str, ifp->name, group_str); } } } /* s_flag is clear: timer updates */ return 0; } static int igmp_v3_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { uint16_t recv_checksum; uint16_t checksum; int num_groups; uint8_t *group_record; uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len; struct interface *ifp = igmp->interface; int i; if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) { zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d", from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE); return -1; } recv_checksum = *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET); /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; checksum = in_cksum(igmp_msg, igmp_msg_len); if (checksum != recv_checksum) { zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x", from_str, ifp->name, recv_checksum, checksum); return -1; } num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET)); if (num_groups < 1) { zlog_warn("Recv IGMP report v3 from %s on %s: missing group records", from_str, ifp->name); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d", from_str, ifp->name, igmp_msg_len, checksum, num_groups); } group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; /* Scan groups */ for (i = 0; i < num_groups; ++i) { struct in_addr rec_group; uint8_t *sources; uint8_t *src; int rec_type; int rec_auxdatalen; int rec_num_sources; int j; if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) { zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end", from_str, ifp->name); return -1; } rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET]; rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET]; rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET)); //rec_group = *(struct in_addr *)(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET); memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr)); if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s", from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group)); } /* Scan sources */ sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET; for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) { if ((src + 4) > report_pastend) { zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end", from_str, ifp->name); return -1; } if (PIM_DEBUG_IGMP_PACKETS) { char src_str[200]; if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str))) sprintf(src_str, ""); zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s", from_str, ifp->name, i, inet_ntoa(rec_group), src_str); } } /* for (sources) */ switch (rec_type) { case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE: igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE: igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE: igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE: igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES: igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES: igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources); break; default: zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d", from_str, ifp->name, rec_type); } group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2); } /* for (group records) */ return 0; } static void on_trace(const char *label, struct interface *ifp, struct in_addr from) { if (PIM_DEBUG_IGMP_TRACE) { char from_str[100]; pim_inet4_dump("", from, from_str, sizeof(from_str)); zlog_debug("%s: from %s on %s", label, from_str, ifp->name); } } static int igmp_v2_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; struct igmp_group *group; struct in_addr group_addr; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP report v2 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return -1; } group->last_igmp_v2_report_dsec = pim_time_monotonic_dsec(); return 0; } static int igmp_v2_leave(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP leave v2 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } return 0; } static int igmp_v1_report(struct igmp_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; struct igmp_group *group; struct in_addr group_addr; on_trace(__PRETTY_FUNCTION__, igmp->interface, from); if (igmp_msg_len != IGMP_V12_MSG_SIZE) { zlog_warn("Recv IGMP report v1 from %s on %s: size=%d other than correct=%d", from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); return -1; } if (PIM_DEBUG_IGMP_TRACE) { zlog_warn("%s %s: FIXME WRITEME", __FILE__, __PRETTY_FUNCTION__); } //group_addr = *(struct in_addr *)(igmp_msg + 4); memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr)); /* non-existant group is created as INCLUDE {empty} */ group = igmp_add_group_by_addr(igmp, group_addr, ifp->name); if (!group) { return -1; } group->last_igmp_v1_report_dsec = pim_time_monotonic_dsec(); return 0; } int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) { struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ char *igmp_msg; int igmp_msg_len; int msg_type; char from_str[100]; char to_str[100]; if (len < sizeof(*ip_hdr)) { zlog_warn("IGMP packet size=%zu shorter than minimum=%zu", len, sizeof(*ip_hdr)); return -1; } ip_hdr = (struct ip *) buf; pim_inet4_dump("", ip_hdr->ip_src, from_str , sizeof(from_str)); pim_inet4_dump("", ip_hdr->ip_dst, to_str , sizeof(to_str)); ip_hlen = ip_hdr->ip_hl << 2; /* ip_hl gives length in 4-byte words */ if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IP packet from %s to %s on %s: size=%zu ip_header_size=%zu ip_proto=%d", from_str, to_str, igmp->interface->name, len, ip_hlen, ip_hdr->ip_p); } if (ip_hdr->ip_p != PIM_IP_PROTO_IGMP) { zlog_warn("IP packet protocol=%d is not IGMP=%d", ip_hdr->ip_p, PIM_IP_PROTO_IGMP); return -1; } if (ip_hlen < PIM_IP_HEADER_MIN_LEN) { zlog_warn("IP packet header size=%zu shorter than minimum=%d", ip_hlen, PIM_IP_HEADER_MIN_LEN); return -1; } if (ip_hlen > PIM_IP_HEADER_MAX_LEN) { zlog_warn("IP packet header size=%zu greater than maximum=%d", ip_hlen, PIM_IP_HEADER_MAX_LEN); return -1; } igmp_msg = buf + ip_hlen; msg_type = *igmp_msg; igmp_msg_len = len - ip_hlen; if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug("Recv IGMP packet from %s to %s on %s: ttl=%d msg_type=%d msg_size=%d", from_str, to_str, igmp->interface->name, ip_hdr->ip_ttl, msg_type, igmp_msg_len); } if (igmp_msg_len < PIM_IGMP_MIN_LEN) { zlog_warn("IGMP message size=%d shorter than minimum=%d", igmp_msg_len, PIM_IGMP_MIN_LEN); return -1; } switch (msg_type) { case PIM_IGMP_MEMBERSHIP_QUERY: { int max_resp_code = igmp_msg[1]; int query_version; /* RFC 3376: 7.1. Query Version Distinctions IGMPv1 Query: length = 8 octets AND Max Resp Code field is zero IGMPv2 Query: length = 8 octets AND Max Resp Code field is non-zero IGMPv3 Query: length >= 12 octets */ if (igmp_msg_len == 8) { query_version = max_resp_code ? 2 : 1; } else if (igmp_msg_len >= 12) { query_version = 3; } else { zlog_warn("Unknown IGMP query version"); return -1; } return recv_igmp_query(igmp, query_version, max_resp_code, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); } case PIM_IGMP_V3_MEMBERSHIP_REPORT: return igmp_v3_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V2_MEMBERSHIP_REPORT: return igmp_v2_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V1_MEMBERSHIP_REPORT: return igmp_v1_report(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); case PIM_IGMP_V2_LEAVE_GROUP: return igmp_v2_leave(igmp, ip_hdr->ip_src, from_str, igmp_msg, igmp_msg_len); } zlog_warn("Ignoring unsupported IGMP message type: %d", msg_type); return -1; } static int pim_igmp_general_query(struct thread *t); void pim_igmp_general_query_on(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; int startup_mode; int query_interval; zassert(igmp); zassert(igmp->interface); /* Since this socket is starting as querier, there should not exist a timer for other-querier-present. */ zassert(!igmp->t_other_querier_timer); pim_ifp = igmp->interface->info; zassert(pim_ifp); /* RFC 3376: 8.6. Startup Query Interval The Startup Query Interval is the interval between General Queries sent by a Querier on startup. Default: 1/4 the Query Interval. */ startup_mode = igmp->startup_query_count > 0; if (startup_mode) { --igmp->startup_query_count; /* query_interval = pim_ifp->igmp_default_query_interval >> 2; */ query_interval = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); } else { query_interval = igmp->querier_query_interval; } if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("Querier %s scheduling %d-second (%s) TIMER event for IGMP query on fd=%d", ifaddr_str, query_interval, startup_mode ? "startup" : "non-startup", igmp->fd); } igmp->t_igmp_query_timer = 0; zassert(!igmp->t_igmp_query_timer); THREAD_TIMER_ON(master, igmp->t_igmp_query_timer, pim_igmp_general_query, igmp, query_interval); } void pim_igmp_general_query_off(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_igmp_query_timer) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("IGMP querier %s fd=%d cancelling query TIMER event on %s", ifaddr_str, igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_igmp_query_timer); zassert(!igmp->t_igmp_query_timer); } /* Issue IGMP general query */ static int pim_igmp_general_query(struct thread *t) { char query_buf[PIM_IGMP_BUFSIZE_WRITE]; struct igmp_sock *igmp; struct in_addr dst_addr; struct in_addr group_addr; struct pim_interface *pim_ifp; zassert(t); igmp = THREAD_ARG(t); zassert(igmp); zassert(igmp->interface); zassert(igmp->interface->info); pim_ifp = igmp->interface->info; /* RFC3376: 4.1.12. IP Destination Addresses for Queries In IGMPv3, General Queries are sent with an IP destination address of 224.0.0.1, the all-systems multicast address. Group-Specific and Group-and-Source-Specific Queries are sent with an IP destination address equal to the multicast address of interest. */ dst_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); group_addr.s_addr = PIM_NET_INADDR_ANY; if (PIM_DEBUG_IGMP_TRACE) { char querier_str[100]; char dst_str[100]; pim_inet4_dump("", igmp->ifaddr, querier_str, sizeof(querier_str)); pim_inet4_dump("", dst_addr, dst_str, sizeof(dst_str)); zlog_debug("Querier %s issuing IGMP general query to %s on %s", querier_str, dst_str, igmp->interface->name); } pim_igmp_send_membership_query(0 /* igmp_group */, igmp->fd, igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources */, dst_addr, group_addr, pim_ifp->igmp_query_max_response_time_dsec, 1 /* s_flag: always set for general queries */, igmp->querier_robustness_variable, igmp->querier_query_interval); pim_igmp_general_query_on(igmp); return 0; } static int pim_igmp_read(struct thread *t); static void igmp_read_on(struct igmp_sock *igmp) { zassert(igmp); if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Scheduling READ event on IGMP socket fd=%d", igmp->fd); } igmp->t_igmp_read = 0; zassert(!igmp->t_igmp_read); THREAD_READ_ON(master, igmp->t_igmp_read, pim_igmp_read, igmp, igmp->fd); } static int pim_igmp_read(struct thread *t) { struct igmp_sock *igmp; int fd; struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); socklen_t tolen = sizeof(to); uint8_t buf[PIM_IGMP_BUFSIZE_READ]; int len; int ifindex = -1; int result = -1; /* defaults to bad */ zassert(t); igmp = THREAD_ARG(t); zassert(igmp); fd = THREAD_FD(t); zassert(fd == igmp->fd); len = pim_socket_recvfromto(fd, buf, sizeof(buf), &from, &fromlen, &to, &tolen, &ifindex); if (len < 0) { zlog_warn("Failure receiving IP IGMP packet on fd=%d: errno=%d: %s", fd, errno, safe_strerror(errno)); goto done; } if (PIM_DEBUG_IGMP_PACKETS) { char from_str[100]; char to_str[100]; if (!inet_ntop(AF_INET, &from.sin_addr, from_str, sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str, sizeof(to_str))) sprintf(to_str, ""); zlog_debug("Recv IP IGMP pkt size=%d from %s to %s on fd=%d on ifindex=%d (sock_ifindex=%d)", len, from_str, to_str, fd, ifindex, igmp->interface->ifindex); } #ifdef PIM_CHECK_RECV_IFINDEX_SANITY /* ifindex sanity check */ if (ifindex != (int) igmp->interface->ifindex) { char from_str[100]; char to_str[100]; struct interface *ifp; if (!inet_ntop(AF_INET, &from.sin_addr, from_str , sizeof(from_str))) sprintf(from_str, ""); if (!inet_ntop(AF_INET, &to.sin_addr, to_str , sizeof(to_str))) sprintf(to_str, ""); ifp = if_lookup_by_index(ifindex); if (ifp) { zassert(ifindex == (int) ifp->ifindex); } #ifdef PIM_REPORT_RECV_IFINDEX_MISMATCH zlog_warn("Interface mismatch: recv IGMP pkt from %s to %s on fd=%d: recv_ifindex=%d (%s) sock_ifindex=%d (%s)", from_str, to_str, fd, ifindex, ifp ? ifp->name : "", igmp->interface->ifindex, igmp->interface->name); #endif goto done; } #endif if (pim_igmp_packet(igmp, (char *)buf, len)) { goto done; } result = 0; /* good */ done: igmp_read_on(igmp); return result; } static void sock_close(struct igmp_sock *igmp) { pim_igmp_other_querier_timer_off(igmp); pim_igmp_general_query_off(igmp); if (PIM_DEBUG_IGMP_TRACE) { if (igmp->t_igmp_read) { zlog_debug("Cancelling READ event on IGMP socket %s fd=%d on interface %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name); } } THREAD_OFF(igmp->t_igmp_read); zassert(!igmp->t_igmp_read); if (close(igmp->fd)) { zlog_err("Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name, errno, safe_strerror(errno)); } if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Deleted IGMP socket %s fd=%d on interface %s", inet_ntoa(igmp->ifaddr), igmp->fd, igmp->interface->name); } } void igmp_startup_mode_on(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; pim_ifp = igmp->interface->info; /* RFC 3376: 8.7. Startup Query Count The Startup Query Count is the number of Queries sent out on startup, separated by the Startup Query Interval. Default: the Robustness Variable. */ igmp->startup_query_count = igmp->querier_robustness_variable; /* Since we're (re)starting, reset QQI to default Query Interval */ igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; } static void igmp_group_free(struct igmp_group *group) { zassert(!group->t_group_query_retransmit_timer); zassert(!group->t_group_timer); zassert(group->group_source_list); zassert(!listcount(group->group_source_list)); list_free(group->group_source_list); XFREE(MTYPE_PIM_IGMP_GROUP, group); } static void igmp_group_delete(struct igmp_group *group) { struct listnode *src_node; struct listnode *src_nextnode; struct igmp_source *src; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Deleting IGMP group %s from socket %d interface %s", group_str, group->group_igmp_sock->fd, group->group_igmp_sock->interface->name); } for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode, src)) { igmp_source_delete(src); } if (group->t_group_query_retransmit_timer) { THREAD_OFF(group->t_group_query_retransmit_timer); zassert(!group->t_group_query_retransmit_timer); } group_timer_off(group); listnode_delete(group->group_igmp_sock->igmp_group_list, group); igmp_group_free(group); } void igmp_group_delete_empty_include(struct igmp_group *group) { zassert(!group->group_filtermode_isexcl); zassert(!listcount(group->group_source_list)); igmp_group_delete(group); } void igmp_sock_free(struct igmp_sock *igmp) { zassert(!igmp->t_igmp_read); zassert(!igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); zassert(igmp->igmp_group_list); zassert(!listcount(igmp->igmp_group_list)); list_free(igmp->igmp_group_list); XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); } void igmp_sock_delete(struct igmp_sock *igmp) { struct pim_interface *pim_ifp; struct listnode *grp_node; struct listnode *grp_nextnode; struct igmp_group *grp; for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode, grp)) { igmp_group_delete(grp); } sock_close(igmp); pim_ifp = igmp->interface->info; listnode_delete(pim_ifp->igmp_socket_list, igmp); igmp_sock_free(igmp); } static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, struct interface *ifp) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; pim_ifp = ifp->info; if (PIM_DEBUG_IGMP_TRACE) { zlog_debug("Creating IGMP socket fd=%d for address %s on interface %s", fd, inet_ntoa(ifaddr), ifp->name); } igmp = XMALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp)); if (!igmp) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; } igmp->igmp_group_list = list_new(); if (!igmp->igmp_group_list) { zlog_err("%s %s: failure: igmp_group_list = list_new()", __FILE__, __PRETTY_FUNCTION__); return 0; } igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free; igmp->fd = fd; igmp->interface = ifp; igmp->ifaddr = ifaddr; igmp->t_igmp_read = 0; igmp->t_igmp_query_timer = 0; igmp->t_other_querier_timer = 0; /* no other querier present */ igmp->querier_robustness_variable = pim_ifp->igmp_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); /* igmp_startup_mode_on() will reset QQI: igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; */ igmp_startup_mode_on(igmp); igmp_read_on(igmp); pim_igmp_general_query_on(igmp); return igmp; } struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, struct interface *ifp) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; int fd; pim_ifp = ifp->info; fd = igmp_sock_open(ifaddr, ifp->ifindex, pim_ifp->options); if (fd < 0) { zlog_warn("Could not open IGMP socket for %s on %s", inet_ntoa(ifaddr), ifp->name); return 0; } igmp = igmp_sock_new(fd, ifaddr, ifp); if (!igmp) { zlog_err("%s %s: igmp_sock_new() failure", __FILE__, __PRETTY_FUNCTION__); close(fd); return 0; } listnode_add(igmp_sock_list, igmp); #ifdef IGMP_SOCK_DUMP igmp_sock_dump(igmp_sock_array); #endif return igmp; } /* RFC 3376: 6.5. Switching Router Filter-Modes When a router's filter-mode for a group is EXCLUDE and the group timer expires, the router filter-mode for the group transitions to INCLUDE. A router uses source records with running source timers as its state for the switch to a filter-mode of INCLUDE. If there are any source records with source timers greater than zero (i.e., requested to be forwarded), a router switches to filter-mode of INCLUDE using those source records. Source records whose timers are zero (from the previous EXCLUDE mode) are deleted. */ static int igmp_group_timer(struct thread *t) { struct igmp_group *group; zassert(t); group = THREAD_ARG(t); zassert(group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("%s: Timer for group %s on interface %s", __PRETTY_FUNCTION__, group_str, group->group_igmp_sock->interface->name); } zassert(group->group_filtermode_isexcl); group->t_group_timer = 0; group->group_filtermode_isexcl = 0; /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); igmp_source_delete_expired(group->group_source_list); zassert(!group->t_group_timer); zassert(!group->group_filtermode_isexcl); /* RFC 3376: 6.2.2. Definition of Group Timers If there are no more source records for the group, delete group record. */ if (listcount(group->group_source_list) < 1) { igmp_group_delete_empty_include(group); } return 0; } static void group_timer_off(struct igmp_group *group) { if (!group->t_group_timer) return; if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Cancelling TIMER event for group %s on %s", group_str, group->group_igmp_sock->interface->name); } THREAD_OFF(group->t_group_timer); zassert(!group->t_group_timer); } void igmp_group_timer_on(struct igmp_group *group, long interval_msec, const char *ifname) { group_timer_off(group); if (PIM_DEBUG_IGMP_EVENTS) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s on %s", interval_msec / 1000, interval_msec % 1000, group_str, ifname); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(group->group_filtermode_isexcl); THREAD_TIMER_MSEC_ON(master, group->t_group_timer, igmp_group_timer, group, interval_msec); } static struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr) { struct igmp_group *group; struct listnode *node; for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, node, group)) if (group_addr.s_addr == group->group_addr.s_addr) return group; return 0; } struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr, const char *ifname) { struct igmp_group *group; group = find_group_by_addr(igmp, group_addr); if (group) { return group; } /* Non-existant group is created as INCLUDE {empty}: RFC 3376 - 5.1. Action on Change of Interface State If no interface state existed for that multicast address before the change (i.e., the change consisted of creating a new per-interface record), or if no state exists after the change (i.e., the change consisted of deleting a per-interface record), then the "non-existent" state is considered to have a filter mode of INCLUDE and an empty source list. */ group = XMALLOC(MTYPE_PIM_IGMP_GROUP, sizeof(*group)); if (!group) { zlog_warn("%s %s: XMALLOC() failure", __FILE__, __PRETTY_FUNCTION__); return 0; /* error, not found, could not create */ } group->group_source_list = list_new(); if (!group->group_source_list) { zlog_warn("%s %s: list_new() failure", __FILE__, __PRETTY_FUNCTION__); XFREE(MTYPE_PIM_IGMP_GROUP, group); /* discard group */ return 0; /* error, not found, could not initialize */ } group->group_source_list->del = (void (*)(void *)) igmp_source_free; group->t_group_timer = 0; group->t_group_query_retransmit_timer = 0; group->group_specific_query_retransmit_count = 0; group->group_addr = group_addr; group->group_igmp_sock = igmp; group->last_igmp_v1_report_dsec = -1; group->last_igmp_v2_report_dsec = -1; group->group_creation = pim_time_monotonic_sec(); /* initialize new group as INCLUDE {empty} */ group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */ listnode_add(igmp->igmp_group_list, group); if (PIM_DEBUG_IGMP_TRACE) { char group_str[100]; pim_inet4_dump("", group->group_addr, group_str, sizeof(group_str)); zlog_debug("Creating new IGMP group %s on socket %d interface %s", group_str, group->group_igmp_sock->fd, ifname); } /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ zassert(!group->group_filtermode_isexcl); /* INCLUDE mode */ zassert(!group->t_group_timer); /* group timer == 0 */ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ igmp_anysource_forward_stop(group); return group; } quagga-0.99.24.1/pimd/pim_vty.c0000644000175000017500000001054012476520570013020 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "linklist.h" #include "pimd.h" #include "pim_vty.h" #include "pim_iface.h" #include "pim_cmd.h" #include "pim_str.h" #include "pim_ssmpingd.h" int pim_debug_config_write(struct vty *vty) { int writes = 0; if (PIM_DEBUG_IGMP_EVENTS) { vty_out(vty, "debug igmp events%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_IGMP_PACKETS) { vty_out(vty, "debug igmp packets%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_IGMP_TRACE) { vty_out(vty, "debug igmp trace%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_MROUTE) { vty_out(vty, "debug mroute%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_EVENTS) { vty_out(vty, "debug pim events%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETS) { vty_out(vty, "debug pim packets%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { vty_out(vty, "debug pim packet-dump send%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_PACKETDUMP_RECV) { vty_out(vty, "debug pim packet-dump receive%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_PIM_TRACE) { vty_out(vty, "debug pim trace%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_ZEBRA) { vty_out(vty, "debug pim zebra%s", VTY_NEWLINE); ++writes; } if (PIM_DEBUG_SSMPINGD) { vty_out(vty, "debug ssmpingd%s", VTY_NEWLINE); ++writes; } return writes; } int pim_global_config_write(struct vty *vty) { int writes = 0; if (PIM_MROUTE_IS_ENABLED) { vty_out(vty, "%s%s", PIM_CMD_IP_MULTICAST_ROUTING, VTY_NEWLINE); ++writes; } if (qpim_ssmpingd_list) { struct listnode *node; struct ssmpingd_sock *ss; vty_out(vty, "!%s", VTY_NEWLINE); ++writes; for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { char source_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); vty_out(vty, "ip ssmpingd %s%s", source_str, VTY_NEWLINE); ++writes; } } return writes; } int pim_interface_config_write(struct vty *vty) { int writes = 0; struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { /* IF name */ vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); ++writes; if (ifp->info) { struct pim_interface *pim_ifp = ifp->info; /* IF ip pim ssm */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { vty_out(vty, " ip pim ssm%s", VTY_NEWLINE); ++writes; } /* IF ip igmp */ if (PIM_IF_TEST_IGMP(pim_ifp->options)) { vty_out(vty, " ip igmp%s", VTY_NEWLINE); ++writes; } /* IF ip igmp query-interval */ vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_INTERVAL, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); ++writes; /* IF ip igmp query-max-response-time */ vty_out(vty, " %s %d%s", PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); ++writes; /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { struct listnode *node; struct igmp_join *ij; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, node, ij)) { char group_str[100]; char source_str[100]; pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); vty_out(vty, " ip igmp join %s %s%s", group_str, source_str, VTY_NEWLINE); ++writes; } } } vty_out(vty, "!%s", VTY_NEWLINE); ++writes; } return writes; } quagga-0.99.24.1/pimd/pim_iface.c0000644000175000017500000007432212476520570013255 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "if.h" #include "log.h" #include "vty.h" #include "memory.h" #include "prefix.h" #include "pimd.h" #include "pim_iface.h" #include "pim_igmp.h" #include "pim_mroute.h" #include "pim_oil.h" #include "pim_str.h" #include "pim_pim.h" #include "pim_neighbor.h" #include "pim_ifchannel.h" #include "pim_rand.h" #include "pim_sock.h" #include "pim_time.h" #include "pim_ssmpingd.h" static void pim_if_igmp_join_del_all(struct interface *ifp); void pim_if_init() { if_init(); } static void *if_list_clean(struct pim_interface *pim_ifp) { if (pim_ifp->igmp_join_list) { list_delete(pim_ifp->igmp_join_list); } if (pim_ifp->igmp_socket_list) { list_delete(pim_ifp->igmp_socket_list); } if (pim_ifp->pim_neighbor_list) { list_delete(pim_ifp->pim_neighbor_list); } if (pim_ifp->pim_ifchannel_list) { list_delete(pim_ifp->pim_ifchannel_list); } XFREE(MTYPE_PIM_INTERFACE, pim_ifp); return 0; } struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim) { struct pim_interface *pim_ifp; zassert(ifp); zassert(!ifp->info); pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); if (!pim_ifp) { zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp)); return 0; } pim_ifp->options = 0; pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; /* RFC 3376: 8.3. Query Response Interval The number of seconds represented by the [Query Response Interval] must be less than the [Query Interval]. */ zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval); if (pim) PIM_IF_DO_PIM(pim_ifp->options); if (igmp) PIM_IF_DO_IGMP(pim_ifp->options); #if 0 /* FIXME: Should join? */ PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); #endif pim_ifp->igmp_join_list = 0; pim_ifp->igmp_socket_list = 0; pim_ifp->pim_neighbor_list = 0; pim_ifp->pim_ifchannel_list = 0; /* list of struct igmp_sock */ pim_ifp->igmp_socket_list = list_new(); if (!pim_ifp->igmp_socket_list) { zlog_err("%s %s: failure: igmp_socket_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free; /* list of struct pim_neighbor */ pim_ifp->pim_neighbor_list = list_new(); if (!pim_ifp->pim_neighbor_list) { zlog_err("%s %s: failure: pim_neighbor_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free; /* list of struct pim_ifchannel */ pim_ifp->pim_ifchannel_list = list_new(); if (!pim_ifp->pim_ifchannel_list) { zlog_err("%s %s: failure: pim_ifchannel_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return if_list_clean(pim_ifp); } pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free; ifp->info = pim_ifp; pim_sock_reset(ifp); zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options)); if (PIM_MROUTE_IS_ENABLED) { pim_if_add_vif(ifp); } return pim_ifp; } void pim_if_delete(struct interface *ifp) { struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; zassert(pim_ifp); if (pim_ifp->igmp_join_list) { pim_if_igmp_join_del_all(ifp); } zassert(!pim_ifp->igmp_join_list); zassert(pim_ifp->igmp_socket_list); zassert(!listcount(pim_ifp->igmp_socket_list)); zassert(pim_ifp->pim_neighbor_list); zassert(!listcount(pim_ifp->pim_neighbor_list)); zassert(pim_ifp->pim_ifchannel_list); zassert(!listcount(pim_ifp->pim_ifchannel_list)); if (PIM_MROUTE_IS_ENABLED) { pim_if_del_vif(ifp); } list_delete(pim_ifp->igmp_socket_list); list_delete(pim_ifp->pim_neighbor_list); list_delete(pim_ifp->pim_ifchannel_list); XFREE(MTYPE_PIM_INTERFACE, pim_ifp); ifp->info = 0; } void pim_if_update_could_assert(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_could_assert(ch); } } static void pim_if_update_my_assert_metric(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_my_assert_metric(ch); } } static void pim_addr_change(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */ pim_if_update_join_desired(pim_ifp); /* depends on DR */ pim_if_update_could_assert(ifp); /* depends on DR */ pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */ /* RFC 4601: 4.3.1. Sending Hello Messages 1) Before an interface goes down or changes primary IP address, a Hello message with a zero HoldTime should be sent immediately (with the old IP address if the IP address changed). -- FIXME See CAVEAT C13 2) After an interface has changed its IP address, it MUST send a Hello message with its new IP address. -- DONE below 3) If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. -- FIXME See TODO T31 */ pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */ if (pim_ifp->pim_sock_fd < 0) return; pim_hello_restart_now(ifp); /* send hello and restart timer */ } static void on_primary_address_change(struct interface *ifp, const char *caller, struct in_addr old_addr, struct in_addr new_addr) { struct pim_interface *pim_ifp; { char old_str[100]; char new_str[100]; pim_inet4_dump("", old_addr, old_str, sizeof(old_str)); pim_inet4_dump("", new_addr, new_str, sizeof(new_str)); zlog_info("%s: %s: primary address changed from %s to %s on interface %s", __PRETTY_FUNCTION__, caller, old_str, new_str, ifp->name); } pim_ifp = ifp->info; if (!pim_ifp) { return; } if (!PIM_IF_TEST_PIM(pim_ifp->options)) { return; } pim_addr_change(ifp); } static int detect_primary_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { struct pim_interface *pim_ifp; struct in_addr new_prim_addr; int changed; pim_ifp = ifp->info; if (!pim_ifp) return 0; if (force_prim_as_any) new_prim_addr = qpim_inaddr_any; else new_prim_addr = pim_find_primary_addr(ifp); changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr; if (PIM_DEBUG_ZEBRA) { char new_prim_str[100]; char old_prim_str[100]; pim_inet4_dump("", new_prim_addr, new_prim_str, sizeof(new_prim_str)); pim_inet4_dump("", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str)); zlog_debug("%s: old=%s new=%s on interface %s: %s", __PRETTY_FUNCTION__, old_prim_str, new_prim_str, ifp->name, changed ? "changed" : "unchanged"); } if (changed) { struct in_addr old_addr = pim_ifp->primary_address; pim_ifp->primary_address = new_prim_addr; on_primary_address_change(ifp, caller, old_addr, new_prim_addr); } return changed; } static void detect_secondary_address_change(struct interface *ifp, const char *caller) { struct pim_interface *pim_ifp; int changed; pim_ifp = ifp->info; if (!pim_ifp) return; changed = 1; /* true */ zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change", __PRETTY_FUNCTION__, ifp->name); if (PIM_DEBUG_ZEBRA) { zlog_debug("%s: on interface %s: %s", __PRETTY_FUNCTION__, ifp->name, changed ? "changed" : "unchanged"); } if (!changed) { return; } if (!PIM_IF_TEST_PIM(pim_ifp->options)) { return; } pim_addr_change(ifp); } static void detect_address_change(struct interface *ifp, int force_prim_as_any, const char *caller) { int prim_changed; prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller); if (prim_changed) { /* no need to detect secondary change because the reaction would be the same */ return; } detect_secondary_address_change(ifp, caller); } void pim_if_addr_add(struct connected *ifc) { struct pim_interface *pim_ifp; struct interface *ifp; struct in_addr ifaddr; zassert(ifc); ifp = ifc->ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) return; if (!if_is_operative(ifp)) return; /* if (PIM_DEBUG_ZEBRA) */ { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d connected IP address %s %s", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } ifaddr = ifc->address->u.prefix4; detect_address_change(ifp, 0, __PRETTY_FUNCTION__); if (PIM_IF_TEST_IGMP(pim_ifp->options)) { struct igmp_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp); } } /* igmp */ if (PIM_IF_TEST_PIM(pim_ifp->options)) { /* Interface has a valid primary address ? */ if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { /* Interface has a valid socket ? */ if (pim_ifp->pim_sock_fd < 0) { if (pim_sock_add(ifp)) { zlog_warn("Failure creating PIM socket for interface %s", ifp->name); } } } } /* pim */ if (PIM_MROUTE_IS_ENABLED) { /* PIM or IGMP is enabled on interface, and there is at least one address assigned, then try to create a vif_index. */ if (pim_ifp->mroute_vif_index < 0) { pim_if_add_vif(ifp); } } } static void pim_if_addr_del_igmp(struct connected *ifc) { struct pim_interface *pim_ifp = ifc->ifp->info; struct igmp_sock *igmp; struct in_addr ifaddr; if (ifc->address->family != AF_INET) { /* non-IPv4 address */ return; } if (!pim_ifp) { /* IGMP not enabled on interface */ return; } ifaddr = ifc->address->u.prefix4; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); if (igmp) { /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); } } static void pim_if_addr_del_pim(struct connected *ifc) { struct pim_interface *pim_ifp = ifc->ifp->info; if (ifc->address->family != AF_INET) { /* non-IPv4 address */ return; } if (!pim_ifp) { /* PIM not enabled on interface */ return; } if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) { /* Interface keeps a valid primary address */ return; } if (pim_ifp->pim_sock_fd < 0) { /* Interface does not hold a valid socket any longer */ return; } /* pim_sock_delete() closes the socket, stops read and timer threads, and kills all neighbors. */ pim_sock_delete(ifc->ifp, "last address has been removed from interface"); } void pim_if_addr_del(struct connected *ifc, int force_prim_as_any) { struct interface *ifp; zassert(ifc); ifp = ifc->ifp; zassert(ifp); /* if (PIM_DEBUG_ZEBRA) */ { char buf[BUFSIZ]; prefix2str(ifc->address, buf, BUFSIZ); zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex, buf, CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary"); } detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__); pim_if_addr_del_igmp(ifc); pim_if_addr_del_pim(ifc); } void pim_if_addr_add_all(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_add(ifc); } } void pim_if_addr_del_all(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */); } } void pim_if_addr_del_all_igmp(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del_igmp(ifc); } } void pim_if_addr_del_all_pim(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct listnode *nextnode; /* PIM/IGMP enabled ? */ if (!ifp->info) return; for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; pim_if_addr_del_pim(ifc); } } static struct in_addr find_first_nonsec_addr(struct interface *ifp) { struct connected *ifc; struct listnode *node; struct in_addr addr; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if (PIM_INADDR_IS_ANY(p->u.prefix4)) { zlog_warn("%s: null IPv4 address connected to interface %s", __PRETTY_FUNCTION__, ifp->name); continue; } if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) continue; return p->u.prefix4; } addr.s_addr = PIM_NET_INADDR_ANY; return addr; } struct in_addr pim_find_primary_addr(struct interface *ifp) { return find_first_nonsec_addr(ifp); } /* pim_if_add_vif() uses ifindex as vif_index see also pim_if_find_vifindex_by_ifindex() */ int pim_if_add_vif(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; struct in_addr ifaddr; zassert(pim_ifp); if (pim_ifp->mroute_vif_index > 0) { zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d", __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); return -1; } if (ifp->ifindex < 1) { zlog_warn("%s: ifindex=%d < 1 on interface %s", __PRETTY_FUNCTION__, ifp->ifindex, ifp->name); return -2; } if (ifp->ifindex >= MAXVIFS) { zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s", __PRETTY_FUNCTION__, ifp->ifindex, MAXVIFS, ifp->name); return -3; } ifaddr = pim_ifp->primary_address; if (PIM_INADDR_IS_ANY(ifaddr)) { zlog_warn("%s: could not get address for interface %s ifindex=%d", __PRETTY_FUNCTION__, ifp->name, ifp->ifindex); return -4; } if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) { /* pim_mroute_add_vif reported error */ return -5; } pim_ifp->mroute_vif_index = ifp->ifindex; /* Update highest vif_index */ if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) { qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index; } return 0; } static int iflist_find_highest_vif_index() { struct listnode *ifnode; struct interface *ifp; struct pim_interface *pim_ifp; int highest_vif_index = -1; for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->mroute_vif_index > highest_vif_index) { highest_vif_index = pim_ifp->mroute_vif_index; } } return highest_vif_index; } int pim_if_del_vif(struct interface *ifp) { struct pim_interface *pim_ifp = ifp->info; int old_vif_index; if (pim_ifp->mroute_vif_index < 1) { zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d", __PRETTY_FUNCTION__, pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex); return -1; } if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) { /* pim_mroute_del_vif reported error */ return -2; } /* Update highest vif_index */ /* save old vif_index in order to compare with highest below */ old_vif_index = pim_ifp->mroute_vif_index; pim_ifp->mroute_vif_index = -1; if (old_vif_index == qpim_mroute_oif_highest_vif_index) { qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index(); } return 0; } void pim_if_add_vif_all() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (!ifp->info) continue; pim_if_add_vif(ifp); } } void pim_if_del_vif_all() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (!ifp->info) continue; pim_if_del_vif(ifp); } } struct interface *pim_if_find_by_vif_index(int vif_index) { struct listnode *ifnode; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { if (ifp->info) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; if (vif_index == pim_ifp->mroute_vif_index) return ifp; } } return 0; } /* pim_if_add_vif() uses ifindex as vif_index */ int pim_if_find_vifindex_by_ifindex(int ifindex) { return ifindex; } int pim_if_lan_delay_enabled(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0); return pim_ifp->pim_number_of_nonlandelay_neighbors == 0; } uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp) { if (pim_if_lan_delay_enabled(ifp)) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; return pim_ifp->pim_neighbors_highest_propagation_delay_msec; } else { return PIM_DEFAULT_PROPAGATION_DELAY_MSEC; } } uint16_t pim_if_effective_override_interval_msec(struct interface *ifp) { if (pim_if_lan_delay_enabled(ifp)) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; return pim_ifp->pim_neighbors_highest_override_interval_msec; } else { return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC; } } int pim_if_t_override_msec(struct interface *ifp) { int effective_override_interval_msec; int t_override_msec; effective_override_interval_msec = pim_if_effective_override_interval_msec(ifp); t_override_msec = pim_rand_next(0, effective_override_interval_msec); return t_override_msec; } uint16_t pim_if_jp_override_interval_msec(struct interface *ifp) { return pim_if_effective_propagation_delay_msec(ifp) + pim_if_effective_override_interval_msec(ifp); } /* RFC 4601: 4.1.6. State Summarization Macros The function NBR( I, A ) uses information gathered through PIM Hello messages to map the IP address A of a directly connected PIM neighbor router on interface I to the primary IP address of the same router (Section 4.3.4). The primary IP address of a neighbor is the address that it uses as the source of its PIM Hello messages. */ struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct in_addr addr) { struct listnode *neighnode; struct pim_neighbor *neigh; struct pim_interface *pim_ifp; zassert(ifp); pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return 0; } for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { /* primary address ? */ if (neigh->source_addr.s_addr == addr.s_addr) return neigh; /* secondary address ? */ if (pim_neighbor_find_secondary(neigh, addr)) return neigh; } if (PIM_DEBUG_PIM_TRACE) { char addr_str[100]; pim_inet4_dump("", addr, addr_str, sizeof(addr_str)); zlog_debug("%s: neighbor not found for address %s on interface %s", __PRETTY_FUNCTION__, addr_str, ifp->name); } return 0; } long pim_if_t_suppressed_msec(struct interface *ifp) { struct pim_interface *pim_ifp; long t_suppressed_msec; pim_ifp = ifp->info; zassert(pim_ifp); /* join suppression disabled ? */ if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)) return 0; /* t_suppressed = t_periodic * rand(1.1, 1.4) */ t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400); return t_suppressed_msec; } static void igmp_join_free(struct igmp_join *ij) { XFREE(MTYPE_PIM_IGMP_JOIN, ij); } static struct igmp_join *igmp_join_find(struct list *join_list, struct in_addr group_addr, struct in_addr source_addr) { struct listnode *node; struct igmp_join *ij; zassert(join_list); for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) { if ((group_addr.s_addr == ij->group_addr.s_addr) && (source_addr.s_addr == ij->source_addr.s_addr)) return ij; } return 0; } static int igmp_join_sock(const char *ifname, int ifindex, struct in_addr group_addr, struct in_addr source_addr) { int join_fd; join_fd = pim_socket_raw(IPPROTO_IGMP); if (join_fd < 0) { return -1; } if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) { close(join_fd); return -2; } return join_fd; } static struct igmp_join *igmp_join_new(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; int join_fd; pim_ifp = ifp->info; zassert(pim_ifp); join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr); if (join_fd < 0) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return 0; } ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij)); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, sizeof(*ij), group_str, source_str, ifp->name); close(join_fd); return 0; } ij->sock_fd = join_fd; ij->group_addr = group_addr; ij->source_addr = source_addr; ij->sock_creation = pim_time_monotonic_sec(); listnode_add(pim_ifp->igmp_join_list, ij); return ij; } int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (!pim_ifp->igmp_join_list) { pim_ifp->igmp_join_list = list_new(); if (!pim_ifp->igmp_join_list) { zlog_err("%s %s: failure: igmp_join_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return -2; } pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free; } ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); if (ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -3; } ij = igmp_join_new(ifp, group_addr, source_addr); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -4; } { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s", __PRETTY_FUNCTION__, source_str, group_str, ifp->name); } return 0; } int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return -1; } if (!pim_ifp->igmp_join_list) { zlog_warn("%s: no IGMP join on interface %s", __PRETTY_FUNCTION__, ifp->name); return -2; } ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); if (!ij) { char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: could not find IGMP group %s source %s on interface %s", __PRETTY_FUNCTION__, group_str, source_str, ifp->name); return -3; } if (close(ij->sock_fd)) { int e = errno; char group_str[100]; char source_str[100]; pim_inet4_dump("", group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", source_addr, source_str, sizeof(source_str)); zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s", __PRETTY_FUNCTION__, ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e)); /* warning only */ } listnode_delete(pim_ifp->igmp_join_list, ij); igmp_join_free(ij); if (listcount(pim_ifp->igmp_join_list) < 1) { list_delete(pim_ifp->igmp_join_list); pim_ifp->igmp_join_list = 0; } return 0; } static void pim_if_igmp_join_del_all(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *nextnode; struct igmp_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { zlog_warn("%s: multicast not enabled on interface %s", __PRETTY_FUNCTION__, ifp->name); return; } if (!pim_ifp->igmp_join_list) return; for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } /* RFC 4601 Transitions from "I am Assert Loser" State Current Winner's GenID Changes or NLT Expires The Neighbor Liveness Timer associated with the current winner expires or we receive a Hello message from the current winner reporting a different GenID from the one it previously reported. This indicates that the current winner's interface or router has gone down (and may have come back up), and so we must assume it no longer knows it was the winner. */ void pim_if_assert_on_neighbor_down(struct interface *ifp, struct in_addr neigh_addr) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; zassert(pim_ifp); for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { /* Is (S,G,I) assert loser ? */ if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER) continue; /* Dead neighbor was winner ? */ if (ch->ifassert_winner.s_addr != neigh_addr.s_addr) continue; assert_action_a5(ch); } } void pim_if_update_join_desired(struct pim_interface *pim_ifp) { struct listnode *ch_node; struct pim_ifchannel *ch; /* clear off flag from interface's upstreams */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags); } /* scan per-interface (S,G,I) state on this I interface */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { struct pim_upstream *up = ch->upstream; if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags)) continue; /* update join_desired for the global (S,G) state */ pim_upstream_update_join_desired(up); PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags); } } void pim_if_update_assert_tracking_desired(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *node; struct listnode *next_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) return; for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) { pim_ifchannel_update_assert_tracking_desired(ch); } } quagga-0.99.24.1/pimd/pim_signals.c0000644000175000017500000000334512476520570013643 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include "sigevent.h" #include "memory.h" #include "log.h" #include "pim_signals.h" #include "pimd.h" /* * Signal handlers */ static void pim_sighup() { zlog_debug ("SIGHUP received, ignoring"); } static void pim_sigint() { zlog_notice("Terminating on signal SIGINT"); pim_terminate(); exit(1); } static void pim_sigterm() { zlog_notice("Terminating on signal SIGTERM"); pim_terminate(); exit(1); } static void pim_sigusr1() { zlog_debug ("SIGUSR1 received"); zlog_rotate (NULL); } static struct quagga_signal_t pimd_signals[] = { { .signal = SIGHUP, .handler = &pim_sighup, }, { .signal = SIGUSR1, .handler = &pim_sigusr1, }, { .signal = SIGINT, .handler = &pim_sigint, }, { .signal = SIGTERM, .handler = &pim_sigterm, }, }; void pim_signals_init() { signal_init(master, array_size(pimd_signals), pimd_signals); } quagga-0.99.24.1/pimd/pim_cmd.c0000644000175000017500000035752212476520570012757 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include #include "command.h" #include "if.h" #include "prefix.h" #include "zclient.h" #include "pimd.h" #include "pim_cmd.h" #include "pim_iface.h" #include "pim_vty.h" #include "pim_mroute.h" #include "pim_str.h" #include "pim_igmp.h" #include "pim_igmpv3.h" #include "pim_sock.h" #include "pim_time.h" #include "pim_util.h" #include "pim_oil.h" #include "pim_neighbor.h" #include "pim_pim.h" #include "pim_ifchannel.h" #include "pim_hello.h" #include "pim_msg.h" #include "pim_upstream.h" #include "pim_rpf.h" #include "pim_macro.h" #include "pim_ssmpingd.h" #include "pim_zebra.h" static struct cmd_node pim_global_node = { PIM_NODE, "", 1 /* vtysh ? yes */ }; static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */ }; static void pim_if_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; pim_ifp = ifp->info; zassert(pim_ifp); if (PIM_IF_TEST_PIM(pim_ifp->options) && PIM_IF_TEST_IGMP(pim_ifp->options)) { return; } pim_ifchannel_membership_clear(ifp); } /* When PIM is disabled on interface, IGMPv3 local membership information is not injected into PIM interface state. The function pim_if_membership_refresh() fetches all IGMPv3 local membership information into PIM. It is intented to be called whenever PIM is enabled on the interface in order to collect missed local membership information. */ static void pim_if_membership_refresh(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp = ifp->info; zassert(pim_ifp); if (!PIM_IF_TEST_PIM(pim_ifp->options)) return; if (!PIM_IF_TEST_IGMP(pim_ifp->options)) return; /* First clear off membership from all PIM (S,G) entries on the interface */ pim_ifchannel_membership_clear(ifp); /* Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on the interface */ /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { struct listnode *grpnode; struct igmp_group *grp; /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { struct listnode *srcnode; struct igmp_source *src; /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) { pim_ifchannel_local_membership_add(ifp, src->source_addr, grp->group_addr); } } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ /* Finally delete every PIM (S,G) entry lacking all state info */ pim_ifchannel_delete_on_noinfo(ifp); } static void pim_show_assert(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group State Winner Uptime Timer%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char winner_str[100]; char uptime[10]; char timer[10]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", ch->ifassert_winner, winner_str, sizeof(winner_str)); pim_time_uptime(uptime, sizeof(uptime), now - ch->ifassert_creation); pim_time_timer_to_mmss(timer, sizeof(timer), ch->t_ifassert_timer); vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %-15s %-8s %-5s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifassert_name(ch->ifassert_state), winner_str, uptime, timer, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_internal(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "CA: CouldAssert%s" "ECA: Evaluate CouldAssert%s" "ATD: AssertTrackingDesired%s" "eATD: Evaluate AssertTrackingDesired%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address Source Group CA eCA ATD eATD%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-3s %-3s %-4s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags) ? "yes" : "no", pim_macro_ch_could_assert_eval(ch) ? "yes" : "no", PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(ch->flags) ? "yes" : "no", pim_macro_assert_tracking_desired_eval(ch) ? "yes" : "no", VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_metric(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char addr_str[100]; struct pim_assert_metric am; am = pim_macro_spt_assert_metric(&ch->upstream->rpf, pim_ifp->primary_address); pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am.ip_address, addr_str, sizeof(addr_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %4u %6u %-15s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am.rpt_bit_flag ? "yes" : "no", am.metric_preference, am.route_metric, addr_str, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_assert_winner_metric(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group RPT Pref Metric Address %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char addr_str[100]; struct pim_assert_metric *am; char pref_str[5]; char metr_str[7]; am = &ch->ifassert_winner_metric; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_inet4_dump("", am->ip_address, addr_str, sizeof(addr_str)); if (am->metric_preference == PIM_ASSERT_METRIC_PREFERENCE_MAX) snprintf(pref_str, sizeof(pref_str), "INFI"); else snprintf(pref_str, sizeof(pref_str), "%4u", am->metric_preference); if (am->route_metric == PIM_ASSERT_ROUTE_METRIC_MAX) snprintf(metr_str, sizeof(metr_str), "INFI"); else snprintf(metr_str, sizeof(metr_str), "%6u", am->route_metric); vty_out(vty, "%-9s %-15s %-15s %-15s %-3s %-4s %-6s %-15s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, am->rpt_bit_flag ? "yes" : "no", pref_str, metr_str, addr_str, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_membership(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Source Group Membership%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %-10s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO ? "NOINFO" : "INCLUDE", VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void igmp_show_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp = ifp->info; if (!pim_ifp) continue; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char uptime[10]; int mloop; pim_time_uptime(uptime, sizeof(uptime), now - igmp->sock_creation); mloop = pim_socket_mcastloop_get(igmp->fd); vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", ifp->name, inet_ntoa(igmp->ifaddr), ifp->ifindex, igmp->fd, uptime, if_is_multicast(ifp) ? "yes" : "no", if_is_broadcast(ifp) ? "yes" : "no", (mloop < 0) ? "?" : (mloop ? "yes" : "no"), (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", (ifp->flags & IFF_PROMISC) ? "yes" : "no", PIM_IF_IS_DELETED(ifp) ? "yes" : "no", VTY_NEWLINE); } } } static void igmp_show_interface_join(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group Socket Uptime %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct listnode *join_node; struct igmp_join *ij; struct in_addr pri_addr; char pri_addr_str[100]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (!pim_ifp->igmp_join_list) continue; pri_addr = pim_find_primary_addr(ifp); pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node, ij)) { char group_str[100]; char source_str[100]; char uptime[10]; pim_time_uptime(uptime, sizeof(uptime), now - ij->sock_creation); pim_inet4_dump("", ij->group_addr, group_str, sizeof(group_str)); pim_inet4_dump("", ij->source_addr, source_str, sizeof(source_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %6d %8s%s", ifp->name, pri_addr_str, source_str, group_str, ij->sock_fd, uptime, VTY_NEWLINE); } /* for (pim_ifp->igmp_join_list) */ } /* for (iflist) */ } static void show_interface_address(struct vty *vty) { struct listnode *ifpnode; struct interface *ifp; vty_out(vty, "Interface Primary Secondary %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifpnode, ifp)) { struct listnode *ifcnode; struct connected *ifc; struct in_addr pri_addr; char pri_addr_str[100]; pri_addr = pim_find_primary_addr(ifp); pim_inet4_dump("", pri_addr, pri_addr_str, sizeof(pri_addr_str)); for (ALL_LIST_ELEMENTS_RO(ifp->connected, ifcnode, ifc)) { char sec_addr_str[100]; struct prefix *p = ifc->address; if (p->family != AF_INET) continue; if (p->u.prefix4.s_addr == pri_addr.s_addr) { sec_addr_str[0] = '\0'; } else { pim_inet4_dump("", p->u.prefix4, sec_addr_str, sizeof(sec_addr_str)); } vty_out(vty, "%-9s %-15s %-15s%s", ifp->name, pri_addr_str, sec_addr_str, VTY_NEWLINE); } } } static void pim_show_dr(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "NonPri: Number of neighbors missing DR Priority hello option%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address DR Uptime Elections Changes NonPri%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char dr_str[100]; char dr_uptime[10]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_uptime_begin(dr_uptime, sizeof(dr_uptime), now, pim_ifp->pim_dr_election_last); pim_inet4_dump("", pim_ifp->pim_dr_addr, dr_str, sizeof(dr_str)); vty_out(vty, "%-9s %-15s %-15s %8s %9d %7d %6d%s", ifp->name, inet_ntoa(ifaddr), dr_str, dr_uptime, pim_ifp->pim_dr_election_count, pim_ifp->pim_dr_election_changes, pim_ifp->pim_dr_num_nondrpri_neighbors, VTY_NEWLINE); } } static void pim_show_hello(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Period Timer StatStart Recv Rfail Send Sfail%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char hello_period[10]; char hello_timer[10]; char stat_uptime[10]; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_timer_to_mmss(hello_timer, sizeof(hello_timer), pim_ifp->t_pim_hello_timer); pim_time_mmss(hello_period, sizeof(hello_period), pim_ifp->pim_hello_period); pim_time_uptime(stat_uptime, sizeof(stat_uptime), now - pim_ifp->pim_ifstat_start); vty_out(vty, "%-9s %-15s %6s %5s %9s %4u %5u %4u %5u%s", ifp->name, inet_ntoa(ifaddr), hello_period, hello_timer, stat_uptime, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_recvfail, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_hello_sendfail, VTY_NEWLINE); } } static void pim_show_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address ifIndex Socket Uptime Multi Broad MLoop AllMu Prmsc Del%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; char uptime[10]; int mloop; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; pim_time_uptime(uptime, sizeof(uptime), now - pim_ifp->pim_sock_creation); mloop = pim_socket_mcastloop_get(pim_ifp->pim_sock_fd); vty_out(vty, "%-9s %-15s %7d %6d %8s %5s %5s %5s %5s %5s %3s%s", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->pim_sock_fd, uptime, if_is_multicast(ifp) ? "yes" : "no", if_is_broadcast(ifp) ? "yes" : "no", (mloop < 0) ? "?" : (mloop ? "yes" : "no"), (ifp->flags & IFF_ALLMULTI) ? "yes" : "no", (ifp->flags & IFF_PROMISC) ? "yes" : "no", PIM_IF_IS_DELETED(ifp) ? "yes" : "no", VTY_NEWLINE); } } static void pim_show_join(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Source Group State Uptime Expire Prune%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *ch_node; struct pim_ifchannel *ch; pim_ifp = ifp->info; if (!pim_ifp) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) { char ch_src_str[100]; char ch_grp_str[100]; char uptime[10]; char expire[10]; char prune[10]; pim_inet4_dump("", ch->source_addr, ch_src_str, sizeof(ch_src_str)); pim_inet4_dump("", ch->group_addr, ch_grp_str, sizeof(ch_grp_str)); pim_time_uptime_begin(uptime, sizeof(uptime), now, ch->ifjoin_creation); pim_time_timer_to_mmss(expire, sizeof(expire), ch->t_ifjoin_expiry_timer); pim_time_timer_to_mmss(prune, sizeof(prune), ch->t_ifjoin_prune_pending_timer); vty_out(vty, "%-9s %-15s %-15s %-15s %-6s %8s %-6s %5s%s", ifp->name, inet_ntoa(ifaddr), ch_src_str, ch_grp_str, pim_ifchannel_ifjoin_name(ch->ifjoin_state), uptime, expire, prune, VTY_NEWLINE); } /* scan interface channels */ } /* scan interfaces */ } static void pim_show_neighbors(struct vty *vty) { struct listnode *node; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Recv flags: H=holdtime L=lan_prune_delay P=dr_priority G=generation_id A=address_list%s" " T=can_disable_join_suppression%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address Neighbor Uptime Timer Holdt DrPri GenId Recv %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char uptime[10]; char holdtime[10]; char expire[10]; char neigh_src_str[100]; char recv[7]; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); pim_time_uptime(uptime, sizeof(uptime), now - neigh->creation); pim_time_mmss(holdtime, sizeof(holdtime), neigh->holdtime); pim_time_timer_to_mmss(expire, sizeof(expire), neigh->t_expire_timer); recv[0] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_HOLDTIME) ? 'H' : ' '; recv[1] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? 'L' : ' '; recv[2] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY) ? 'P' : ' '; recv[3] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_GENERATION_ID) ? 'G' : ' '; recv[4] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_ADDRESS_LIST) ? 'A' : ' '; recv[5] = PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION) ? 'T' : ' '; recv[6] = '\0'; vty_out(vty, "%-9s %-15s %-15s %8s %5s %5s %5u %08x %6s%s", ifp->name, inet_ntoa(ifaddr), neigh_src_str, uptime, expire, holdtime, neigh->dr_priority, neigh->generation_id, recv, VTY_NEWLINE); } } } static void pim_show_lan_prune_delay(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "PrDly=propagation_delay (msec) OvInt=override_interval (msec)%s" "HiDly=highest_propagation_delay (msec) HiInt=highest_override_interval (msec)%s" "NoDly=number_of_non_lan_delay_neighbors%s" "T=t_bit LPD=lan_prune_delay_hello_option%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address PrDly OvInt NoDly HiDly HiInt T | Neighbor LPD PrDly OvInt T%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char neigh_src_str[100]; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); vty_out(vty, "%-9s %-15s %5u %5u %5u %5u %5u %1u | %-15s %-3s %5u %5u %1u%s", ifp->name, inet_ntoa(ifaddr), pim_ifp->pim_propagation_delay_msec, pim_ifp->pim_override_interval_msec, pim_ifp->pim_number_of_nonlandelay_neighbors, pim_ifp->pim_neighbors_highest_propagation_delay_msec, pim_ifp->pim_neighbors_highest_override_interval_msec, PIM_FORCE_BOOLEAN(PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options)), neigh_src_str, PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY) ? "yes" : "no", neigh->propagation_delay_msec, neigh->override_interval_msec, PIM_FORCE_BOOLEAN(PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION)), VTY_NEWLINE); } } } static void pim_show_jp_override_interval(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "EffPDelay=effective_propagation_delay (msec)%s" "EffOvrInt=override_interval (msec)%s" "JPOvrInt=jp_override_interval (msec)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address LAN_Delay EffPDelay EffOvrInt JPOvrInt%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; vty_out(vty, "%-9s %-15s %-9s %9u %9u %8u%s", ifp->name, inet_ntoa(ifaddr), pim_if_lan_delay_enabled(ifp) ? "enabled" : "disabled", pim_if_effective_propagation_delay_msec(ifp), pim_if_effective_override_interval_msec(ifp), pim_if_jp_override_interval_msec(ifp), VTY_NEWLINE); } } static void pim_show_neighbors_secondary(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "Interface Address Neighbor Secondary %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct listnode *neighnode; struct pim_neighbor *neigh; pim_ifp = ifp->info; if (!pim_ifp) continue; if (pim_ifp->pim_sock_fd < 0) continue; ifaddr = pim_ifp->primary_address; for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) { char neigh_src_str[100]; struct listnode *prefix_node; struct prefix *p; if (!neigh->prefix_list) continue; pim_inet4_dump("", neigh->source_addr, neigh_src_str, sizeof(neigh_src_str)); for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) { char neigh_sec_str[100]; if (p->family != AF_INET) continue; pim_inet4_dump("", p->u.prefix4, neigh_sec_str, sizeof(neigh_sec_str)); vty_out(vty, "%-9s %-15s %-15s %-15s%s", ifp->name, inet_ntoa(ifaddr), neigh_src_str, neigh_sec_str, VTY_NEWLINE); } } } } static void pim_show_upstream(struct vty *vty) { struct listnode *upnode; struct pim_upstream *up; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Source Group State Uptime JoinTimer RefCnt%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { char src_str[100]; char grp_str[100]; char uptime[10]; char join_timer[10]; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_time_uptime(uptime, sizeof(uptime), now - up->state_transition); pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), up->t_join_timer); vty_out(vty, "%-15s %-15s %-5s %-8s %-9s %6d%s", src_str, grp_str, up->join_state == PIM_UPSTREAM_JOINED ? "Jnd" : "NtJnd", uptime, join_timer, up->ref_count, VTY_NEWLINE); } } static void pim_show_join_desired(struct vty *vty) { struct listnode *ifnode; struct listnode *chnode; struct interface *ifp; struct pim_interface *pim_ifp; struct pim_ifchannel *ch; char src_str[100]; char grp_str[100]; vty_out(vty, "Interface Source Group LostAssert Joins PimInclude JoinDesired EvalJD%s", VTY_NEWLINE); /* scan all interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { pim_ifp = ifp->info; if (!pim_ifp) continue; /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, chnode, ch)) { struct pim_upstream *up = ch->upstream; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); vty_out(vty, "%-9s %-15s %-15s %-10s %-5s %-10s %-11s %-6s%s", ifp->name, src_str, grp_str, pim_macro_ch_lost_assert(ch) ? "yes" : "no", pim_macro_chisin_joins(ch) ? "yes" : "no", pim_macro_chisin_pim_include(ch) ? "yes" : "no", PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(up->flags) ? "yes" : "no", pim_upstream_evaluate_join_desired(up) ? "yes" : "no", VTY_NEWLINE); } } } static void pim_show_upstream_rpf(struct vty *vty) { struct listnode *upnode; struct pim_upstream *up; vty_out(vty, "Source Group RpfIface RibNextHop RpfAddress %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, upnode, up)) { char src_str[100]; char grp_str[100]; char rpf_nexthop_str[100]; char rpf_addr_str[100]; struct pim_rpf *rpf; const char *rpf_ifname; rpf = &up->rpf; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rpf_nexthop_str, sizeof(rpf_nexthop_str)); pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; vty_out(vty, "%-15s %-15s %-8s %-15s %-15s%s", src_str, grp_str, rpf_ifname, rpf_nexthop_str, rpf_addr_str, VTY_NEWLINE); } } static void show_rpf_refresh_stats(struct vty *vty, time_t now) { char refresh_uptime[10]; pim_time_uptime_begin(refresh_uptime, sizeof(refresh_uptime), now, qpim_rpf_cache_refresh_last); vty_out(vty, "RPF Cache Refresh Delay: %ld msecs%s" "RPF Cache Refresh Timer: %ld msecs%s" "RPF Cache Refresh Requests: %lld%s" "RPF Cache Refresh Events: %lld%s" "RPF Cache Refresh Last: %s%s", qpim_rpf_cache_refresh_delay_msec, VTY_NEWLINE, pim_time_timer_remain_msec(qpim_rpf_cache_refresher), VTY_NEWLINE, (long long)qpim_rpf_cache_refresh_requests, VTY_NEWLINE, (long long)qpim_rpf_cache_refresh_events, VTY_NEWLINE, refresh_uptime, VTY_NEWLINE); } static void show_scan_oil_stats(struct vty *vty, time_t now) { char uptime_scan_oil[10]; char uptime_mroute_add[10]; char uptime_mroute_del[10]; pim_time_uptime_begin(uptime_scan_oil, sizeof(uptime_scan_oil), now, qpim_scan_oil_last); pim_time_uptime_begin(uptime_mroute_add, sizeof(uptime_mroute_add), now, qpim_mroute_add_last); pim_time_uptime_begin(uptime_mroute_del, sizeof(uptime_mroute_del), now, qpim_mroute_del_last); vty_out(vty, "Scan OIL - Last: %s Events: %lld%s" "MFC Add - Last: %s Events: %lld%s" "MFC Del - Last: %s Events: %lld%s", uptime_scan_oil, (long long) qpim_scan_oil_events, VTY_NEWLINE, uptime_mroute_add, (long long) qpim_mroute_add_events, VTY_NEWLINE, uptime_mroute_del, (long long) qpim_mroute_del_events, VTY_NEWLINE); } static void pim_show_rpf(struct vty *vty) { struct listnode *up_node; struct pim_upstream *up; time_t now = pim_time_monotonic_sec(); show_rpf_refresh_stats(vty, now); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Source Group RpfIface RpfAddress RibNextHop Metric Pref%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_upstream_list, up_node, up)) { char src_str[100]; char grp_str[100]; char rpf_addr_str[100]; char rib_nexthop_str[100]; const char *rpf_ifname; struct pim_rpf *rpf = &up->rpf; pim_inet4_dump("", up->source_addr, src_str, sizeof(src_str)); pim_inet4_dump("", up->group_addr, grp_str, sizeof(grp_str)); pim_inet4_dump("", rpf->rpf_addr, rpf_addr_str, sizeof(rpf_addr_str)); pim_inet4_dump("", rpf->source_nexthop.mrib_nexthop_addr, rib_nexthop_str, sizeof(rib_nexthop_str)); rpf_ifname = rpf->source_nexthop.interface ? rpf->source_nexthop.interface->name : ""; vty_out(vty, "%-15s %-15s %-8s %-15s %-15s %6d %4d%s", src_str, grp_str, rpf_ifname, rpf_addr_str, rib_nexthop_str, rpf->source_nexthop.mrib_route_metric, rpf->source_nexthop.mrib_metric_preference, VTY_NEWLINE); } } static void igmp_show_querier(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "Interface Address Querier StartCount Query-Timer Other-Timer%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char query_hhmmss[10]; char other_hhmmss[10]; pim_time_timer_to_hhmmss(query_hhmmss, sizeof(query_hhmmss), igmp->t_igmp_query_timer); pim_time_timer_to_hhmmss(other_hhmmss, sizeof(other_hhmmss), igmp->t_other_querier_timer); vty_out(vty, "%-9s %-15s %-7s %10d %11s %11s%s", ifp->name, inet_ntoa(igmp->ifaddr), igmp->t_igmp_query_timer ? "THIS" : "OTHER", igmp->startup_query_count, query_hhmmss, other_hhmmss, VTY_NEWLINE); } } } static void igmp_show_groups(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group Mode Timer Srcs V Uptime %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; char hhmmss[10]; char uptime[10]; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss), grp->t_group_timer); pim_time_uptime(uptime, sizeof(uptime), now - grp->group_creation); vty_out(vty, "%-9s %-15s %-15s %4s %8s %4d %d %8s%s", ifp->name, ifaddr_str, group_str, grp->group_filtermode_isexcl ? "EXCL" : "INCL", hhmmss, grp->group_source_list ? listcount(grp->group_source_list) : 0, igmp_group_compat_mode(igmp, grp), uptime, VTY_NEWLINE); } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_group_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Group RetTimer Counter RetSrcs%s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; char grp_retr_mmss[10]; struct listnode *src_node; struct igmp_source *src; int grp_retr_sources = 0; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); pim_time_timer_to_mmss(grp_retr_mmss, sizeof(grp_retr_mmss), grp->t_group_query_retransmit_timer); /* count group sources with retransmission state */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { if (src->source_query_retransmit_count > 0) { ++grp_retr_sources; } } vty_out(vty, "%-9s %-15s %-15s %-8s %7d %7d%s", ifp->name, ifaddr_str, group_str, grp_retr_mmss, grp->group_specific_query_retransmit_count, grp_retr_sources, VTY_NEWLINE); } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_parameters(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "QRV: Robustness Variable SQI: Startup Query Interval%s" "QQI: Query Interval OQPI: Other Querier Present Interval%s" "QRI: Query Response Interval LMQT: Last Member Query Time%s" "GMI: Group Membership Interval OHPI: Older Host Present Interval%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Interface Address QRV QQI QRI GMI SQI OQPI LMQT OHPI %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; long gmi_dsec; /* Group Membership Interval */ long oqpi_dsec; /* Other Querier Present Interval */ int sqi; long lmqt_dsec; long ohpi_dsec; long qri_dsec; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); gmi_dsec = PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec) / 100; sqi = PIM_IGMP_SQI(pim_ifp->igmp_default_query_interval); oqpi_dsec = PIM_IGMP_OQPI_MSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec) / 100; lmqt_dsec = PIM_IGMP_LMQT_MSEC(pim_ifp->igmp_query_max_response_time_dsec, igmp->querier_robustness_variable) / 100; ohpi_dsec = PIM_IGMP_OHPI_DSEC(igmp->querier_robustness_variable, igmp->querier_query_interval, pim_ifp->igmp_query_max_response_time_dsec); qri_dsec = pim_ifp->igmp_query_max_response_time_dsec; vty_out(vty, "%-9s %-15s %3d %3d %3ld.%ld %3ld.%ld %3d %3ld.%ld %3ld.%ld %3ld.%ld%s", ifp->name, ifaddr_str, igmp->querier_robustness_variable, igmp->querier_query_interval, qri_dsec / 10, qri_dsec % 10, gmi_dsec / 10, gmi_dsec % 10, sqi, oqpi_dsec / 10, oqpi_dsec % 10, lmqt_dsec / 10, lmqt_dsec % 10, ohpi_dsec / 10, ohpi_dsec % 10, VTY_NEWLINE); } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_sources(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; time_t now; now = pim_time_monotonic_sec(); vty_out(vty, "Interface Address Group Source Timer Fwd Uptime %s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; struct listnode *srcnode; struct igmp_source *src; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { char source_str[100]; char mmss[10]; char uptime[10]; pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); pim_time_timer_to_mmss(mmss, sizeof(mmss), src->t_source_timer); pim_time_uptime(uptime, sizeof(uptime), now - src->source_creation); vty_out(vty, "%-9s %-15s %-15s %-15s %5s %3s %8s%s", ifp->name, ifaddr_str, group_str, source_str, mmss, IGMP_SOURCE_TEST_FORWARDING(src->source_flags) ? "Y" : "N", uptime, VTY_NEWLINE); } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void igmp_show_source_retransmission(struct vty *vty) { struct listnode *ifnode; struct interface *ifp; vty_out(vty, "Interface Address Group Source Counter%s", VTY_NEWLINE); /* scan interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node; struct igmp_sock *igmp; if (!pim_ifp) continue; /* scan igmp sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { char ifaddr_str[100]; struct listnode *grpnode; struct igmp_group *grp; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode, grp)) { char group_str[100]; struct listnode *srcnode; struct igmp_source *src; pim_inet4_dump("", grp->group_addr, group_str, sizeof(group_str)); /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { char source_str[100]; pim_inet4_dump("", src->source_addr, source_str, sizeof(source_str)); vty_out(vty, "%-9s %-15s %-15s %-15s %7d%s", ifp->name, ifaddr_str, group_str, source_str, src->source_query_retransmit_count, VTY_NEWLINE); } /* scan group sources */ } /* scan igmp groups */ } /* scan igmp sockets */ } /* scan interfaces */ } static void clear_igmp_interfaces() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_if_addr_del_all_igmp(ifp); } for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { pim_if_addr_add_all(ifp); } } static void clear_pim_interfaces() { struct listnode *ifnode; struct listnode *ifnextnode; struct interface *ifp; for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) { if (ifp->info) { pim_neighbor_delete_all(ifp, "interface cleared"); } } } static void clear_interfaces() { clear_igmp_interfaces(); clear_pim_interfaces(); } DEFUN (pim_interface, pim_interface_cmd, "interface IFNAME", "Select an interface to configure\n" "Interface's name\n") { struct interface *ifp; const char *ifname = argv[0]; size_t sl; sl = strlen(ifname); if (sl > INTERFACE_NAMSIZ) { vty_out(vty, "%% Interface name %s is invalid: length exceeds " "%d characters%s", ifname, INTERFACE_NAMSIZ, VTY_NEWLINE); return CMD_WARNING; } ifp = if_lookup_by_name_len(ifname, sl); if (!ifp) { vty_out(vty, "%% Interface %s does not exist%s", ifname, VTY_NEWLINE); /* Returning here would prevent pimd from booting when there are interface commands in pimd.conf, since all interfaces are unknown at pimd boot time (the zebra daemon has not been contacted for interface discovery). */ ifp = if_get_by_name_len(ifname, sl); if (!ifp) { vty_out(vty, "%% Could not create interface %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } } vty->index = ifp; vty->node = INTERFACE_NODE; return CMD_SUCCESS; } DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, "clear ip interfaces", CLEAR_STR IP_STR "Reset interfaces\n") { clear_interfaces(); return CMD_SUCCESS; } DEFUN (clear_ip_igmp_interfaces, clear_ip_igmp_interfaces_cmd, "clear ip igmp interfaces", CLEAR_STR IP_STR CLEAR_IP_IGMP_STR "Reset IGMP interfaces\n") { clear_igmp_interfaces(); return CMD_SUCCESS; } static void mroute_add_all() { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if (pim_mroute_add(&c_oil->oil)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } static void mroute_del_all() { struct listnode *node; struct channel_oil *c_oil; for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { if (pim_mroute_del(&c_oil->oil)) { /* just log warning */ char source_str[100]; char group_str[100]; pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC", __FILE__, __PRETTY_FUNCTION__, source_str, group_str); } } } DEFUN (clear_ip_mroute, clear_ip_mroute_cmd, "clear ip mroute", CLEAR_STR IP_STR "Reset multicast routes\n") { mroute_del_all(); mroute_add_all(); return CMD_SUCCESS; } DEFUN (clear_ip_pim_interfaces, clear_ip_pim_interfaces_cmd, "clear ip pim interfaces", CLEAR_STR IP_STR CLEAR_IP_PIM_STR "Reset PIM interfaces\n") { clear_pim_interfaces(); return CMD_SUCCESS; } DEFUN (clear_ip_pim_oil, clear_ip_pim_oil_cmd, "clear ip pim oil", CLEAR_STR IP_STR CLEAR_IP_PIM_STR "Rescan PIM OIL (output interface list)\n") { pim_scan_oil(); return CMD_SUCCESS; } DEFUN (show_ip_igmp_interface, show_ip_igmp_interface_cmd, "show ip igmp interface", SHOW_STR IP_STR IGMP_STR "IGMP interface information\n") { igmp_show_interfaces(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_join, show_ip_igmp_join_cmd, "show ip igmp join", SHOW_STR IP_STR IGMP_STR "IGMP static join information\n") { igmp_show_interface_join(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups, show_ip_igmp_groups_cmd, "show ip igmp groups", SHOW_STR IP_STR IGMP_STR IGMP_GROUP_STR) { igmp_show_groups(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_groups_retransmissions, show_ip_igmp_groups_retransmissions_cmd, "show ip igmp groups retransmissions", SHOW_STR IP_STR IGMP_STR IGMP_GROUP_STR "IGMP group retransmissions\n") { igmp_show_group_retransmission(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_parameters, show_ip_igmp_parameters_cmd, "show ip igmp parameters", SHOW_STR IP_STR IGMP_STR "IGMP parameters information\n") { igmp_show_parameters(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources, show_ip_igmp_sources_cmd, "show ip igmp sources", SHOW_STR IP_STR IGMP_STR IGMP_SOURCE_STR) { igmp_show_sources(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_sources_retransmissions, show_ip_igmp_sources_retransmissions_cmd, "show ip igmp sources retransmissions", SHOW_STR IP_STR IGMP_STR IGMP_SOURCE_STR "IGMP source retransmissions\n") { igmp_show_source_retransmission(vty); return CMD_SUCCESS; } DEFUN (show_ip_igmp_querier, show_ip_igmp_querier_cmd, "show ip igmp querier", SHOW_STR IP_STR IGMP_STR "IGMP querier information\n") { igmp_show_querier(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_address, show_ip_pim_address_cmd, "show ip pim address", SHOW_STR IP_STR PIM_STR "PIM interface address\n") { show_interface_address(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert, show_ip_pim_assert_cmd, "show ip pim assert", SHOW_STR IP_STR PIM_STR "PIM interface assert\n") { pim_show_assert(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_internal, show_ip_pim_assert_internal_cmd, "show ip pim assert-internal", SHOW_STR IP_STR PIM_STR "PIM interface internal assert state\n") { pim_show_assert_internal(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_metric, show_ip_pim_assert_metric_cmd, "show ip pim assert-metric", SHOW_STR IP_STR PIM_STR "PIM interface assert metric\n") { pim_show_assert_metric(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_assert_winner_metric, show_ip_pim_assert_winner_metric_cmd, "show ip pim assert-winner-metric", SHOW_STR IP_STR PIM_STR "PIM interface assert winner metric\n") { pim_show_assert_winner_metric(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_dr, show_ip_pim_dr_cmd, "show ip pim designated-router", SHOW_STR IP_STR PIM_STR "PIM interface designated router\n") { pim_show_dr(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_hello, show_ip_pim_hello_cmd, "show ip pim hello", SHOW_STR IP_STR PIM_STR "PIM interface hello information\n") { pim_show_hello(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_interface, show_ip_pim_interface_cmd, "show ip pim interface", SHOW_STR IP_STR PIM_STR "PIM interface information\n") { pim_show_interfaces(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_join, show_ip_pim_join_cmd, "show ip pim join", SHOW_STR IP_STR PIM_STR "PIM interface join information\n") { pim_show_join(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_lan_prune_delay, show_ip_pim_lan_prune_delay_cmd, "show ip pim lan-prune-delay", SHOW_STR IP_STR PIM_STR "PIM neighbors LAN prune delay parameters\n") { pim_show_lan_prune_delay(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_local_membership, show_ip_pim_local_membership_cmd, "show ip pim local-membership", SHOW_STR IP_STR PIM_STR "PIM interface local-membership\n") { pim_show_membership(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_jp_override_interval, show_ip_pim_jp_override_interval_cmd, "show ip pim jp-override-interval", SHOW_STR IP_STR PIM_STR "PIM interface J/P override interval\n") { pim_show_jp_override_interval(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_neighbor, show_ip_pim_neighbor_cmd, "show ip pim neighbor", SHOW_STR IP_STR PIM_STR "PIM neighbor information\n") { pim_show_neighbors(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_secondary, show_ip_pim_secondary_cmd, "show ip pim secondary", SHOW_STR IP_STR PIM_STR "PIM neighbor addresses\n") { pim_show_neighbors_secondary(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream, show_ip_pim_upstream_cmd, "show ip pim upstream", SHOW_STR IP_STR PIM_STR "PIM upstream information\n") { pim_show_upstream(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_join_desired, show_ip_pim_upstream_join_desired_cmd, "show ip pim upstream-join-desired", SHOW_STR IP_STR PIM_STR "PIM upstream join-desired\n") { pim_show_join_desired(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_upstream_rpf, show_ip_pim_upstream_rpf_cmd, "show ip pim upstream-rpf", SHOW_STR IP_STR PIM_STR "PIM upstream source rpf\n") { pim_show_upstream_rpf(vty); return CMD_SUCCESS; } DEFUN (show_ip_pim_rpf, show_ip_pim_rpf_cmd, "show ip pim rpf", SHOW_STR IP_STR PIM_STR "PIM cached source rpf information\n") { pim_show_rpf(vty); return CMD_SUCCESS; } static void show_multicast_interfaces(struct vty *vty) { struct listnode *node; struct interface *ifp; vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) { struct pim_interface *pim_ifp; struct in_addr ifaddr; struct sioc_vif_req vreq; pim_ifp = ifp->info; if (!pim_ifp) continue; memset(&vreq, 0, sizeof(vreq)); vreq.vifi = pim_ifp->mroute_vif_index; if (ioctl(qpim_mroute_socket_fd, SIOCGETVIFCNT, &vreq)) { int e = errno; vty_out(vty, "ioctl(SIOCGETVIFCNT=%d) failure for interface %s vif_index=%d: errno=%d: %s%s", SIOCGETVIFCNT, ifp->name, pim_ifp->mroute_vif_index, e, safe_strerror(e), VTY_NEWLINE); continue; } ifaddr = pim_ifp->primary_address; vty_out(vty, "%-9s %-15s %3d %3d %7lu %7lu %10lu %10lu%s", ifp->name, inet_ntoa(ifaddr), ifp->ifindex, pim_ifp->mroute_vif_index, vreq.icount, vreq.ocount, vreq.ibytes, vreq.obytes, VTY_NEWLINE); } } DEFUN (show_ip_multicast, show_ip_multicast_cmd, "show ip multicast", SHOW_STR IP_STR "Multicast global information\n") { time_t now = pim_time_monotonic_sec(); if (PIM_MROUTE_IS_ENABLED) { char uptime[10]; vty_out(vty, "Mroute socket descriptor: %d%s", qpim_mroute_socket_fd, VTY_NEWLINE); pim_time_uptime(uptime, sizeof(uptime), now - qpim_mroute_socket_creation); vty_out(vty, "Mroute socket uptime: %s%s", uptime, VTY_NEWLINE); } else { vty_out(vty, "Multicast disabled%s", VTY_NEWLINE); } vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Zclient update socket: "); if (qpim_zclient_update) { vty_out(vty, "%d failures=%d%s", qpim_zclient_update->sock, qpim_zclient_update->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); } vty_out(vty, "Zclient lookup socket: "); if (qpim_zclient_lookup) { vty_out(vty, "%d failures=%d%s", qpim_zclient_lookup->sock, qpim_zclient_lookup->fail, VTY_NEWLINE); } else { vty_out(vty, "%s", VTY_NEWLINE); } vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Current highest VifIndex: %d%s", qpim_mroute_oif_highest_vif_index, VTY_NEWLINE); vty_out(vty, "Maximum highest VifIndex: %d%s", MAXVIFS - 1, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Upstream Join Timer: %d secs%s", qpim_t_periodic, VTY_NEWLINE); vty_out(vty, "Join/Prune Holdtime: %d secs%s", PIM_JP_HOLDTIME, VTY_NEWLINE); vty_out(vty, "%s", VTY_NEWLINE); show_rpf_refresh_stats(vty, now); vty_out(vty, "%s", VTY_NEWLINE); show_scan_oil_stats(vty, now); show_multicast_interfaces(vty); return CMD_SUCCESS; } static void show_mroute(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; time_t now; vty_out(vty, "Proto: I=IGMP P=PIM%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out(vty, "Source Group Proto Input iVifI Output oVifI TTL Uptime %s", VTY_NEWLINE); now = pim_time_monotonic_sec(); for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; int oif_vif_index; pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); for (oif_vif_index = 0; oif_vif_index < MAXVIFS; ++oif_vif_index) { struct interface *ifp_in; struct interface *ifp_out; char oif_uptime[10]; int ttl; char proto[5]; ttl = c_oil->oil.mfcc_ttls[oif_vif_index]; if (ttl < 1) continue; ifp_in = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent); ifp_out = pim_if_find_by_vif_index(oif_vif_index); pim_time_uptime(oif_uptime, sizeof(oif_uptime), now - c_oil->oif_creation[oif_vif_index]); proto[0] = '\0'; if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_PIM) { strcat(proto, "P"); } if (c_oil->oif_flags[oif_vif_index] & PIM_OIF_FLAG_PROTO_IGMP) { strcat(proto, "I"); } vty_out(vty, "%-15s %-15s %-5s %-5s %5d %-6s %5d %3d %8s %s", source_str, group_str, proto, ifp_in ? ifp_in->name : "", c_oil->oil.mfcc_parent, ifp_out ? ifp_out->name : "", oif_vif_index, ttl, oif_uptime, VTY_NEWLINE); } } } DEFUN (show_ip_mroute, show_ip_mroute_cmd, "show ip mroute", SHOW_STR IP_STR MROUTE_STR) { show_mroute(vty); return CMD_SUCCESS; } static void show_mroute_count(struct vty *vty) { struct listnode *node; struct channel_oil *c_oil; vty_out(vty, "%s", VTY_NEWLINE); vty_out(vty, "Source Group Packets Bytes WrongIf %s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) { char group_str[100]; char source_str[100]; struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); sgreq.src = c_oil->oil.mfcc_origin; sgreq.grp = c_oil->oil.mfcc_mcastgrp; pim_inet4_dump("", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str)); pim_inet4_dump("", c_oil->oil.mfcc_origin, source_str, sizeof(source_str)); if (ioctl(qpim_mroute_socket_fd, SIOCGETSGCNT, &sgreq)) { int e = errno; vty_out(vty, "ioctl(SIOCGETSGCNT=%d) failure for (S,G)=(%s,%s): errno=%d: %s%s", SIOCGETSGCNT, source_str, group_str, e, safe_strerror(e), VTY_NEWLINE); continue; } vty_out(vty, "%-15s %-15s %7ld %10ld %7ld %s", source_str, group_str, sgreq.pktcnt, sgreq.bytecnt, sgreq.wrong_if, VTY_NEWLINE); } } DEFUN (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute count", SHOW_STR IP_STR MROUTE_STR "Route and packet count data\n") { show_mroute_count(vty); return CMD_SUCCESS; } DEFUN (show_ip_rib, show_ip_rib_cmd, "show ip rib A.B.C.D", SHOW_STR IP_STR RIB_STR "Unicast address\n") { struct in_addr addr; const char *addr_str; struct pim_nexthop nexthop; char nexthop_addr_str[100]; int result; addr_str = argv[0]; result = inet_pton(AF_INET, addr_str, &addr); if (result <= 0) { vty_out(vty, "Bad unicast address %s: errno=%d: %s%s", addr_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } if (pim_nexthop_lookup(&nexthop, addr)) { vty_out(vty, "Failure querying RIB nexthop for unicast address %s%s", addr_str, VTY_NEWLINE); return CMD_WARNING; } vty_out(vty, "Address NextHop Interface Metric Preference%s", VTY_NEWLINE); pim_inet4_dump("", nexthop.mrib_nexthop_addr, nexthop_addr_str, sizeof(nexthop_addr_str)); vty_out(vty, "%-15s %-15s %-9s %6d %10d%s", addr_str, nexthop_addr_str, nexthop.interface ? nexthop.interface->name : "", nexthop.mrib_route_metric, nexthop.mrib_metric_preference, VTY_NEWLINE); return CMD_SUCCESS; } static void show_ssmpingd(struct vty *vty) { struct listnode *node; struct ssmpingd_sock *ss; time_t now; vty_out(vty, "Source Socket Address Port Uptime Requests%s", VTY_NEWLINE); if (!qpim_ssmpingd_list) return; now = pim_time_monotonic_sec(); for (ALL_LIST_ELEMENTS_RO(qpim_ssmpingd_list, node, ss)) { char source_str[100]; char ss_uptime[10]; struct sockaddr_in bind_addr; socklen_t len = sizeof(bind_addr); char bind_addr_str[100]; pim_inet4_dump("", ss->source_addr, source_str, sizeof(source_str)); if (pim_socket_getsockname(ss->sock_fd, (struct sockaddr *) &bind_addr, &len)) { vty_out(vty, "%% Failure reading socket name for ssmpingd source %s on fd=%d%s", source_str, ss->sock_fd, VTY_NEWLINE); } pim_inet4_dump("", bind_addr.sin_addr, bind_addr_str, sizeof(bind_addr_str)); pim_time_uptime(ss_uptime, sizeof(ss_uptime), now - ss->creation); vty_out(vty, "%-15s %6d %-15s %5d %8s %8lld%s", source_str, ss->sock_fd, bind_addr_str, ntohs(bind_addr.sin_port), ss_uptime, (long long)ss->requests, VTY_NEWLINE); } } DEFUN (show_ip_ssmpingd, show_ip_ssmpingd_cmd, "show ip ssmpingd", SHOW_STR IP_STR SHOW_SSMPINGD_STR) { show_ssmpingd(vty); return CMD_SUCCESS; } DEFUN (ip_multicast_routing, ip_multicast_routing_cmd, PIM_CMD_IP_MULTICAST_ROUTING, IP_STR "Enable IP multicast forwarding\n") { pim_mroute_socket_enable(); pim_if_add_vif_all(); mroute_add_all(); return CMD_SUCCESS; } DEFUN (no_ip_multicast_routing, no_ip_multicast_routing_cmd, PIM_CMD_NO " " PIM_CMD_IP_MULTICAST_ROUTING, NO_STR IP_STR "Global IP configuration subcommands\n" "Enable IP multicast forwarding\n") { mroute_del_all(); pim_if_del_vif_all(); pim_mroute_socket_disable(); return CMD_SUCCESS; } DEFUN (ip_ssmpingd, ip_ssmpingd_cmd, "ip ssmpingd [A.B.C.D]", IP_STR CONF_SSMPINGD_STR "Source address\n") { int result; struct in_addr source_addr; const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_ssmpingd_start(source_addr); if (result) { vty_out(vty, "%% Failure starting ssmpingd for source %s: %d%s", source_str, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_ip_ssmpingd, no_ip_ssmpingd_cmd, "no ip ssmpingd [A.B.C.D]", NO_STR IP_STR CONF_SSMPINGD_STR "Source address\n") { int result; struct in_addr source_addr; const char *source_str = (argc > 0) ? argv[0] : "0.0.0.0"; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "%% Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_ssmpingd_stop(source_addr); if (result) { vty_out(vty, "%% Failure stopping ssmpingd for source %s: %d%s", source_str, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_ip_igmp, interface_ip_igmp_cmd, "ip igmp", IP_STR IFACE_IGMP_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { pim_ifp = pim_if_new(ifp, 1 /* igmp=true */, 0 /* pim=false */); if (!pim_ifp) { vty_out(vty, "Could not enable IGMP on interface %s%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } } else { PIM_IF_DO_IGMP(pim_ifp->options); } pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp, interface_no_ip_igmp_cmd, "no ip igmp", NO_STR IP_STR IFACE_IGMP_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; PIM_IF_DONT_IGMP(pim_ifp->options); pim_if_membership_clear(ifp); pim_if_addr_del_all_igmp(ifp); if (!PIM_IF_TEST_PIM(pim_ifp->options)) { pim_if_delete(ifp); } return CMD_SUCCESS; } DEFUN (interface_ip_igmp_join, interface_ip_igmp_join_cmd, "ip igmp join A.B.C.D A.B.C.D", IP_STR IFACE_IGMP_STR "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") { struct interface *ifp; const char *group_str; const char *source_str; struct in_addr group_addr; struct in_addr source_addr; int result; ifp = vty->index; /* Group address */ group_str = argv[0]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[1]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_if_igmp_join_add(ifp, group_addr, source_addr); if (result) { vty_out(vty, "%% Failure joining IGMP group %s source %s on interface %s: %d%s", group_str, source_str, ifp->name, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_join, interface_no_ip_igmp_join_cmd, "no ip igmp join A.B.C.D A.B.C.D", NO_STR IP_STR IFACE_IGMP_STR "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") { struct interface *ifp; const char *group_str; const char *source_str; struct in_addr group_addr; struct in_addr source_addr; int result; ifp = vty->index; /* Group address */ group_str = argv[0]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[1]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } result = pim_if_igmp_join_del(ifp, group_addr, source_addr); if (result) { vty_out(vty, "%% Failure leaving IGMP group %s source %s on interface %s: %d%s", group_str, source_str, ifp->name, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* CLI reconfiguration affects the interface level (struct pim_interface). This function propagates the reconfiguration to every active socket for that interface. */ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) { struct interface *ifp; struct pim_interface *pim_ifp; zassert(igmp); /* other querier present? */ if (igmp->t_other_querier_timer) return; /* this is the querier */ zassert(igmp->interface); zassert(igmp->interface->info); ifp = igmp->interface; pim_ifp = ifp->info; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[100]; pim_inet4_dump("", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str)); zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", __PRETTY_FUNCTION__, ifaddr_str, ifp->name, pim_ifp->igmp_default_query_interval); } /* igmp_startup_mode_on() will reset QQI: igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; */ igmp_startup_mode_on(igmp); } static void igmp_sock_query_reschedule(struct igmp_sock *igmp) { if (igmp->t_igmp_query_timer) { /* other querier present */ zassert(igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); pim_igmp_general_query_off(igmp); pim_igmp_general_query_on(igmp); zassert(igmp->t_igmp_query_timer); zassert(!igmp->t_other_querier_timer); } else { /* this is the querier */ zassert(!igmp->t_igmp_query_timer); zassert(igmp->t_other_querier_timer); pim_igmp_other_querier_timer_off(igmp); pim_igmp_other_querier_timer_on(igmp); zassert(!igmp->t_igmp_query_timer); zassert(igmp->t_other_querier_timer); } } static void change_query_interval(struct pim_interface *pim_ifp, int query_interval) { struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp->igmp_default_query_interval = query_interval; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { igmp_sock_query_interval_reconfig(igmp); igmp_sock_query_reschedule(igmp); } } static void change_query_max_response_time(struct pim_interface *pim_ifp, int query_max_response_time_dsec) { struct listnode *sock_node; struct igmp_sock *igmp; pim_ifp->igmp_query_max_response_time_dsec = query_max_response_time_dsec; /* Below we modify socket/group/source timers in order to quickly reflect the change. Otherwise, those timers would eventually catch up. */ /* scan all sockets */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { struct listnode *grp_node; struct igmp_group *grp; /* reschedule socket general query */ igmp_sock_query_reschedule(igmp); /* scan socket groups */ for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node, grp)) { struct listnode *src_node; struct igmp_source *src; /* reset group timers for groups in EXCLUDE mode */ if (grp->group_filtermode_isexcl) { igmp_group_reset_gmi(grp); } /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node, src)) { /* reset source timers for sources with running timers */ if (src->t_source_timer) { igmp_source_reset_gmi(igmp, grp, src); } } } } } #define IGMP_QUERY_INTERVAL_MIN (1) #define IGMP_QUERY_INTERVAL_MAX (1800) DEFUN (interface_ip_igmp_query_interval, interface_ip_igmp_query_interval_cmd, PIM_CMD_IP_IGMP_QUERY_INTERVAL " <1-1800>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR "Query interval in seconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_interval; int query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_interval = atoi(argv[0]); query_interval_dsec = 10 * query_interval; /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_interval < IGMP_QUERY_INTERVAL_MIN) { vty_out(vty, "General query interval %d lower than minimum %d%s", query_interval, IGMP_QUERY_INTERVAL_MIN, VTY_NEWLINE); return CMD_WARNING; } if (query_interval > IGMP_QUERY_INTERVAL_MAX) { vty_out(vty, "General query interval %d higher than maximum %d%s", query_interval, IGMP_QUERY_INTERVAL_MAX, VTY_NEWLINE); return CMD_WARNING; } if (query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { vty_out(vty, "Can't set general query interval %d dsec <= query max response time %d dsec.%s", query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_interval(pim_ifp, query_interval); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_interval, interface_no_ip_igmp_query_interval_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_INTERVAL, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_INTERVAL_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = IGMP_GENERAL_QUERY_INTERVAL * 10; if (default_query_interval_dsec <= pim_ifp->igmp_query_max_response_time_dsec) { vty_out(vty, "Can't set default general query interval %d dsec <= query max response time %d dsec.%s", default_query_interval_dsec, pim_ifp->igmp_query_max_response_time_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_interval(pim_ifp, IGMP_GENERAL_QUERY_INTERVAL); return CMD_SUCCESS; } #define IGMP_QUERY_MAX_RESPONSE_TIME_MIN (1) #define IGMP_QUERY_MAX_RESPONSE_TIME_MAX (25) DEFUN (interface_ip_igmp_query_max_response_time, interface_ip_igmp_query_max_response_time_cmd, PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME " <1-25>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "Query response value in seconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_max_response_time; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_max_response_time = atoi(argv[0]); /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_max_response_time < IGMP_QUERY_MAX_RESPONSE_TIME_MIN) { vty_out(vty, "Query max response time %d sec lower than minimum %d sec%s", query_max_response_time, IGMP_QUERY_MAX_RESPONSE_TIME_MIN, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time > IGMP_QUERY_MAX_RESPONSE_TIME_MAX) { vty_out(vty, "Query max response time %d sec higher than maximum %d sec%s", query_max_response_time, IGMP_QUERY_MAX_RESPONSE_TIME_MAX, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time >= pim_ifp->igmp_default_query_interval) { vty_out(vty, "Can't set query max response time %d sec >= general query interval %d sec%s", query_max_response_time, pim_ifp->igmp_default_query_interval, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, 10 * query_max_response_time); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_max_response_time, interface_no_ip_igmp_query_max_response_time_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { vty_out(vty, "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); return CMD_SUCCESS; } #define IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC (10) #define IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC (250) DEFUN (interface_ip_igmp_query_max_response_time_dsec, interface_ip_igmp_query_max_response_time_dsec_cmd, PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC " <10-250>", IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "Query response value in deciseconds\n") { struct interface *ifp; struct pim_interface *pim_ifp; int query_max_response_time_dsec; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { vty_out(vty, "IGMP not enabled on interface %s. Please enable IGMP first.%s", ifp->name, VTY_NEWLINE); return CMD_WARNING; } query_max_response_time_dsec = atoi(argv[0]); /* It seems we don't need to check bounds since command.c does it already, but we verify them anyway for extra safety. */ if (query_max_response_time_dsec < IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC) { vty_out(vty, "Query max response time %d dsec lower than minimum %d dsec%s", query_max_response_time_dsec, IGMP_QUERY_MAX_RESPONSE_TIME_MIN_DSEC, VTY_NEWLINE); return CMD_WARNING; } if (query_max_response_time_dsec > IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC) { vty_out(vty, "Query max response time %d dsec higher than maximum %d dsec%s", query_max_response_time_dsec, IGMP_QUERY_MAX_RESPONSE_TIME_MAX_DSEC, VTY_NEWLINE); return CMD_WARNING; } default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (query_max_response_time_dsec >= default_query_interval_dsec) { vty_out(vty, "Can't set query max response time %d dsec >= general query interval %d dsec%s", query_max_response_time_dsec, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, query_max_response_time_dsec); return CMD_SUCCESS; } DEFUN (interface_no_ip_igmp_query_max_response_time_dsec, interface_no_ip_igmp_query_max_response_time_dsec_cmd, PIM_CMD_NO " " PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, NO_STR IP_STR IFACE_IGMP_STR IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR) { struct interface *ifp; struct pim_interface *pim_ifp; int default_query_interval_dsec; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; default_query_interval_dsec = 10 * pim_ifp->igmp_default_query_interval; if (IGMP_QUERY_MAX_RESPONSE_TIME_DSEC >= default_query_interval_dsec) { vty_out(vty, "Can't set default query max response time %d dsec >= general query interval %d dsec.%s", IGMP_QUERY_MAX_RESPONSE_TIME_DSEC, default_query_interval_dsec, VTY_NEWLINE); return CMD_WARNING; } change_query_max_response_time(pim_ifp, IGMP_QUERY_MAX_RESPONSE_TIME_DSEC); return CMD_SUCCESS; } DEFUN (interface_ip_pim_ssm, interface_ip_pim_ssm_cmd, "ip pim ssm", IP_STR PIM_STR IFACE_PIM_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) { pim_ifp = pim_if_new(ifp, 0 /* igmp=false */, 1 /* pim=true */); if (!pim_ifp) { vty_out(vty, "Could not enable PIM on interface%s", VTY_NEWLINE); return CMD_WARNING; } } else { PIM_IF_DO_PIM(pim_ifp->options); } pim_if_addr_add_all(ifp); pim_if_membership_refresh(ifp); return CMD_SUCCESS; } DEFUN (interface_no_ip_pim_ssm, interface_no_ip_pim_ssm_cmd, "no ip pim ssm", NO_STR IP_STR PIM_STR IFACE_PIM_STR) { struct interface *ifp; struct pim_interface *pim_ifp; ifp = vty->index; pim_ifp = ifp->info; if (!pim_ifp) return CMD_SUCCESS; PIM_IF_DONT_PIM(pim_ifp->options); pim_if_membership_clear(ifp); /* pim_if_addr_del_all() removes all sockets from pim_ifp->igmp_socket_list. */ pim_if_addr_del_all(ifp); /* pim_sock_delete() removes all neighbors from pim_ifp->pim_neighbor_list. */ pim_sock_delete(ifp, "pim unconfigured on interface"); if (!PIM_IF_TEST_IGMP(pim_ifp->options)) { pim_if_delete(ifp); } return CMD_SUCCESS; } DEFUN (debug_igmp, debug_igmp_cmd, "debug igmp", DEBUG_STR DEBUG_IGMP_STR) { PIM_DO_DEBUG_IGMP_EVENTS; PIM_DO_DEBUG_IGMP_PACKETS; PIM_DO_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_igmp, no_debug_igmp_cmd, "no debug igmp", NO_STR DEBUG_STR DEBUG_IGMP_STR) { PIM_DONT_DEBUG_IGMP_EVENTS; PIM_DONT_DEBUG_IGMP_PACKETS; PIM_DONT_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_igmp, undebug_igmp_cmd, "undebug igmp", UNDEBUG_STR DEBUG_IGMP_STR) DEFUN (debug_igmp_events, debug_igmp_events_cmd, "debug igmp events", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) { PIM_DO_DEBUG_IGMP_EVENTS; return CMD_SUCCESS; } DEFUN (no_debug_igmp_events, no_debug_igmp_events_cmd, "no debug igmp events", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) { PIM_DONT_DEBUG_IGMP_EVENTS; return CMD_SUCCESS; } ALIAS (no_debug_igmp_events, undebug_igmp_events_cmd, "undebug igmp events", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_EVENTS_STR) DEFUN (debug_igmp_packets, debug_igmp_packets_cmd, "debug igmp packets", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) { PIM_DO_DEBUG_IGMP_PACKETS; return CMD_SUCCESS; } DEFUN (no_debug_igmp_packets, no_debug_igmp_packets_cmd, "no debug igmp packets", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) { PIM_DONT_DEBUG_IGMP_PACKETS; return CMD_SUCCESS; } ALIAS (no_debug_igmp_packets, undebug_igmp_packets_cmd, "undebug igmp packets", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_PACKETS_STR) DEFUN (debug_igmp_trace, debug_igmp_trace_cmd, "debug igmp trace", DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) { PIM_DO_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_igmp_trace, no_debug_igmp_trace_cmd, "no debug igmp trace", NO_STR DEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) { PIM_DONT_DEBUG_IGMP_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_igmp_trace, undebug_igmp_trace_cmd, "undebug igmp trace", UNDEBUG_STR DEBUG_IGMP_STR DEBUG_IGMP_TRACE_STR) DEFUN (debug_mroute, debug_mroute_cmd, "debug mroute", DEBUG_STR DEBUG_MROUTE_STR) { PIM_DO_DEBUG_MROUTE; return CMD_SUCCESS; } DEFUN (no_debug_mroute, no_debug_mroute_cmd, "no debug mroute", NO_STR DEBUG_STR DEBUG_MROUTE_STR) { PIM_DONT_DEBUG_MROUTE; return CMD_SUCCESS; } ALIAS (no_debug_mroute, undebug_mroute_cmd, "undebug mroute", UNDEBUG_STR DEBUG_MROUTE_STR) DEFUN (debug_pim, debug_pim_cmd, "debug pim", DEBUG_STR DEBUG_PIM_STR) { PIM_DO_DEBUG_PIM_EVENTS; PIM_DO_DEBUG_PIM_PACKETS; PIM_DO_DEBUG_PIM_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_pim, no_debug_pim_cmd, "no debug pim", NO_STR DEBUG_STR DEBUG_PIM_STR) { PIM_DONT_DEBUG_PIM_EVENTS; PIM_DONT_DEBUG_PIM_PACKETS; PIM_DONT_DEBUG_PIM_TRACE; PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } ALIAS (no_debug_pim, undebug_pim_cmd, "undebug pim", UNDEBUG_STR DEBUG_PIM_STR) DEFUN (debug_pim_events, debug_pim_events_cmd, "debug pim events", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) { PIM_DO_DEBUG_PIM_EVENTS; return CMD_SUCCESS; } DEFUN (no_debug_pim_events, no_debug_pim_events_cmd, "no debug pim events", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) { PIM_DONT_DEBUG_PIM_EVENTS; return CMD_SUCCESS; } ALIAS (no_debug_pim_events, undebug_pim_events_cmd, "undebug pim events", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_EVENTS_STR) DEFUN (debug_pim_packets, debug_pim_packets_cmd, "debug pim packets", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) { PIM_DO_DEBUG_PIM_PACKETS; vty_out (vty, "PIM Packet debugging is on %s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (debug_pim_packets_filter, debug_pim_packets_filter_cmd, "debug pim packets (hello|joins)", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { if (strncmp(argv[0],"h",1) == 0) { PIM_DO_DEBUG_PIM_HELLO; vty_out (vty, "PIM Hello debugging is on %s", VTY_NEWLINE); } else if (strncmp(argv[0],"j",1) == 0) { PIM_DO_DEBUG_PIM_J_P; vty_out (vty, "PIM Join/Prune debugging is on %s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_pim_packets, no_debug_pim_packets_cmd, "no debug pim packets", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { PIM_DONT_DEBUG_PIM_PACKETS; vty_out (vty, "PIM Packet debugging is off %s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (no_debug_pim_packets_filter, no_debug_pim_packets_filter_cmd, "no debug pim packets (hello|joins)", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR DEBUG_PIM_HELLO_PACKETS_STR DEBUG_PIM_J_P_PACKETS_STR) { if (strncmp(argv[0],"h",1) == 0) { PIM_DONT_DEBUG_PIM_HELLO; vty_out (vty, "PIM Hello debugging is off %s", VTY_NEWLINE); } else if (strncmp(argv[0],"j",1) == 0) { PIM_DONT_DEBUG_PIM_J_P; vty_out (vty, "PIM Join/Prune debugging is off %s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_pim_packets, undebug_pim_packets_cmd, "undebug pim packets", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETS_STR) DEFUN (debug_pim_packetdump_send, debug_pim_packetdump_send_cmd, "debug pim packet-dump send", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) { PIM_DO_DEBUG_PIM_PACKETDUMP_SEND; return CMD_SUCCESS; } DEFUN (no_debug_pim_packetdump_send, no_debug_pim_packetdump_send_cmd, "no debug pim packet-dump send", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) { PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND; return CMD_SUCCESS; } ALIAS (no_debug_pim_packetdump_send, undebug_pim_packetdump_send_cmd, "undebug pim packet-dump send", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_SEND_STR) DEFUN (debug_pim_packetdump_recv, debug_pim_packetdump_recv_cmd, "debug pim packet-dump receive", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) { PIM_DO_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } DEFUN (no_debug_pim_packetdump_recv, no_debug_pim_packetdump_recv_cmd, "no debug pim packet-dump receive", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) { PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV; return CMD_SUCCESS; } ALIAS (no_debug_pim_packetdump_recv, undebug_pim_packetdump_recv_cmd, "undebug pim packet-dump receive", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_PACKETDUMP_STR DEBUG_PIM_PACKETDUMP_RECV_STR) DEFUN (debug_pim_trace, debug_pim_trace_cmd, "debug pim trace", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) { PIM_DO_DEBUG_PIM_TRACE; return CMD_SUCCESS; } DEFUN (no_debug_pim_trace, no_debug_pim_trace_cmd, "no debug pim trace", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) { PIM_DONT_DEBUG_PIM_TRACE; return CMD_SUCCESS; } ALIAS (no_debug_pim_trace, undebug_pim_trace_cmd, "undebug pim trace", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_TRACE_STR) DEFUN (debug_ssmpingd, debug_ssmpingd_cmd, "debug ssmpingd", DEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) { PIM_DO_DEBUG_SSMPINGD; return CMD_SUCCESS; } DEFUN (no_debug_ssmpingd, no_debug_ssmpingd_cmd, "no debug ssmpingd", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) { PIM_DONT_DEBUG_SSMPINGD; return CMD_SUCCESS; } ALIAS (no_debug_ssmpingd, undebug_ssmpingd_cmd, "undebug ssmpingd", UNDEBUG_STR DEBUG_PIM_STR DEBUG_SSMPINGD_STR) DEFUN (debug_pim_zebra, debug_pim_zebra_cmd, "debug pim zebra", DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) { PIM_DO_DEBUG_ZEBRA; return CMD_SUCCESS; } DEFUN (no_debug_pim_zebra, no_debug_pim_zebra_cmd, "no debug pim zebra", NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) { PIM_DONT_DEBUG_ZEBRA; return CMD_SUCCESS; } ALIAS (no_debug_pim_zebra, undebug_pim_zebra_cmd, "undebug pim zebra", UNDEBUG_STR DEBUG_PIM_STR DEBUG_PIM_ZEBRA_STR) DEFUN (show_debugging, show_debugging_cmd, "show debugging", SHOW_STR "State of each debugging option\n") { pim_debug_config_write(vty); return CMD_SUCCESS; } static struct igmp_sock *find_igmp_sock_by_fd(int fd) { struct listnode *ifnode; struct interface *ifp; /* scan all interfaces */ for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) { struct pim_interface *pim_ifp; struct igmp_sock *igmp; if (!ifp->info) continue; pim_ifp = ifp->info; /* lookup igmp socket under current interface */ igmp = igmp_sock_lookup_by_fd(pim_ifp->igmp_socket_list, fd); if (igmp) return igmp; } return 0; } DEFUN (test_igmp_receive_report, test_igmp_receive_report_cmd, "test igmp receive report <0-65535> A.B.C.D <1-6> .LINE", "Test\n" "Test IGMP protocol\n" "Test IGMP message\n" "Test IGMP report\n" "Socket\n" "IGMP group address\n" "Record type\n" "Sources\n") { char buf[1000]; char *igmp_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int igmp_msg_len; const char *socket; int socket_fd; const char *grp_str; struct in_addr grp_addr; const char *record_type_str; int record_type; const char *src_str; int result; struct igmp_sock *igmp; char *group_record; int num_sources; struct in_addr *sources; struct in_addr *src_addr; int argi; socket = argv[0]; socket_fd = atoi(socket); igmp = find_igmp_sock_by_fd(socket_fd); if (!igmp) { vty_out(vty, "Could not find IGMP socket %s: fd=%d%s", socket, socket_fd, VTY_NEWLINE); return CMD_WARNING; } grp_str = argv[1]; result = inet_pton(AF_INET, grp_str, &grp_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", grp_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } record_type_str = argv[2]; record_type = atoi(record_type_str); /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_IGMP; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = igmp->ifaddr; ip_hdr->ip_dst = igmp->ifaddr; /* Build IGMP v3 report message */ igmp_msg = buf + ip_hlen; group_record = igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET; *igmp_msg = PIM_IGMP_V3_MEMBERSHIP_REPORT; /* type */ *(uint16_t *) (igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = 0; /* for computing checksum */ *(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET) = htons(1); /* one group record */ *(uint8_t *) (group_record + IGMP_V3_GROUP_RECORD_TYPE_OFFSET) = record_type; memcpy(group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, &grp_addr, sizeof(struct in_addr)); /* Scan LINE sources */ sources = (struct in_addr *) (group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET); src_addr = sources; for (argi = 3; argi < argc; ++argi,++src_addr) { src_str = argv[argi]; result = inet_pton(AF_INET, src_str, src_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } } num_sources = src_addr - sources; *(uint16_t *)(group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET) = htons(num_sources); igmp_msg_len = IGMP_V3_MSG_MIN_SIZE + (num_sources << 4); /* v3 report for one single group record */ /* compute checksum */ *(uint16_t *)(igmp_msg + IGMP_V3_CHECKSUM_OFFSET) = in_cksum(igmp_msg, igmp_msg_len); /* "receive" message */ ip_msg_len = ip_hlen + igmp_msg_len; result = pim_igmp_packet(igmp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_igmp_packet(len=%d) returned: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static int hexval(uint8_t ch) { return isdigit(ch) ? (ch - '0') : (10 + tolower(ch) - 'a'); } DEFUN (test_pim_receive_dump, test_pim_receive_dump_cmd, "test pim receive dump INTERFACE A.B.C.D .LINE", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM packet dump reception from neighbor\n" "Interface\n" "Neighbor address\n" "Packet dump\n") { uint8_t buf[1000]; uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *ifname; struct interface *ifp; int argi; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM hello message */ pim_msg = buf + ip_hlen; pim_msg_size = 0; /* Scan LINE dump into buffer */ for (argi = 2; argi < argc; ++argi) { const char *str = argv[argi]; int str_len = strlen(str); int str_last = str_len - 1; int i; if (str_len % 2) { vty_out(vty, "%% Uneven hex array arg %d=%s%s", argi, str, VTY_NEWLINE); return CMD_WARNING; } for (i = 0; i < str_last; i += 2) { uint8_t octet; int left; uint8_t h1 = str[i]; uint8_t h2 = str[i + 1]; if (!isxdigit(h1) || !isxdigit(h2)) { vty_out(vty, "%% Non-hex octet %c%c at hex array arg %d=%s%s", h1, h2, argi, str, VTY_NEWLINE); return CMD_WARNING; } octet = (hexval(h1) << 4) + hexval(h2); left = sizeof(buf) - ip_hlen - pim_msg_size; if (left < 1) { vty_out(vty, "%% Overflow buf_size=%zu buf_left=%d at hex array arg %d=%s octet %02x%s", sizeof(buf), left, argi, str, octet, VTY_NEWLINE); return CMD_WARNING; } pim_msg[pim_msg_size++] = octet; } } ip_msg_len = ip_hlen + pim_msg_size; vty_out(vty, "Receiving: buf_size=%zu ip_msg_size=%d pim_msg_size=%d%s", sizeof(buf), ip_msg_len, pim_msg_size, VTY_NEWLINE); /* "receive" message */ result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "%% pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_hello, test_pim_receive_hello_cmd, "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM hello reception from neighbor\n" "Interface\n" "Neighbor address\n" "Neighbor holdtime\n" "Neighbor DR priority\n" "Neighbor generation ID\n" "Neighbor propagation delay (msec)\n" "Neighbor override interval (msec)\n" "Neighbor LAN prune delay T-bit\n" "Neighbor secondary addresses\n") { uint8_t buf[1000]; uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_tlv_size; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *ifname; struct interface *ifp; uint16_t neigh_holdtime; uint16_t neigh_propagation_delay; uint16_t neigh_override_interval; int neigh_can_disable_join_suppression; uint32_t neigh_dr_priority; uint32_t neigh_generation_id; int argi; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } neigh_holdtime = atoi(argv[2]); neigh_dr_priority = atoi(argv[3]); neigh_generation_id = atoi(argv[4]); neigh_propagation_delay = atoi(argv[5]); neigh_override_interval = atoi(argv[6]); neigh_can_disable_join_suppression = atoi(argv[7]); /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM hello message */ pim_msg = buf + ip_hlen; /* Scan LINE addresses */ for (argi = 8; argi < argc; ++argi) { const char *sec_str = argv[argi]; struct in_addr sec_addr; result = inet_pton(AF_INET, sec_str, &sec_addr); if (result <= 0) { vty_out(vty, "Bad neighbor secondary address %s: errno=%d: %s%s", sec_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } vty_out(vty, "FIXME WRITEME consider neighbor secondary address %s%s", sec_str, VTY_NEWLINE); } pim_tlv_size = pim_hello_build_tlv(ifp->name, pim_msg + PIM_PIM_MIN_LEN, sizeof(buf) - ip_hlen - PIM_PIM_MIN_LEN, neigh_holdtime, neigh_dr_priority, neigh_generation_id, neigh_propagation_delay, neigh_override_interval, neigh_can_disable_join_suppression, 0 /* FIXME secondary address list */); if (pim_tlv_size < 0) { vty_out(vty, "pim_hello_build_tlv() returned failure: %d%s", pim_tlv_size, VTY_NEWLINE); return CMD_WARNING; } pim_msg_size = pim_tlv_size + PIM_PIM_MIN_LEN; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_HELLO); /* "receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_assert, test_pim_receive_assert_cmd, "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D <0-65535> <0-65535> <0-1>", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of PIM assert\n" "Interface\n" "Neighbor address\n" "Assert multicast group address\n" "Assert unicast source address\n" "Assert metric preference\n" "Assert route metric\n" "Assert RPT bit flag\n") { uint8_t buf[1000]; uint8_t *buf_pastend = buf + sizeof(buf); uint8_t *pim_msg; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; int pim_msg_size; const char *neigh_str; struct in_addr neigh_addr; const char *group_str; struct in_addr group_addr; const char *source_str; struct in_addr source_addr; const char *ifname; struct interface *ifp; uint32_t assert_metric_preference; uint32_t assert_route_metric; uint32_t assert_rpt_bit_flag; int remain; int result; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } /* Neighbor address */ neigh_str = argv[1]; result = inet_pton(AF_INET, neigh_str, &neigh_addr); if (result <= 0) { vty_out(vty, "Bad neighbor address %s: errno=%d: %s%s", neigh_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Group address */ group_str = argv[2]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[3]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } assert_metric_preference = atoi(argv[4]); assert_route_metric = atoi(argv[5]); assert_rpt_bit_flag = atoi(argv[6]); remain = buf_pastend - buf; if (remain < (int) sizeof(struct ip)) { vty_out(vty, "No room for ip header: buf_size=%d < ip_header_size=%zu%s", remain, sizeof(struct ip), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM assert message */ pim_msg = buf + ip_hlen; /* skip ip header */ pim_msg_size = pim_assert_build_msg(pim_msg, buf_pastend - pim_msg, ifp, group_addr, source_addr, assert_metric_preference, assert_route_metric, assert_rpt_bit_flag); if (pim_msg_size < 0) { vty_out(vty, "Failure building PIM assert message: size=%d%s", pim_msg_size, VTY_NEWLINE); return CMD_WARNING; } /* "receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } static int recv_joinprune(struct vty *vty, const char *argv[], int src_is_join) { uint8_t buf[1000]; const uint8_t *buf_pastend = buf + sizeof(buf); uint8_t *pim_msg; uint8_t *pim_msg_curr; int pim_msg_size; struct ip *ip_hdr; size_t ip_hlen; /* ip header length in bytes */ int ip_msg_len; uint16_t neigh_holdtime; const char *neigh_dst_str; struct in_addr neigh_dst_addr; const char *neigh_src_str; struct in_addr neigh_src_addr; const char *group_str; struct in_addr group_addr; const char *source_str; struct in_addr source_addr; const char *ifname; struct interface *ifp; int result; int remain; uint16_t num_joined; uint16_t num_pruned; /* Find interface */ ifname = argv[0]; ifp = if_lookup_by_name(ifname); if (!ifp) { vty_out(vty, "No such interface name %s%s", ifname, VTY_NEWLINE); return CMD_WARNING; } neigh_holdtime = atoi(argv[1]); /* Neighbor destination address */ neigh_dst_str = argv[2]; result = inet_pton(AF_INET, neigh_dst_str, &neigh_dst_addr); if (result <= 0) { vty_out(vty, "Bad neighbor destination address %s: errno=%d: %s%s", neigh_dst_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Neighbor source address */ neigh_src_str = argv[3]; result = inet_pton(AF_INET, neigh_src_str, &neigh_src_addr); if (result <= 0) { vty_out(vty, "Bad neighbor source address %s: errno=%d: %s%s", neigh_src_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Multicast group address */ group_str = argv[4]; result = inet_pton(AF_INET, group_str, &group_addr); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Multicast source address */ source_str = argv[5]; result = inet_pton(AF_INET, source_str, &source_addr); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Tweak IP header */ ip_hdr = (struct ip *) buf; ip_hdr->ip_p = PIM_IP_PROTO_PIM; ip_hlen = PIM_IP_HEADER_MIN_LEN; /* ip header length in bytes */ ip_hdr->ip_hl = ip_hlen >> 2; /* ip header length in 4-byte words */ ip_hdr->ip_src = neigh_src_addr; ip_hdr->ip_dst = qpim_all_pim_routers_addr; /* Build PIM message */ pim_msg = buf + ip_hlen; /* skip room for pim header */ pim_msg_curr = pim_msg + PIM_MSG_HEADER_LEN; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_ucast(pim_msg_curr, remain, neigh_dst_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding destination address %s: space left=%d%s", neigh_dst_str, remain, VTY_NEWLINE); return CMD_WARNING; } remain = buf_pastend - pim_msg_curr; if (remain < 4) { vty_out(vty, "Group will not fit: space left=%d%s", remain, VTY_NEWLINE); return CMD_WARNING; } *pim_msg_curr = 0; /* reserved */ ++pim_msg_curr; *pim_msg_curr = 1; /* number of groups */ ++pim_msg_curr; *((uint16_t *) pim_msg_curr) = htons(neigh_holdtime); ++pim_msg_curr; ++pim_msg_curr; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_group(pim_msg_curr, remain, group_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding group address %s: space left=%d%s", group_str, remain, VTY_NEWLINE); return CMD_WARNING; } remain = buf_pastend - pim_msg_curr; if (remain < 4) { vty_out(vty, "Sources will not fit: space left=%d%s", remain, VTY_NEWLINE); return CMD_WARNING; } if (src_is_join) { num_joined = 1; num_pruned = 0; } else { num_joined = 0; num_pruned = 1; } /* number of joined sources */ *((uint16_t *) pim_msg_curr) = htons(num_joined); ++pim_msg_curr; ++pim_msg_curr; /* number of pruned sources */ *((uint16_t *) pim_msg_curr) = htons(num_pruned); ++pim_msg_curr; ++pim_msg_curr; remain = buf_pastend - pim_msg_curr; pim_msg_curr = pim_msg_addr_encode_ipv4_source(pim_msg_curr, remain, source_addr); if (!pim_msg_curr) { vty_out(vty, "Failure encoding source address %s: space left=%d%s", source_str, remain, VTY_NEWLINE); return CMD_WARNING; } /* Add PIM header */ pim_msg_size = pim_msg_curr - pim_msg; pim_msg_build_header(pim_msg, pim_msg_size, PIM_MSG_TYPE_JOIN_PRUNE); /* "Receive" message */ ip_msg_len = ip_hlen + pim_msg_size; result = pim_pim_packet(ifp, buf, ip_msg_len); if (result) { vty_out(vty, "pim_pim_packet(len=%d) returned failure: %d%s", ip_msg_len, result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (test_pim_receive_join, test_pim_receive_join_cmd, "test pim receive join INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM join reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") { return recv_joinprune(vty, argv, 1 /* src_is_join=true */); } DEFUN (test_pim_receive_prune, test_pim_receive_prune_cmd, "test pim receive prune INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM prune reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") { return recv_joinprune(vty, argv, 0 /* src_is_join=false */); } DEFUN (test_pim_receive_upcall, test_pim_receive_upcall_cmd, "test pim receive upcall (nocache|wrongvif|wholepkt) <0-65535> A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of kernel upcall\n" "NOCACHE kernel upcall\n" "WRONGVIF kernel upcall\n" "WHOLEPKT kernel upcall\n" "Input interface vif index\n" "Multicast group address\n" "Multicast source address\n") { struct igmpmsg msg; const char *upcall_type; const char *group_str; const char *source_str; int result; upcall_type = argv[0]; if (upcall_type[0] == 'n') msg.im_msgtype = IGMPMSG_NOCACHE; else if (upcall_type[1] == 'r') msg.im_msgtype = IGMPMSG_WRONGVIF; else if (upcall_type[1] == 'h') msg.im_msgtype = IGMPMSG_WHOLEPKT; else { vty_out(vty, "Unknown kernel upcall type: %s%s", upcall_type, VTY_NEWLINE); return CMD_WARNING; } msg.im_vif = atoi(argv[1]); /* Group address */ group_str = argv[2]; result = inet_pton(AF_INET, group_str, &msg.im_dst); if (result <= 0) { vty_out(vty, "Bad group address %s: errno=%d: %s%s", group_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } /* Source address */ source_str = argv[3]; result = inet_pton(AF_INET, source_str, &msg.im_src); if (result <= 0) { vty_out(vty, "Bad source address %s: errno=%d: %s%s", source_str, errno, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } msg.im_mbz = 0; /* Must be zero */ result = pim_mroute_msg(-1, (char *) &msg, sizeof(msg)); if (result) { vty_out(vty, "pim_mroute_msg(len=%zu) returned failure: %d%s", sizeof(msg), result, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } void pim_cmd_init() { install_node (&pim_global_node, pim_global_config_write); /* PIM_NODE */ install_node (&interface_node, pim_interface_config_write); /* INTERFACE_NODE */ install_element (CONFIG_NODE, &ip_multicast_routing_cmd); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd); install_element (CONFIG_NODE, &ip_ssmpingd_cmd); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd); #if 0 install_element (CONFIG_NODE, &interface_cmd); /* from if.h */ #else install_element (CONFIG_NODE, &pim_interface_cmd); #endif install_element (CONFIG_NODE, &no_interface_cmd); /* from if.h */ install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd); install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd); install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd); install_element (VIEW_NODE, &show_ip_igmp_interface_cmd); install_element (VIEW_NODE, &show_ip_igmp_join_cmd); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_cmd); install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd); install_element (VIEW_NODE, &show_ip_igmp_sources_cmd); install_element (VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd); install_element (VIEW_NODE, &show_ip_igmp_querier_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd); install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd); install_element (VIEW_NODE, &show_ip_pim_dr_cmd); install_element (VIEW_NODE, &show_ip_pim_hello_cmd); install_element (VIEW_NODE, &show_ip_pim_interface_cmd); install_element (VIEW_NODE, &show_ip_pim_join_cmd); install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd); install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd); install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd); install_element (VIEW_NODE, &show_ip_pim_neighbor_cmd); install_element (VIEW_NODE, &show_ip_pim_rpf_cmd); install_element (VIEW_NODE, &show_ip_pim_secondary_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd); install_element (VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); install_element (VIEW_NODE, &show_ip_multicast_cmd); install_element (VIEW_NODE, &show_ip_mroute_cmd); install_element (VIEW_NODE, &show_ip_mroute_count_cmd); install_element (VIEW_NODE, &show_ip_rib_cmd); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd); install_element (VIEW_NODE, &show_debugging_cmd); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_mroute_cmd); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd); install_element (ENABLE_NODE, &show_ip_igmp_join_cmd); install_element (ENABLE_NODE, &show_ip_igmp_parameters_cmd); install_element (ENABLE_NODE, &show_ip_igmp_groups_cmd); install_element (ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd); install_element (ENABLE_NODE, &show_ip_igmp_sources_cmd); install_element (ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd); install_element (ENABLE_NODE, &show_ip_igmp_querier_cmd); install_element (ENABLE_NODE, &show_ip_pim_address_cmd); install_element (ENABLE_NODE, &show_ip_pim_assert_cmd); install_element (ENABLE_NODE, &show_ip_pim_assert_internal_cmd); install_element (ENABLE_NODE, &show_ip_pim_assert_metric_cmd); install_element (ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd); install_element (ENABLE_NODE, &show_ip_pim_dr_cmd); install_element (ENABLE_NODE, &show_ip_pim_hello_cmd); install_element (ENABLE_NODE, &show_ip_pim_interface_cmd); install_element (ENABLE_NODE, &show_ip_pim_join_cmd); install_element (ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd); install_element (ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd); install_element (ENABLE_NODE, &show_ip_pim_local_membership_cmd); install_element (ENABLE_NODE, &show_ip_pim_neighbor_cmd); install_element (ENABLE_NODE, &show_ip_pim_rpf_cmd); install_element (ENABLE_NODE, &show_ip_pim_secondary_cmd); install_element (ENABLE_NODE, &show_ip_pim_upstream_cmd); install_element (ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd); install_element (ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd); install_element (ENABLE_NODE, &show_ip_multicast_cmd); install_element (ENABLE_NODE, &show_ip_mroute_cmd); install_element (ENABLE_NODE, &show_ip_mroute_count_cmd); install_element (ENABLE_NODE, &show_ip_rib_cmd); install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd); install_element (ENABLE_NODE, &show_debugging_cmd); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd); install_element (ENABLE_NODE, &test_pim_receive_dump_cmd); install_element (ENABLE_NODE, &test_pim_receive_hello_cmd); install_element (ENABLE_NODE, &test_pim_receive_join_cmd); install_element (ENABLE_NODE, &test_pim_receive_prune_cmd); install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd); install_element (ENABLE_NODE, &debug_igmp_cmd); install_element (ENABLE_NODE, &no_debug_igmp_cmd); install_element (ENABLE_NODE, &undebug_igmp_cmd); install_element (ENABLE_NODE, &debug_igmp_events_cmd); install_element (ENABLE_NODE, &no_debug_igmp_events_cmd); install_element (ENABLE_NODE, &undebug_igmp_events_cmd); install_element (ENABLE_NODE, &debug_igmp_packets_cmd); install_element (ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element (ENABLE_NODE, &undebug_igmp_packets_cmd); install_element (ENABLE_NODE, &debug_igmp_trace_cmd); install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element (ENABLE_NODE, &undebug_igmp_trace_cmd); install_element (ENABLE_NODE, &debug_mroute_cmd); install_element (ENABLE_NODE, &no_debug_mroute_cmd); install_element (ENABLE_NODE, &debug_pim_cmd); install_element (ENABLE_NODE, &no_debug_pim_cmd); install_element (ENABLE_NODE, &undebug_pim_cmd); install_element (ENABLE_NODE, &debug_pim_events_cmd); install_element (ENABLE_NODE, &no_debug_pim_events_cmd); install_element (ENABLE_NODE, &undebug_pim_events_cmd); install_element (ENABLE_NODE, &debug_pim_packets_cmd); install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd); install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd); install_element (ENABLE_NODE, &undebug_pim_packets_cmd); install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd); install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd); install_element (ENABLE_NODE, &debug_pim_trace_cmd); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd); install_element (ENABLE_NODE, &undebug_pim_trace_cmd); install_element (ENABLE_NODE, &debug_ssmpingd_cmd); install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element (ENABLE_NODE, &undebug_ssmpingd_cmd); install_element (ENABLE_NODE, &debug_pim_zebra_cmd); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd); install_element (CONFIG_NODE, &debug_igmp_cmd); install_element (CONFIG_NODE, &no_debug_igmp_cmd); install_element (CONFIG_NODE, &undebug_igmp_cmd); install_element (CONFIG_NODE, &debug_igmp_events_cmd); install_element (CONFIG_NODE, &no_debug_igmp_events_cmd); install_element (CONFIG_NODE, &undebug_igmp_events_cmd); install_element (CONFIG_NODE, &debug_igmp_packets_cmd); install_element (CONFIG_NODE, &no_debug_igmp_packets_cmd); install_element (CONFIG_NODE, &undebug_igmp_packets_cmd); install_element (CONFIG_NODE, &debug_igmp_trace_cmd); install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd); install_element (CONFIG_NODE, &undebug_igmp_trace_cmd); install_element (CONFIG_NODE, &debug_mroute_cmd); install_element (CONFIG_NODE, &no_debug_mroute_cmd); install_element (CONFIG_NODE, &debug_pim_cmd); install_element (CONFIG_NODE, &no_debug_pim_cmd); install_element (CONFIG_NODE, &undebug_pim_cmd); install_element (CONFIG_NODE, &debug_pim_events_cmd); install_element (CONFIG_NODE, &no_debug_pim_events_cmd); install_element (CONFIG_NODE, &undebug_pim_events_cmd); install_element (CONFIG_NODE, &debug_pim_packets_cmd); install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &no_debug_pim_packets_cmd); install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd); install_element (CONFIG_NODE, &undebug_pim_packets_cmd); install_element (CONFIG_NODE, &debug_pim_trace_cmd); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd); install_element (CONFIG_NODE, &undebug_pim_trace_cmd); install_element (CONFIG_NODE, &debug_ssmpingd_cmd); install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd); install_element (CONFIG_NODE, &undebug_ssmpingd_cmd); install_element (CONFIG_NODE, &debug_pim_zebra_cmd); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd); } quagga-0.99.24.1/pimd/pim_version.c0000644000175000017500000000162112476520570013663 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include "pim_version.h" const char * const PIMD_VERSION = PIMD_VERSION_STR; quagga-0.99.24.1/pimd/pimd.c0000644000175000017500000001100212476520570012254 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #include #include "log.h" #include "memory.h" #include "pimd.h" #include "pim_cmd.h" #include "pim_iface.h" #include "pim_zebra.h" #include "pim_str.h" #include "pim_oil.h" #include "pim_pim.h" #include "pim_upstream.h" #include "pim_rand.h" #include "pim_rpf.h" #include "pim_ssmpingd.h" const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; struct thread_master *master = 0; uint32_t qpim_debugs = 0; int qpim_mroute_socket_fd = -1; int64_t qpim_mroute_socket_creation = 0; /* timestamp of creation */ struct thread *qpim_mroute_socket_reader = 0; int qpim_mroute_oif_highest_vif_index = -1; struct list *qpim_channel_oil_list = 0; int qpim_t_periodic = PIM_DEFAULT_T_PERIODIC; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list = 0; struct zclient *qpim_zclient_update = 0; struct zclient *qpim_zclient_lookup = 0; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec = 10000; struct thread *qpim_rpf_cache_refresher = 0; int64_t qpim_rpf_cache_refresh_requests = 0; int64_t qpim_rpf_cache_refresh_events = 0; int64_t qpim_rpf_cache_refresh_last = 0; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list = 0; struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events = 0; int64_t qpim_scan_oil_last = 0; int64_t qpim_mroute_add_events = 0; int64_t qpim_mroute_add_last = 0; int64_t qpim_mroute_del_events = 0; int64_t qpim_mroute_del_last = 0; static void pim_free() { pim_ssmpingd_destroy(); if (qpim_channel_oil_list) list_free(qpim_channel_oil_list); if (qpim_upstream_list) list_free(qpim_upstream_list); } void pim_init() { pim_rand_init(); if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) { zlog_err("%s %s: could not solve %s to group address: errno=%d: %s", __FILE__, __PRETTY_FUNCTION__, PIM_ALL_PIM_ROUTERS, errno, safe_strerror(errno)); zassert(0); return; } qpim_channel_oil_list = list_new(); if (!qpim_channel_oil_list) { zlog_err("%s %s: failure: channel_oil_list=list_new()", __FILE__, __PRETTY_FUNCTION__); return; } qpim_channel_oil_list->del = (void (*)(void *)) pim_channel_oil_free; qpim_upstream_list = list_new(); if (!qpim_upstream_list) { zlog_err("%s %s: failure: upstream_list=list_new()", __FILE__, __PRETTY_FUNCTION__); pim_free(); return; } qpim_upstream_list->del = (void (*)(void *)) pim_upstream_free; qpim_mroute_socket_fd = -1; /* mark mroute as disabled */ qpim_mroute_oif_highest_vif_index = -1; zassert(!qpim_debugs); zassert(!PIM_MROUTE_IS_ENABLED); qpim_inaddr_any.s_addr = PIM_NET_INADDR_ANY; /* RFC 4601: 4.6.3. Assert Metrics assert_metric infinite_assert_metric() { return {1,infinity,infinity,0} } */ qpim_infinite_assert_metric.rpt_bit_flag = 1; qpim_infinite_assert_metric.metric_preference = PIM_ASSERT_METRIC_PREFERENCE_MAX; qpim_infinite_assert_metric.route_metric = PIM_ASSERT_ROUTE_METRIC_MAX; qpim_infinite_assert_metric.ip_address = qpim_inaddr_any; pim_if_init(); pim_cmd_init(); pim_ssmpingd_init(); } void pim_terminate() { pim_free(); } quagga-0.99.24.1/pimd/TODO0000644000175000017500000003744612476520570011673 00000000000000# $QuaggaId: $Format:%an, %ai, %h$ $ T1 DONE Implement debug command test pim receive join T2 DONE Implement debug command test pim receive prune T3 DONE Per-interface Downstream (S,G) state machine (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages) T4 DONE Upstream (S,G) state machine (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages) T5 DONE Verify Data Packet Forwarding Rules RFC 4601 4.2. Data Packet Forwarding Rules RFC 4601 4.8.2. PIM-SSM-Only Routers Additionally, the Packet forwarding rules of Section 4.2 can be simplified in a PIM-SSM-only router: iif is the incoming interface of the packet. oiflist = NULL if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) { oiflist = inherited_olist(S,G) } else if (iif is in inherited_olist(S,G)) { send Assert(S,G) on iif } oiflist = oiflist (-) iif forward packet on all interfaces in oiflist Macro: inherited_olist(S,G) = joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G) T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1). Changes in pim_ifchannel.ifassert_winner should trigger pim_upstream_update_join_desired(). Depends on TODO T27. Depends on TODO T33. See also CAVEAT C7. See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages Transitions from Joined State RPF'(S,G) changes due to an Assert http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html: The PIM Assert mechanism is used to shutoff duplicate flows onto the same multiaccess network. Routers detect this condiction when they receive an (S,G) packet via a multi-access interface that is in the (S,G) OIL. This causes the routers to send Assert Messages. Note that neighbors will not accept Join/Prune or Assert messages from a router unless they have first heard a Hello message from that router. Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. T7 DONE Implement hello option: LAN Prune Delay T8 DONE Implement J/P_Override_Interval(I) Depends on TODO T7. See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval. T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update. channel_oil vif index accordingly ? Beware accidentaly adding looped MFC entries (IIF=OIF). T10 DONE React to (S,G) join directed to another upstream address. See also: RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages If a router wishes to propagate a Join(S,G) upstream, it must also watch for messages on its upstream interface from other routers on that subnet, and these may modify its behavior. If it sees a Join(S,G) to the correct upstream neighbor, it should suppress its own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or Prune(*,G) to the correct upstream neighbor towards S, it should be prepared to override that prune by scheduling a Join(S,G) to be sent almost immediately. T11 DONE Review protocol modifications for SSM (RFC 4601 4.8.1. Protocol Modifications for SSM Destination Addresses) T12 DONE Review updates of RPF entries. FIXME pim_upstream.c send_join(): Currently only one upstream state is affected by detection of RPF change. RPF change should affect all upstream states sharing the RPF cache. T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually implemented with this strategy: rpf_ifch=find_ifch(up->rpf->interface). See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example. $ grep -i macro pimd/*.c pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros pimd/pim_ifchannel.c: Macro: pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall. See pim_mroute.c mroute_msg(). T15 DONE Interface command to statically join (S,G). interface eth0 ip igmp join-group 239.1.1.1 source 1.1.1.1 T16 DONE RPF'(S,G) lookup is not working for S reachable with default route. See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c. Zebra daemon RIB is not reflecting changes in kernel routes accurately? T17 DONE Prevent CLI from creating bogus interfaces. Example: conf t interface xxx T18 Consider reliable pim solution (refresh reduction) A Reliable Transport Mechanism for PIM http://tools.ietf.org/wg/pim/draft-ietf-pim-port/ PORT=PIM-Over-Reliable-Transport T19 DONE Fix self as neighbor See mailing list post: http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html T20 DONE Fix debug message: "pim_neighbor_update: internal error: trying to replace same prefix list" See mailing list post: http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html T21 DONE Clean-up PIM/IGMP interface mismatch debugging See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am See mailing list post: http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html T22 DONE IGMP must be protected against adding looped MFC entries created by both source and receiver attached to the same interface. T23 DONE libzebra crash after zclient_lookup_nexthop. See mailing list post: http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html T24 DONE zserv may return recursive routes: - nexthop type is set to ZEBRA_NEXTHOP_IPV4 - ifindex is not reported - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted See also this mailing list post: [PATCH 21/21] Link detect and recursive routes http://www.gossamer-threads.com/lists/quagga/dev/17564 T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32 See also: pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32 zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32 T26 DONE Zebra daemon is marking recursive static route as inactive. FIXED: zebra daemon was incorrectly marking recursive routes pointing to kernel routes as inactive: zebra/zebra_rib.c nexthop_active_ipv4: -- Original: else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) -- Fixed: else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || match->type == ZEBRA_ROUTE_KERNEL) Old problem description: This prevents rib_match_ipv4 from returning its nexthop: client: pim_zlookup.c zclient_read_nexthop server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4 Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4 Examples: rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); This patch didn't fix the issue: [PATCH 21/21] Link detect and recursive routes http://www.gossamer-threads.com/lists/quagga/dev/17564 See the example below for the route 2.2.2.2. bash# route add -host 1.1.1.1 gw 127.0.0.1 bash# route add -host 2.2.2.2 gw 1.1.1.1 bash# netstat -nvr Kernel IP routing table Destination Gateway Genmask Flags MSS Window irtt Iface 2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo 1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo 192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0 0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0 bash# zebra# sh ip route Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - ISIS, B - BGP, > - selected route, * - FIB route K>* 0.0.0.0/0 via 192.168.0.2, eth0 K>* 1.1.1.1/32 via 127.0.0.1, lo K * 2.2.2.2/32 via 1.1.1.1, lo inactive C>* 127.0.0.0/8 is directly connected, lo C>* 192.168.0.0/24 is directly connected, eth0 quagga-pimd-router# sh ip route 1.1.1.1 Address NextHop Interface Metric Preference 1.1.1.1 127.0.0.1 lo 0 0 quagga-pimd-router# quagga-pimd-router# sh ip route 2.2.2.2 Address NextHop Interface Metric Preference 2.2.2.2 192.168.0.2 eth0 0 0 quagga-pimd-router# T27 DONE Implement debug command test pim receive assert See also TODO T6: (S,G) Assert state machine. T28 DONE Bad IPv4 address family=02 in Join/Prune dump Reported by Andrew Lunn # 58-byte pim v2 Join/Prune dump # ------------------------------ # IPv4 address family=02 is wrong, correct IPv4 address family is 01 # See http://www.iana.org/assignments/address-family-numbers # c8XX YY03 : ip src 200.xx.yy.3 e000 000d : ip dst 224.0.0.13 9404 0000 : ip router alert option 148.4.0.0 2300 ab13 : pimv2,type=3 res=00 checksum=ab13 0200 : upstream family=02, encoding=00 c8XX YY08 : upstream 200.xx.yy.8 0001 00d2 : res=00 groups=01 holdtime=00d2 0200 0020 : group family=02, encoding=00, res=00, mask_len=20 ef01 0101 : group address 239.1.1.1 0001 0000 : joined=0001 pruned=0000 0200 0020 : source family=02, encoding=00, res=00, mask_len=20 0101 0101 : source address 1.1.1.1 T29 DONE Reset interface PIM-hello-sent counter when primary address changes See pim_ifp->pim_ifstat_hello_sent RFC 4601: 4.3.1. Sending Hello Messages Thus, if a router needs to send a Join/Prune or Assert message on an interface on which it has not yet sent a Hello message with the currently configured IP address, then it MUST immediately send the relevant Hello message without waiting for the Hello Timer to expire, followed by the Join/Prune or Assert message. T30 DONE Run interface DR election when primary address changes Reported by Andrew Lunn See pim_if_dr_election(). T31 If an interface changes one of its secondary IP addresses, a Hello message with an updated Address_List option and a non-zero HoldTime should be sent immediately. See also detect_secondary_address_change See also CAVEAT C15. See also RFC 4601: 4.3.1. Sending Hello Messages T32 FIXED Detection of interface primary address changes may fail when there are multiple addresses. See also CAVEAT C14. pim_find_primary_addr() should return interface primary address from connected list. Currently it returns the first address. Zebra daemon "show int" is able to keep the primary address as first address. T33 DONE Implement debug command: test pim receive upcall See also TODO T6: (S,G) Assert state machine. T34 DONE assert_action_a1 T35 DONE Review macros depending on interface I. See also: grep ,I\) pimd/*.c For the case (S,G,I) check if I is either 1) interface attached to this per-interface S,G state (don't think so) or 2) an arbitrary interface (most probably) For the arbitrary interface case (2), consider representing interface ifp as its primary address (struct in_addr ifaddr). The benefit is in_addr does not need to be dereferenced, so it does not demand protection against crashes. T36 DONE React to zebra daemon link-detect up/down notification. pim_ifp->primary_address is managed by detect_primary_address_change() depending on to ifp->connected (managed by zebra_interface_address_read()). T37 DONE Review list of variables which may affect pim_upstream.c pim_upstream_evaluate_join_desired(). Call pim_upstream_update_join_desired() accordingly. See the order of invokation: pim_if_dr_election(ifp); pim_if_update_join_desired(pim_ifp); /* depends on DR */ pim_if_update_could_assert(ifp); /* depends on DR */ pim_if_update_my_assert_metric(ifp); /* depends on could_assert */ join_desired depends on: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->ifassert_winner_metric ch->ifassert_winner ch->local_ifmembership ch->ifjoin_state ch->upstream->rpf.source_nexthop.mrib_metric_preference ch->upstream->rpf.source_nexthop.mrib_route_metric ch->upstream->rpf.source_nexthop.interface T38 DONE Detect change in AssertTrackingDesired(S,G,I) See the order of invokation: dr_election: none update_join_desired: depends on DR update_tracking_desired: depends on DR, join_desired AssertTrackingDesired(S,G,I) depends on: pim_ifp->primary_address pim_ifp->pim_dr_addr ch->local_ifmembership ch->ifassert_winner ch->ifjoin_state ch->upstream->rpf.source_nexthop.interface PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags) T39 DONE AssertTrackingDesired: flags is not matching evaluation # show ip pim assert-internal CA: CouldAssert ECA: Evaluate CouldAssert ATD: AssertTrackingDesired eATD: Evaluate AssertTrackingDesired Interface Address Source Group CA eCA ATD eATD eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes # T40 Lightweight MLDv2 http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05 http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt http://www.ietf.org/html.charters/mboned-charter.html T41 DONE ssmping support See also: http://www.venaas.no/multicast/ssmping/ draft-ietf-mboned-ssmping-07 http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07 Example: debug ssmpingd conf t ip ssmpingd 1.1.1.1 show ip ssmpingd T42 Static igmp join fails when loading config at boot time ! Wrong behavior seen at boot time: ! 2010/02/22 08:59:00 PIM: igmp_source_forward_start: ignoring request for looped MFC entry (S,G)=(3.3.3.3,239.3.3.3): igmp_sock=12 oif=eth0 vif_index=2 ! Correct behavior seen later: ! 2010/02/22 09:03:16 PIM: igmp_source_forward_start: ignoring request for looped MFC entry (S,G)=(2.2.2.2,239.2.2.2): igmp_sock=17 oif=lo vif_index=1 ! To see the wrong message at boot: ! debug igmp trace ! interface lo ip igmp ip igmp join 239.2.2.2 2.2.2.2 ip igmp join 239.3.3.3 3.3.3.3 ! ! Interfaces indexes: Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut eth0 200.202.112.3 2 2 0 0 0 0 lo 127.0.0.1 1 1 0 0 0 0 T43 PIM Neighbor Reduction https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/ "In a transit LAN (no directly connected source or receiver), many of the PIM procedures don't apply. (...) This proposal describes a procedure to reduce the amount of neighbors established over a transit LAN." T44 Single Stream Multicast Fast Reroute (SMFR) Method https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/ "This document proposes an IP multicast fast convergence method based on differentiating primary and backup PIM join." T45 RFC5384 - The Join Attribute Format "This document describes a modification of the Join message that allows a node to associate attributes with a particular tree." T46 PIM Multi-Topology ID (MT-ID) Join-Attribute http://tools.ietf.org/html/draft-cai-pim-mtid-00 Depends on T45. "This draft introduces a new type of PIM Join Attribute used to encode the identity of the topology PIM uses for RPF." -x- quagga-0.99.24.1/pimd/README0000644000175000017500000001055512476520570012053 00000000000000# # $QuaggaId: $Format:%an, %ai, %h$ $ # INTRODUCTION qpimd aims to implement a PIM (Protocol Independent Multicast) daemon for the Quagga Routing Suite. Initially qpimd targets only PIM SSM (Source-Specific Multicast) mode as defined in section 4.8.2 (PIM-SSM-Only Routers) of RFC 4601. In order to deliver end-to-end multicast routing control plane, qpimd includes the router-side of IGMPv3 (RFC 3376). LICENSE qpimd - pimd for quagga Copyright (C) 2008 Everton da Silva Marques qpimd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. qpimd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with qpimd; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. HOME SITE qpimd lives at: https://github.com/udhos/qpimd PLATFORMS qpimd has been tested with Debian Lenny under Linux 2.6. REQUIREMENTS qpimd requires Quagga (0.99.11 or higher from http://www.quagga.net) The GNU Build System (Autotools) is required to build from source code repository. gawk is also needed to build with Autotools. Any other awk usually won't work. BUILDING FROM QUAGGA GIT REPOSITORY 1) Get the latest quagga source tree # git clone git://code.quagga.net/quagga.git quagga 2) Apply qpimd patch into quagga source tree # patch -p1 -d quagga < pimd-0.153-quagga-git20090623.patch 3) Compile and install quagga # cd quagga # ./bootstrap.sh # ./configure --prefix=/usr/local/quagga --enable-pimd # make # make install BUILDING FROM QUAGGA TARBALL 1) Get the latest quagga tarball # wget http://www.quagga.net/download/quagga-0.99.13.tar.gz 2) Unpack the quagga tarball # tar xzf quagga-0.99.13.tar.gz 3) Apply qpimd patch into quagga source tree # patch -p1 -d quagga-0.99.13 < pimd-0.153-quagga-0.99.13.patch 4) Compile and install quagga # cd quagga-0.99.13 # ./configure --prefix=/usr/local/quagga --enable-pimd # make # make install USAGE 1) Configure and start the zebra daemon # cp /usr/local/quagga/etc/zebra.conf.sample /usr/local/quagga/etc/zebra.conf # vi /usr/local/quagga/etc/zebra.conf # /usr/local/quagga/sbin/zebra 2) Configure and start the pimd daemon # cp /usr/local/quagga/etc/pimd.conf.sample /usr/local/quagga/etc/pimd.conf # vi /usr/local/quagga/etc/pimd.conf # /usr/local/quagga/sbin/pimd 3) Access pimd vty interface at port TCP 2611 # telnet localhost 2611 CONFIGURATION COMMANDS See available commands in the file pimd/COMMANDS. KNOWN CAVEATS See list of known caveats in the file pimd/CAVEATS. SUPPORT Please post comments, questions, patches, bug reports at the support site: https://github.com/udhos/qpimd RELATED WORK igmprt: An IGMPv3-router implementation - http://www.loria.fr/~lahmadi/igmpv3-router.html USC pimd: PIMv2-SM daemon - http://netweb.usc.edu/pim/pimd (URL broken in 2008-12-23) - http://packages.debian.org/source/sid/pimd (from Debian) troglobit pimd: This is the original USC pimd from http://netweb.usc.edu/pim/. In January 16, 2010 it was revived with the intention to collect patches floating around in Debian, Gentoo, Lintrack and other distribution repositories and to provide a central point of collaboration. - http://github.com/troglobit/pimd zpimd: zpimd is not dependent of zebra or any other routing daemon - ftp://robur.slu.se/pub/Routing/Zebra - http://sunsite2.icm.edu.pl/pub/unix/routing/zpimd mrd6: an IPv6 Multicast Router for Linux systems - http://fivebits.net/proj/mrd6/ MBGP: Implementation of RFC 2858 for Quagga - git://git.coplanar.net/~balajig/quagga - http://www.gossamer-threads.com/lists/quagga/dev/18000 REFERENCES IANA Protocol Independent Multicast (PIM) Parameters http://www.iana.org/assignments/pim-parameters/pim-parameters.txt Address Family Numbers http://www.iana.org/assignments/address-family-numbers -- END -- quagga-0.99.24.1/pimd/COPYING0000644000175000017500000004313312476520570012224 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. quagga-0.99.24.1/pimd/AUTHORS0000644000175000017500000000030612476520570012234 00000000000000# $QuaggaId: $Format:%an, %ai, %h$ $ # Everton da Silva Marques $ more ~/.gitconfig [user] name = Everton Marques email = everton.marques@gmail.com -x- quagga-0.99.24.1/pimd/pim_int.h0000644000175000017500000000200012476520570012765 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_INT_H #define PIM_INT_H #include uint32_t pim_read_uint32_host(const uint8_t *buf); void pim_write_uint32(uint8_t *buf, uint32_t val_host); #endif /* PIM_INT_H */ quagga-0.99.24.1/pimd/pim_ssmpingd.h0000644000175000017500000000262612476520570014035 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SSMPINGD_H #define PIM_SSMPINGD_H #include #include "if.h" #include "pim_iface.h" struct ssmpingd_sock { int sock_fd; /* socket */ struct thread *t_sock_read; /* thread for reading socket */ struct in_addr source_addr; /* source address */ int64_t creation; /* timestamp of socket creation */ int64_t requests; /* counter */ }; void pim_ssmpingd_init(void); void pim_ssmpingd_destroy(void); int pim_ssmpingd_start(struct in_addr source_addr); int pim_ssmpingd_stop(struct in_addr source_addr); #endif /* PIM_SSMPINGD_H */ quagga-0.99.24.1/pimd/pim_igmp_join.h0000644000175000017500000000203112476520570014152 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMP_JOIN_H #define PIM_IGMP_JOIN_H #include int pim_igmp_join_source(int fd, int ifindex, struct in_addr group_addr, struct in_addr source_addr); #endif /* PIM_IGMP_JOIN_H */ quagga-0.99.24.1/pimd/pim_macro.h0000644000175000017500000000320212476520570013301 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MACRO_H #define PIM_MACRO_H #include #include "if.h" #include "pim_upstream.h" #include "pim_ifchannel.h" int pim_macro_ch_lost_assert(const struct pim_ifchannel *ch); int pim_macro_chisin_joins(const struct pim_ifchannel *ch); int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch); int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch); int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch); struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, struct in_addr ifaddr); struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch); int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch); int pim_macro_assert_tracking_desired_eval(const struct pim_ifchannel *ch); #endif /* PIM_MACRO_H */ quagga-0.99.24.1/pimd/pim_rand.h0000644000175000017500000000172712476520570013136 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_RAND_H #define PIM_RAND_H void pim_rand_init(void); long pim_rand(void); int pim_rand_next(int min, int max); #endif /* PIM_RAND_H */ quagga-0.99.24.1/pimd/pim_rpf.h0000644000175000017500000000217612476520570013000 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_RPF_H #define PIM_RPF_H #include #include "pim_upstream.h" #include "pim_neighbor.h" int pim_nexthop_lookup(struct pim_nexthop *nexthop, struct in_addr addr); enum pim_rpf_result pim_rpf_update(struct pim_upstream *up, struct in_addr *old_rpf_addr); #endif /* PIM_RPF_H */ quagga-0.99.24.1/pimd/pim_upstream.h0000644000175000017500000001050612476520570014045 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_UPSTREAM_H #define PIM_UPSTREAM_H #include #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED (1 << 0) #define PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED (2 << 0) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) /* RFC 4601: Metric Preference Preference value assigned to the unicast routing protocol that provided the route to the multicast source or Rendezvous-Point. Metric The unicast routing table metric associated with the route used to reach the multicast source or Rendezvous-Point. The metric is in units applicable to the unicast routing protocol used. */ struct pim_nexthop { struct interface *interface; /* RPF_interface(S) */ struct in_addr mrib_nexthop_addr; /* MRIB.next_hop(S) */ uint32_t mrib_metric_preference; /* MRIB.pref(S) */ uint32_t mrib_route_metric; /* MRIB.metric(S) */ }; struct pim_rpf { struct pim_nexthop source_nexthop; struct in_addr rpf_addr; /* RPF'(S,G) */ }; enum pim_rpf_result { PIM_RPF_OK = 0, PIM_RPF_CHANGED, PIM_RPF_FAILURE }; enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, PIM_UPSTREAM_JOINED }; /* Upstream (S,G) channel in Joined state (S,G) in the "Not Joined" state is not represented See RFC 4601: 4.5.7. Sending (S,G) Join/Prune Message */ struct pim_upstream { struct in_addr source_addr; /* (S,G) source key */ struct in_addr group_addr; /* (S,G) group key */ uint32_t flags; struct channel_oil *channel_oil; enum pim_upstream_state join_state; int ref_count; struct pim_rpf rpf; struct thread *t_join_timer; int64_t state_transition; /* Record current state uptime */ }; void pim_upstream_free(struct pim_upstream *up); void pim_upstream_delete(struct pim_upstream *up); struct pim_upstream *pim_upstream_find(struct in_addr source_addr, struct in_addr group_addr); struct pim_upstream *pim_upstream_add(struct in_addr source_addr, struct in_addr group_addr); void pim_upstream_del(struct pim_upstream *up); int pim_upstream_evaluate_join_desired(struct pim_upstream *up); void pim_upstream_update_join_desired(struct pim_upstream *up); void pim_upstream_join_suppress(struct pim_upstream *up, struct in_addr rpf_addr, int holdtime); void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_upstream *up, struct in_addr rpf_addr); void pim_upstream_join_timer_restart(struct pim_upstream *up); void pim_upstream_rpf_genid_changed(struct in_addr neigh_addr); void pim_upstream_rpf_interface_changed(struct pim_upstream *up, struct interface *old_rpf_ifp); void pim_upstream_update_could_assert(struct pim_upstream *up); void pim_upstream_update_my_assert_metric(struct pim_upstream *up); #endif /* PIM_UPSTREAM_H */ quagga-0.99.24.1/pimd/pim_msg.h0000644000175000017500000000306212476520570012772 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MSG_H #define PIM_MSG_H #include /* Number Description ---------- ------------------ 0 Reserved 1 IP (IP version 4) 2 IP6 (IP version 6) From: http://www.iana.org/assignments/address-family-numbers */ #define PIM_MSG_ADDRESS_FAMILY_IPV4 (1) void pim_msg_build_header(uint8_t *pim_msg, int pim_msg_size, uint8_t pim_msg_type); uint8_t *pim_msg_addr_encode_ipv4_ucast(uint8_t *buf, int buf_size, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_group(uint8_t *buf, int buf_size, struct in_addr addr); uint8_t *pim_msg_addr_encode_ipv4_source(uint8_t *buf, int buf_size, struct in_addr addr); #endif /* PIM_MSG_H */ quagga-0.99.24.1/pimd/pim_assert.h0000644000175000017500000000454712476520570013516 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ASSERT_H #define PIM_ASSERT_H #include #include "if.h" #include "pim_neighbor.h" #include "pim_ifchannel.h" /* RFC 4601: 4.11. Timer Values Note that for historical reasons, the Assert message lacks a Holdtime field. Thus, changing the Assert Time from the default value is not recommended. */ #define PIM_ASSERT_OVERRIDE_INTERVAL (3) /* seconds */ #define PIM_ASSERT_TIME (180) /* seconds */ #define PIM_ASSERT_METRIC_PREFERENCE_MAX (0xFFFFFFFF) #define PIM_ASSERT_ROUTE_METRIC_MAX (0xFFFFFFFF) void pim_ifassert_winner_set(struct pim_ifchannel *ch, enum pim_ifassert_state new_state, struct in_addr winner, struct pim_assert_metric winner_metric); int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *buf, int buf_size); int pim_assert_metric_better(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_metric_match(const struct pim_assert_metric *m1, const struct pim_assert_metric *m2); int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr, uint32_t metric_preference, uint32_t route_metric, uint32_t rpt_bit_flag); int pim_assert_send(struct pim_ifchannel *ch); int assert_action_a1(struct pim_ifchannel *ch); void assert_action_a4(struct pim_ifchannel *ch); void assert_action_a5(struct pim_ifchannel *ch); #endif /* PIM_ASSERT_H */ quagga-0.99.24.1/pimd/pim_join.h0000644000175000017500000000243612476520570013147 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_JOIN_H #define PIM_JOIN_H #include #include "if.h" #include "pim_neighbor.h" int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_joinprune_send(struct interface *ifp, struct in_addr upstream_addr, struct in_addr source_addr, struct in_addr group_addr, int send_join); #endif /* PIM_JOIN_H */ quagga-0.99.24.1/pimd/pim_ifchannel.h0000644000175000017500000001217212476520570014135 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IFCHANNEL_H #define PIM_IFCHANNEL_H #include #include "if.h" #include "pim_upstream.h" enum pim_ifmembership { PIM_IFMEMBERSHIP_NOINFO, PIM_IFMEMBERSHIP_INCLUDE }; enum pim_ifjoin_state { PIM_IFJOIN_NOINFO, PIM_IFJOIN_JOIN, PIM_IFJOIN_PRUNE_PENDING }; enum pim_ifassert_state { PIM_IFASSERT_NOINFO, PIM_IFASSERT_I_AM_WINNER, PIM_IFASSERT_I_AM_LOSER }; struct pim_assert_metric { uint32_t rpt_bit_flag; uint32_t metric_preference; uint32_t route_metric; struct in_addr ip_address; /* neighbor router that sourced the Assert message */ }; /* Flag to detect change in CouldAssert(S,G,I) */ #define PIM_IF_FLAG_MASK_COULD_ASSERT (1 << 0) #define PIM_IF_FLAG_TEST_COULD_ASSERT(flags) ((flags) & PIM_IF_FLAG_MASK_COULD_ASSERT) #define PIM_IF_FLAG_SET_COULD_ASSERT(flags) ((flags) |= PIM_IF_FLAG_MASK_COULD_ASSERT) #define PIM_IF_FLAG_UNSET_COULD_ASSERT(flags) ((flags) &= ~PIM_IF_FLAG_MASK_COULD_ASSERT) /* Flag to detect change in AssertTrackingDesired(S,G,I) */ #define PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED (1 << 1) #define PIM_IF_FLAG_TEST_ASSERT_TRACKING_DESIRED(flags) ((flags) & PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_SET_ASSERT_TRACKING_DESIRED(flags) ((flags) |= PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) #define PIM_IF_FLAG_UNSET_ASSERT_TRACKING_DESIRED(flags) ((flags) &= ~PIM_IF_FLAG_MASK_ASSERT_TRACKING_DESIRED) /* Per-interface (S,G) state */ struct pim_ifchannel { struct in_addr source_addr; /* (S,G) source key */ struct in_addr group_addr; /* (S,G) group key */ struct interface *interface; /* backpointer to interface */ uint32_t flags; /* IGMPv3 determined interface has local members for (S,G) ? */ enum pim_ifmembership local_ifmembership; /* Per-interface (S,G) Join/Prune State (Section 4.1.4 of RFC4601) */ enum pim_ifjoin_state ifjoin_state; struct thread *t_ifjoin_expiry_timer; struct thread *t_ifjoin_prune_pending_timer; int64_t ifjoin_creation; /* Record uptime of ifjoin state */ /* Per-interface (S,G) Assert State (Section 4.6.1 of RFC4601) */ enum pim_ifassert_state ifassert_state; struct thread *t_ifassert_timer; struct in_addr ifassert_winner; struct pim_assert_metric ifassert_winner_metric; int64_t ifassert_creation; /* Record uptime of ifassert state */ struct pim_assert_metric ifassert_my_metric; /* Upstream (S,G) state */ struct pim_upstream *upstream; }; void pim_ifchannel_free(struct pim_ifchannel *ch); void pim_ifchannel_delete(struct pim_ifchannel *ch); void pim_ifchannel_membership_clear(struct interface *ifp); void pim_ifchannel_delete_on_noinfo(struct interface *ifp); struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime); void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, struct in_addr source_addr, struct in_addr group_addr, uint8_t source_flags, uint16_t holdtime); void pim_ifchannel_local_membership_add(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_local_membership_del(struct interface *ifp, struct in_addr source_addr, struct in_addr group_addr); void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state); const char *pim_ifchannel_ifjoin_name(enum pim_ifjoin_state ifjoin_state); const char *pim_ifchannel_ifassert_name(enum pim_ifassert_state ifassert_state); int pim_ifchannel_isin_oiflist(struct pim_ifchannel *ch); void reset_ifassert_state(struct pim_ifchannel *ch); void pim_ifchannel_update_could_assert(struct pim_ifchannel *ch); void pim_ifchannel_update_my_assert_metric(struct pim_ifchannel *ch); void pim_ifchannel_update_assert_tracking_desired(struct pim_ifchannel *ch); #endif /* PIM_IFCHANNEL_H */ quagga-0.99.24.1/pimd/pim_hello.h0000644000175000017500000000255412476520570013314 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_HELLO_H #define PIM_HELLO_H #include #include "if.h" int pim_hello_recv(struct interface *ifp, struct in_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size); int pim_hello_build_tlv(const char *ifname, uint8_t *tlv_buf, int tlv_buf_size, uint16_t holdtime, uint32_t dr_priority, uint32_t generation_id, uint16_t propagation_delay, uint16_t override_interval, int can_disable_join_suppression, struct list *ifconnected); void pim_hello_require(struct interface *ifp); #endif /* PIM_HELLO_H */ quagga-0.99.24.1/pimd/pim_neighbor.h0000644000175000017500000000501012476520570013774 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_NEIGHBOR_H #define PIM_NEIGHBOR_H #include #include "if.h" #include "linklist.h" #include "pim_tlv.h" struct pim_neighbor { int64_t creation; /* timestamp of creation */ struct in_addr source_addr; pim_hello_options hello_options; uint16_t holdtime; uint16_t propagation_delay_msec; uint16_t override_interval_msec; uint32_t dr_priority; uint32_t generation_id; struct list *prefix_list; /* list of struct prefix */ struct thread *t_expire_timer; struct interface *interface; }; void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, struct in_addr source_addr); struct pim_neighbor *pim_neighbor_add(struct interface *ifp, struct in_addr source_addr, pim_hello_options hello_options, uint16_t holdtime, uint16_t propagation_delay, uint16_t override_interval, uint32_t dr_priority, uint32_t generation_id, struct list *addr_list); void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh, const char *delete_message); void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message); void pim_neighbor_update(struct pim_neighbor *neigh, pim_hello_options hello_options, uint16_t holdtime, uint32_t dr_priority, struct list *addr_list); struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh, struct in_addr addr); void pim_if_dr_election(struct interface *ifp); #endif /* PIM_NEIGHBOR_H */ quagga-0.99.24.1/pimd/pim_tlv.h0000644000175000017500000001230212476520570013006 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_TLV_H #define PIM_TLV_H #include #include "config.h" #include "if.h" #include "linklist.h" #ifdef HAVE_INTTYPES_H #include #endif /* HAVE_INTTYPES_H */ #define PIM_MSG_OPTION_TYPE_HOLDTIME (1) #define PIM_MSG_OPTION_TYPE_LAN_PRUNE_DELAY (2) #define PIM_MSG_OPTION_TYPE_DR_PRIORITY (19) #define PIM_MSG_OPTION_TYPE_GENERATION_ID (20) #define PIM_MSG_OPTION_TYPE_DM_STATE_REFRESH (21) #define PIM_MSG_OPTION_TYPE_ADDRESS_LIST (24) typedef uint32_t pim_hello_options; #define PIM_OPTION_MASK_HOLDTIME (1 << 0) /* recv holdtime */ #define PIM_OPTION_MASK_LAN_PRUNE_DELAY (1 << 1) /* recv lan_prune_delay */ #define PIM_OPTION_MASK_DR_PRIORITY (1 << 2) /* recv dr_priority */ #define PIM_OPTION_MASK_GENERATION_ID (1 << 3) /* recv generation_id */ #define PIM_OPTION_MASK_ADDRESS_LIST (1 << 4) /* recv secondary address list */ #define PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION (1 << 5) /* T bit value (valid if recv lan_prune_delay) */ #define PIM_RPT_BIT_MASK (1 << 0) #define PIM_WILDCARD_BIT_MASK (1 << 1) #define PIM_OPTION_SET(options, option_mask) ((options) |= (option_mask)) #define PIM_OPTION_UNSET(options, option_mask) ((options) &= ~(option_mask)) #define PIM_OPTION_IS_SET(options, option_mask) ((options) & (option_mask)) #define PIM_TLV_GET_UINT16(buf) ntohs(*(const uint16_t *)(buf)) #define PIM_TLV_GET_UINT32(buf) ntohl(*(const uint32_t *)(buf)) #define PIM_TLV_GET_TYPE(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_LENGTH(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_HOLDTIME(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_PROPAGATION_DELAY(buf) (PIM_TLV_GET_UINT16(buf) & 0x7FFF) #define PIM_TLV_GET_OVERRIDE_INTERVAL(buf) PIM_TLV_GET_UINT16(buf) #define PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(buf) ((*(const uint8_t *)(buf)) & 0x80) #define PIM_TLV_GET_DR_PRIORITY(buf) PIM_TLV_GET_UINT32(buf) #define PIM_TLV_GET_GENERATION_ID(buf) PIM_TLV_GET_UINT32(buf) #define PIM_TLV_TYPE_SIZE (2) #define PIM_TLV_LENGTH_SIZE (2) #define PIM_TLV_MIN_SIZE (PIM_TLV_TYPE_SIZE + PIM_TLV_LENGTH_SIZE) #define PIM_TLV_OPTION_SIZE(option_len) (PIM_TLV_MIN_SIZE + (option_len)) uint8_t *pim_tlv_append_uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value); uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint16_t option_value1, uint16_t option_value2); uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend, uint16_t option_type, uint32_t option_value); uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend, struct list *ifconnected); int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_holdtime, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint16_t *hello_option_propagation_delay, uint16_t *hello_option_override_interval, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_dr_priority, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, uint32_t *hello_option_generation_id, uint16_t option_len, const uint8_t *tlv_curr); int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, pim_hello_options *hello_options, struct list **hello_option_addr_list, uint16_t option_len, const uint8_t *tlv_curr); int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size); int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, struct prefix *p, const uint8_t *buf, int buf_size); int pim_parse_addr_source(const char *ifname, struct in_addr src_addr, struct prefix *p, uint8_t *flags, const uint8_t *buf, int buf_size); #endif /* PIM_TLV_H */ quagga-0.99.24.1/pimd/pim_pim.h0000644000175000017500000000534612476520570013000 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_PIM_H #define PIM_PIM_H #include #include "if.h" #define PIM_PIM_BUFSIZE_READ (20000) #define PIM_PIM_BUFSIZE_WRITE (20000) #define PIM_NEXTHOP_IFINDEX_TAB_SIZE (20) #define PIM_DEFAULT_HELLO_PERIOD (30) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_TRIGGERED_HELLO_DELAY (5) /* seconds, RFC 4601: 4.11 */ #define PIM_DEFAULT_DR_PRIORITY (1) /* RFC 4601: 4.3.1 */ #define PIM_DEFAULT_PROPAGATION_DELAY_MSEC (500) /* RFC 4601: 4.11. Timer Values */ #define PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC (2500) /* RFC 4601: 4.11. Timer Values */ #define PIM_DEFAULT_CAN_DISABLE_JOIN_SUPPRESSION (0) /* boolean */ #define PIM_DEFAULT_T_PERIODIC (60) /* RFC 4601: 4.11. Timer Values */ #define PIM_MSG_TYPE_HELLO (0) #define PIM_MSG_TYPE_JOIN_PRUNE (3) #define PIM_MSG_TYPE_ASSERT (5) #define PIM_MSG_HDR_OFFSET_VERSION(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_TYPE(pim_msg) (pim_msg) #define PIM_MSG_HDR_OFFSET_RESERVED(pim_msg) (((char *)(pim_msg)) + 1) #define PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg) (((char *)(pim_msg)) + 2) #define PIM_MSG_HDR_GET_VERSION(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_VERSION(pim_msg)) >> 4) #define PIM_MSG_HDR_GET_TYPE(pim_msg) ((*(uint8_t*) PIM_MSG_HDR_OFFSET_TYPE(pim_msg)) & 0xF) #define PIM_MSG_HDR_GET_CHECKSUM(pim_msg) (*(uint16_t*) PIM_MSG_HDR_OFFSET_CHECKSUM(pim_msg)) void pim_ifstat_reset(struct interface *ifp); void pim_sock_reset(struct interface *ifp); int pim_sock_add(struct interface *ifp); void pim_sock_delete(struct interface *ifp, const char *delete_message); void pim_hello_restart_now(struct interface *ifp); void pim_hello_restart_triggered(struct interface *ifp); int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len); int pim_msg_send(int fd, struct in_addr dst, uint8_t *pim_msg, int pim_msg_size, const char *ifname); #endif /* PIM_PIM_H */ quagga-0.99.24.1/pimd/pim_zlookup.h0000644000175000017500000000256412476520570013715 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ZLOOKUP_H #define PIM_ZLOOKUP_H #include #include "zclient.h" #define PIM_NEXTHOP_LOOKUP_MAX (3) /* max. recursive route lookup */ struct pim_zlookup_nexthop { struct in_addr nexthop_addr; int ifindex; uint32_t route_metric; uint8_t protocol_distance; }; struct zclient *zclient_lookup_new(void); int zclient_lookup_nexthop(struct zclient *zlookup, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, int max_lookup); #endif /* PIM_ZLOOKUP_H */ quagga-0.99.24.1/pimd/pim_oil.h0000644000175000017500000000322012476520570012763 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_OIL_H #define PIM_OIL_H #include "pim_mroute.h" #define PIM_OIF_FLAG_PROTO_IGMP (1 << 0) /* bitmask 1 */ #define PIM_OIF_FLAG_PROTO_PIM (1 << 1) /* bitmask 2 */ #define PIM_OIF_FLAG_PROTO_ANY (3) /* bitmask (1 | 2) */ /* qpim_channel_oil_list holds a list of struct channel_oil. Each channel_oil.oil is used to control an (S,G) entry in the Kernel Multicast Forwarding Cache. */ struct channel_oil { struct mfcctl oil; int oil_size; int oil_ref_count; time_t oif_creation[MAXVIFS]; uint32_t oif_flags[MAXVIFS]; }; void pim_channel_oil_free(struct channel_oil *c_oil); struct channel_oil *pim_channel_oil_add(struct in_addr group_addr, struct in_addr source_addr, int input_vif_index); void pim_channel_oil_del(struct channel_oil *c_oil); #endif /* PIM_OIL_H */ quagga-0.99.24.1/pimd/pim_time.h0000644000175000017500000000264212476520570013145 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_TIME_H #define PIM_TIME_H #include #include #include "thread.h" int64_t pim_time_monotonic_sec(void); int64_t pim_time_monotonic_dsec(void); int pim_time_mmss(char *buf, int buf_size, long sec); void pim_time_timer_to_mmss(char *buf, int buf_size, struct thread *t); void pim_time_timer_to_hhmmss(char *buf, int buf_size, struct thread *t); void pim_time_uptime(char *buf, int buf_size, int64_t uptime_sec); void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin); long pim_time_timer_remain_msec(struct thread *t_timer); #endif /* PIM_TIME_H */ quagga-0.99.24.1/pimd/pim_util.h0000644000175000017500000000214312476520570013160 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_UTIL_H #define PIM_UTIL_H #include #include #include "checksum.h" uint8_t igmp_msg_encode16to8(uint16_t value); uint16_t igmp_msg_decode8to16(uint8_t code); void pim_pkt_dump(const char *label, const uint8_t *buf, int size); #endif /* PIM_UTIL_H */ quagga-0.99.24.1/pimd/pim_mroute.h0000644000175000017500000001170212476520570013517 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_MROUTE_H #define PIM_MROUTE_H /* For msghdr.msg_control in Solaris 10 */ #ifndef _XPG4_2 #define _XPG4_2 #endif #ifndef __EXTENSIONS__ #define __EXTENSIONS__ #endif #include #ifdef HAVE_NETINET_IP_MROUTE_H #include #endif #define PIM_MROUTE_MIN_TTL (1) /* Below: from */ #ifndef MAXVIFS #define MAXVIFS (32) #endif #ifndef SIOCGETVIFCNT #define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) #define SIOCGETRPF (SIOCPROTOPRIVATE+2) #endif #ifndef MRT_INIT #define MRT_BASE 200 #define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ #define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ #define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ #define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ #define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ #define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ #define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ #define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ #define MRT_PIM (MRT_BASE+8) /* enable PIM code */ #endif #ifndef HAVE_VIFI_T typedef unsigned short vifi_t; #endif #ifndef HAVE_STRUCT_VIFCTL struct vifctl { vifi_t vifc_vifi; /* Index of VIF */ unsigned char vifc_flags; /* VIFF_ flags */ unsigned char vifc_threshold; /* ttl limit */ unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ struct in_addr vifc_lcl_addr; /* Our address */ struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ }; #endif #ifndef HAVE_STRUCT_MFCCTL struct mfcctl { struct in_addr mfcc_origin; /* Origin of mcast */ struct in_addr mfcc_mcastgrp; /* Group in question */ vifi_t mfcc_parent; /* Where it arrived */ unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ unsigned int mfcc_byte_cnt; unsigned int mfcc_wrong_if; int mfcc_expire; }; #endif /* * Group count retrieval for mrouted */ /* struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src)); memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp)); ioctl(mrouter_s4, SIOCGETSGCNT, &sgreq); */ #ifndef HAVE_STRUCT_SIOC_SG_REQ struct sioc_sg_req { struct in_addr src; struct in_addr grp; unsigned long pktcnt; unsigned long bytecnt; unsigned long wrong_if; }; #endif /* * To get vif packet counts */ /* struct sioc_vif_req vreq; memset(&vreq, 0, sizeof(vreq)); vreq.vifi = vif_index; ioctl(mrouter_s4, SIOCGETVIFCNT, &vreq); */ #ifndef HAVE_STRUCT_SIOC_VIF_REQ struct sioc_vif_req { vifi_t vifi; /* Which iface */ unsigned long icount; /* In packets */ unsigned long ocount; /* Out packets */ unsigned long ibytes; /* In bytes */ unsigned long obytes; /* Out bytes */ }; #endif /* * Pseudo messages used by mrouted */ #ifndef IGMPMSG_NOCACHE #define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ #define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ #endif #ifndef HAVE_STRUCT_IGMPMSG struct igmpmsg { uint32_t unused1,unused2; unsigned char im_msgtype; /* What is this */ unsigned char im_mbz; /* Must be zero */ unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ unsigned char unused3; struct in_addr im_src,im_dst; }; #endif /* Above: from */ int pim_mroute_socket_enable(void); int pim_mroute_socket_disable(void); int pim_mroute_add_vif(int vif_index, struct in_addr ifaddr); int pim_mroute_del_vif(int vif_index); int pim_mroute_add(struct mfcctl *mc); int pim_mroute_del(struct mfcctl *mc); int pim_mroute_msg(int fd, const char *buf, int buf_size); #endif /* PIM_MROUTE_H */ quagga-0.99.24.1/pimd/pim_str.h0000644000175000017500000000201612476520570013012 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_STR_H #define PIM_STR_H #include #include #include void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); #endif quagga-0.99.24.1/pimd/pim_igmpv3.h0000644000175000017500000000721212476520570013412 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMPV3_H #define PIM_IGMPV3_H #include #include "if.h" #define IGMP_V3_CHECKSUM_OFFSET (2) #define IGMP_V3_REPORT_NUMGROUPS_OFFSET (6) #define IGMP_V3_REPORT_GROUPPRECORD_OFFSET (8) #define IGMP_V3_NUMSOURCES_OFFSET (10) #define IGMP_V3_SOURCES_OFFSET (12) /* GMI: Group Membership Interval */ #define PIM_IGMP_GMI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * (qri_dsec)) /* OQPI: Other Querier Present Interval */ #define PIM_IGMP_OQPI_MSEC(qrv,qqi,qri_dsec) ((qrv) * (1000 * (qqi)) + 100 * ((qri_dsec) >> 1)) /* SQI: Startup Query Interval */ #define PIM_IGMP_SQI(qi) (((qi) < 4) ? 1 : ((qi) >> 2)) /* LMQT: Last Member Query Time */ #define PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc) ((lmqc) * (100 * (lmqi_dsec))) /* OHPI: Older Host Present Interval */ #define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec)) void igmp_group_reset_gmi(struct igmp_group *group); void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group, struct igmp_source *source); void igmp_source_free(struct igmp_source *source); void igmp_source_delete(struct igmp_source *source); void igmp_source_delete_expired(struct list *source_list); int igmp_group_compat_mode(const struct igmp_sock *igmp, const struct igmp_group *group); void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); void igmp_group_timer_lower_to_lmqt(struct igmp_group *group); void igmp_source_timer_lower_to_lmqt(struct igmp_source *source); struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, struct in_addr src_addr); void pim_igmp_send_membership_query(struct igmp_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval); #endif /* PIM_IGMPV3_H */ quagga-0.99.24.1/pimd/pim_zebra.h0000644000175000017500000000252412476520570013311 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_ZEBRA_H #define PIM_ZEBRA_H #include "pim_igmp.h" #include "pim_ifchannel.h" void pim_zebra_init(char *zebra_sock_path); void pim_scan_oil(void); void igmp_anysource_forward_start(struct igmp_group *group); void igmp_anysource_forward_stop(struct igmp_group *group); void igmp_source_forward_start(struct igmp_source *source); void igmp_source_forward_stop(struct igmp_source *source); void pim_forward_start(struct pim_ifchannel *ch); void pim_forward_stop(struct pim_ifchannel *ch); #endif /* PIM_ZEBRA_H */ quagga-0.99.24.1/pimd/pim_sock.h0000644000175000017500000000423112476520570013142 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SOCK_H #define PIM_SOCK_H #include #define PIM_SOCK_ERR_NONE (0) /* No error */ #define PIM_SOCK_ERR_SOCKET (-1) /* socket() */ #define PIM_SOCK_ERR_RA (-2) /* Router Alert option */ #define PIM_SOCK_ERR_REUSE (-3) /* Reuse option */ #define PIM_SOCK_ERR_TTL (-4) /* TTL option */ #define PIM_SOCK_ERR_LOOP (-5) /* Loopback option */ #define PIM_SOCK_ERR_IFACE (-6) /* Outgoing interface option */ #define PIM_SOCK_ERR_DSTADDR (-7) /* Outgoing interface option */ #define PIM_SOCK_ERR_NONBLOCK_GETFL (-8) /* Get O_NONBLOCK */ #define PIM_SOCK_ERR_NONBLOCK_SETFL (-9) /* Set O_NONBLOCK */ #define PIM_SOCK_ERR_NAME (-10) /* Socket name (getsockname) */ int pim_socket_raw(int protocol); int pim_socket_mcast(int protocol, struct in_addr ifaddr, int loop); int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr, int ifindex); int pim_socket_join_source(int fd, int ifindex, struct in_addr group_addr, struct in_addr source_addr, const char *ifname); int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len, struct sockaddr_in *from, socklen_t *fromlen, struct sockaddr_in *to, socklen_t *tolen, int *ifindex); int pim_socket_mcastloop_get(int fd); int pim_socket_getsockname(int fd, struct sockaddr *name, socklen_t *namelen); #endif /* PIM_SOCK_H */ quagga-0.99.24.1/pimd/pim_igmp.h0000644000175000017500000001456212476520570013147 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IGMP_H #define PIM_IGMP_H #include #include #include "vty.h" #include "linklist.h" /* The following sizes are likely to support any message sent within local MTU. */ #define PIM_IGMP_BUFSIZE_READ (20000) #define PIM_IGMP_BUFSIZE_WRITE (20000) #define PIM_IGMP_MEMBERSHIP_QUERY (0x11) #define PIM_IGMP_V1_MEMBERSHIP_REPORT (0x12) #define PIM_IGMP_V2_MEMBERSHIP_REPORT (0x16) #define PIM_IGMP_V2_LEAVE_GROUP (0x17) #define PIM_IGMP_V3_MEMBERSHIP_REPORT (0x22) #define IGMP_V3_REPORT_HEADER_SIZE (8) #define IGMP_V3_GROUP_RECORD_MIN_SIZE (8) #define IGMP_V3_MSG_MIN_SIZE (IGMP_V3_REPORT_HEADER_SIZE + \ IGMP_V3_GROUP_RECORD_MIN_SIZE) #define IGMP_V12_MSG_SIZE (8) #define IGMP_V3_GROUP_RECORD_TYPE_OFFSET (0) #define IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET (1) #define IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET (2) #define IGMP_V3_GROUP_RECORD_GROUP_OFFSET (4) #define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8) /* RFC 3376: 8.1. Robustness Variable - Default: 2 */ #define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2) /* RFC 3376: 8.2. Query Interval - Default: 125 seconds */ #define IGMP_GENERAL_QUERY_INTERVAL (125) /* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds */ #define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100) /* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */ #define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10) struct igmp_join { struct in_addr group_addr; struct in_addr source_addr; int sock_fd; time_t sock_creation; }; struct igmp_sock { int fd; struct interface *interface; struct in_addr ifaddr; time_t sock_creation; struct thread *t_igmp_read; /* read: IGMP sockets */ struct thread *t_igmp_query_timer; /* timer: issue IGMP general queries */ struct thread *t_other_querier_timer; /* timer: other querier present */ int querier_query_interval; /* QQI */ int querier_robustness_variable; /* QRV */ int startup_query_count; struct list *igmp_group_list; /* list of struct igmp_group */ }; struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, struct in_addr ifaddr); struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd); struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, struct in_addr ifaddr, struct interface *ifp); void igmp_sock_delete(struct igmp_sock *igmp); void igmp_sock_free(struct igmp_sock *igmp); int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len); void pim_igmp_general_query_on(struct igmp_sock *igmp); void pim_igmp_general_query_off(struct igmp_sock *igmp); void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp); void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp); #define IGMP_SOURCE_MASK_FORWARDING (1 << 0) #define IGMP_SOURCE_MASK_DELETE (1 << 1) #define IGMP_SOURCE_MASK_SEND (1 << 2) #define IGMP_SOURCE_TEST_FORWARDING(flags) ((flags) & IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_TEST_DELETE(flags) ((flags) & IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_TEST_SEND(flags) ((flags) & IGMP_SOURCE_MASK_SEND) #define IGMP_SOURCE_DO_FORWARDING(flags) ((flags) |= IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_DO_DELETE(flags) ((flags) |= IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_DO_SEND(flags) ((flags) |= IGMP_SOURCE_MASK_SEND) #define IGMP_SOURCE_DONT_FORWARDING(flags) ((flags) &= ~IGMP_SOURCE_MASK_FORWARDING) #define IGMP_SOURCE_DONT_DELETE(flags) ((flags) &= ~IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_DONT_SEND(flags) ((flags) &= ~IGMP_SOURCE_MASK_SEND) struct igmp_source { struct in_addr source_addr; struct thread *t_source_timer; struct igmp_group *source_group; /* back pointer */ time_t source_creation; uint32_t source_flags; struct channel_oil *source_channel_oil; /* RFC 3376: 6.6.3.2. Building and Sending Group and Source Specific Queries */ int source_query_retransmit_count; }; struct igmp_group { /* RFC 3376: 6.2.2. Definition of Group Timers The group timer is only used when a group is in EXCLUDE mode and it represents the time for the *filter-mode* of the group to expire and switch to INCLUDE mode. */ struct thread *t_group_timer; /* Shared between group-specific and group-and-source-specific retransmissions */ struct thread *t_group_query_retransmit_timer; /* Counter exclusive for group-specific retransmissions (not used by group-and-source-specific retransmissions, since sources have their counters) */ int group_specific_query_retransmit_count; struct in_addr group_addr; int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */ struct list *group_source_list; /* list of struct igmp_source */ time_t group_creation; struct igmp_sock *group_igmp_sock; /* back pointer */ int64_t last_igmp_v1_report_dsec; int64_t last_igmp_v2_report_dsec; }; struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, struct in_addr group_addr, const char *ifname); void igmp_group_delete_empty_include(struct igmp_group *group); void igmp_startup_mode_on(struct igmp_sock *igmp); void igmp_group_timer_on(struct igmp_group *group, long interval_msec, const char *ifname); #endif /* PIM_IGMP_H */ quagga-0.99.24.1/pimd/pim_vty.h0000644000175000017500000000203612476520570013026 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_VTY_H #define PIM_VTY_H #include "vty.h" int pim_debug_config_write(struct vty *vty); int pim_global_config_write(struct vty *vty); int pim_interface_config_write(struct vty *vty); #endif /* PIM_VTY_H */ quagga-0.99.24.1/pimd/pim_iface.h0000644000175000017500000001516012476520570013255 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_IFACE_H #define PIM_IFACE_H #include #include "if.h" #include "vty.h" #include "pim_igmp.h" #include "pim_upstream.h" #define PIM_IF_MASK_PIM (1 << 0) #define PIM_IF_MASK_IGMP (1 << 1) #define PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS (1 << 2) #define PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION (1 << 3) #define PIM_IF_IS_DELETED(ifp) ((ifp)->ifindex == IFINDEX_INTERNAL) #define PIM_IF_TEST_PIM(options) (PIM_IF_MASK_PIM & (options)) #define PIM_IF_TEST_IGMP(options) (PIM_IF_MASK_IGMP & (options)) #define PIM_IF_TEST_IGMP_LISTEN_ALLROUTERS(options) (PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS & (options)) #define PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) (PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION & (options)) #define PIM_IF_DO_PIM(options) ((options) |= PIM_IF_MASK_PIM) #define PIM_IF_DO_IGMP(options) ((options) |= PIM_IF_MASK_IGMP) #define PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(options) ((options) |= PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) #define PIM_IF_DO_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) |= PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) #define PIM_IF_DONT_PIM(options) ((options) &= ~PIM_IF_MASK_PIM) #define PIM_IF_DONT_IGMP(options) ((options) &= ~PIM_IF_MASK_IGMP) #define PIM_IF_DONT_IGMP_LISTEN_ALLROUTERS(options) ((options) &= ~PIM_IF_MASK_IGMP_LISTEN_ALLROUTERS) #define PIM_IF_DONT_PIM_CAN_DISABLE_JOIN_SUPRESSION(options) ((options) &= ~PIM_IF_MASK_PIM_CAN_DISABLE_JOIN_SUPRESSION) struct pim_interface { uint32_t options; /* bit vector */ int mroute_vif_index; struct in_addr primary_address; /* remember addr to detect change */ int igmp_default_robustness_variable; /* IGMPv3 QRV */ int igmp_default_query_interval; /* IGMPv3 secs between general queries */ int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for general queries */ int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response Time in dsecs for specific queries */ struct list *igmp_socket_list; /* list of struct igmp_sock */ struct list *igmp_join_list; /* list of struct igmp_join */ int pim_sock_fd; /* PIM socket file descriptor */ struct thread *t_pim_sock_read; /* thread for reading PIM socket */ int64_t pim_sock_creation; /* timestamp of PIM socket creation */ struct thread *t_pim_hello_timer; int pim_hello_period; int pim_default_holdtime; int pim_triggered_hello_delay; uint32_t pim_generation_id; uint16_t pim_propagation_delay_msec; /* config */ uint16_t pim_override_interval_msec; /* config */ struct list *pim_neighbor_list; /* list of struct pim_neighbor */ struct list *pim_ifchannel_list; /* list of struct pim_ifchannel */ /* neighbors without lan_delay */ int pim_number_of_nonlandelay_neighbors; uint16_t pim_neighbors_highest_propagation_delay_msec; uint16_t pim_neighbors_highest_override_interval_msec; /* DR Election */ int64_t pim_dr_election_last; /* timestamp */ int pim_dr_election_count; int pim_dr_election_changes; struct in_addr pim_dr_addr; uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ int64_t pim_ifstat_start; /* start timestamp for stats */ uint32_t pim_ifstat_hello_sent; uint32_t pim_ifstat_hello_sendfail; uint32_t pim_ifstat_hello_recv; uint32_t pim_ifstat_hello_recvfail; }; /* if default_holdtime is set (>= 0), use it; otherwise default_holdtime is 3.5 * hello_period */ #define PIM_IF_DEFAULT_HOLDTIME(pim_ifp) \ (((pim_ifp)->pim_default_holdtime < 0) ? \ ((pim_ifp)->pim_hello_period * 7 / 2) : \ ((pim_ifp)->pim_default_holdtime)) void pim_if_init(void); struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim); void pim_if_delete(struct interface *ifp); void pim_if_addr_add(struct connected *ifc); void pim_if_addr_del(struct connected *ifc, int force_prim_as_any); void pim_if_addr_add_all(struct interface *ifp); void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); void pim_if_addr_del_all_pim(struct interface *ifp); int pim_if_add_vif(struct interface *ifp); int pim_if_del_vif(struct interface *ifp); void pim_if_add_vif_all(void); void pim_if_del_vif_all(void); struct interface *pim_if_find_by_vif_index(int vif_index); int pim_if_find_vifindex_by_ifindex(int ifindex); int pim_if_lan_delay_enabled(struct interface *ifp); uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp); uint16_t pim_if_effective_override_interval_msec(struct interface *ifp); uint16_t pim_if_jp_override_interval_msec(struct interface *ifp); struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, struct in_addr addr); long pim_if_t_suppressed_msec(struct interface *ifp); int pim_if_t_override_msec(struct interface *ifp); struct in_addr pim_find_primary_addr(struct interface *ifp); int pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr); void pim_if_update_could_assert(struct interface *ifp); void pim_if_assert_on_neighbor_down(struct interface *ifp, struct in_addr neigh_addr); void pim_if_rpf_interface_changed(struct interface *old_rpf_ifp, struct pim_upstream *up); void pim_if_update_join_desired(struct pim_interface *pim_ifp); void pim_if_update_assert_tracking_desired(struct interface *ifp); #endif /* PIM_IFACE_H */ quagga-0.99.24.1/pimd/pim_signals.h0000644000175000017500000000165112476520570013646 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_SIGNALS_H #define PIM_SIGNALS_H void pim_signals_init(void); #endif /* PIM_SIGNALS_H */ quagga-0.99.24.1/pimd/pim_cmd.h0000644000175000017500000000726212476520570012755 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_CMD_H #define PIM_CMD_H #define PIM_STR "PIM information\n" #define IGMP_STR "IGMP information\n" #define IGMP_GROUP_STR "IGMP groups information\n" #define IGMP_SOURCE_STR "IGMP sources information\n" #define CONF_SSMPINGD_STR "Enable ssmpingd operation\n" #define SHOW_SSMPINGD_STR "ssmpingd operation\n" #define IFACE_PIM_STR "Enable PIM SSM operation\n" #define IFACE_IGMP_STR "Enable IGMP operation\n" #define IFACE_IGMP_QUERY_INTERVAL_STR "IGMP host query interval\n" #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR "IGMP max query response value (seconds)\n" #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n" #define DEBUG_IGMP_STR "IGMP protocol activity\n" #define DEBUG_IGMP_EVENTS_STR "IGMP protocol events\n" #define DEBUG_IGMP_PACKETS_STR "IGMP protocol packets\n" #define DEBUG_IGMP_TRACE_STR "IGMP internal daemon activity\n" #define DEBUG_MROUTE_STR "PIM interaction with kernel MFC cache\n" #define DEBUG_PIM_STR "PIM protocol activity\n" #define DEBUG_PIM_EVENTS_STR "PIM protocol events\n" #define DEBUG_PIM_PACKETS_STR "PIM protocol packets\n" #define DEBUG_PIM_HELLO_PACKETS_STR "PIM Hello protocol packets\n" #define DEBUG_PIM_J_P_PACKETS_STR "PIM Join/Prune protocol packets\n" #define DEBUG_PIM_PACKETDUMP_STR "PIM packet dump\n" #define DEBUG_PIM_PACKETDUMP_SEND_STR "Dump sent packets\n" #define DEBUG_PIM_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIM_TRACE_STR "PIM internal daemon activity\n" #define DEBUG_PIM_ZEBRA_STR "ZEBRA protocol activity\n" #define DEBUG_SSMPINGD_STR "ssmpingd activity\n" #define CLEAR_IP_IGMP_STR "IGMP clear commands\n" #define CLEAR_IP_PIM_STR "PIM clear commands\n" #define MROUTE_STR "IP multicast routing table\n" #define RIB_STR "IP unicast routing table\n" #define PIM_CMD_NO "no" #define PIM_CMD_IP_MULTICAST_ROUTING "ip multicast-routing" #define PIM_CMD_IP_IGMP_QUERY_INTERVAL "ip igmp query-interval" #define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME "ip igmp query-max-response-time" #define PIM_CMD_IP_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC "ip igmp query-max-response-time-dsec" void pim_cmd_init(void); #endif /* PIM_CMD_H */ quagga-0.99.24.1/pimd/pim_version.h0000644000175000017500000000171712476520570013676 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIM_VERSION_H #define PIM_VERSION_H #define PIMD_VERSION_STR "0.166" const char * const PIMD_VERSION; #endif /* PIM_VERSION_H */ quagga-0.99.24.1/pimd/pimd.h0000644000175000017500000001707512476520570012301 00000000000000/* PIM for Quagga Copyright (C) 2008 Everton da Silva Marques This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $QuaggaId: $Format:%an, %ai, %h$ $ */ #ifndef PIMD_H #define PIMD_H #include #include "pim_mroute.h" #include "pim_assert.h" #define PIMD_PROGNAME "pimd" #define PIMD_DEFAULT_CONFIG "pimd.conf" #define PIMD_VTY_PORT 2611 #define PIMD_BUG_ADDRESS "https://github.com/udhos/qpimd" #define PIM_IP_HEADER_MIN_LEN (20) #define PIM_IP_HEADER_MAX_LEN (60) #define PIM_IP_PROTO_IGMP (2) #define PIM_IP_PROTO_PIM (103) #define PIM_IGMP_MIN_LEN (8) #define PIM_MSG_HEADER_LEN (4) #define PIM_PIM_MIN_LEN PIM_MSG_HEADER_LEN #define PIM_PROTO_VERSION (2) #define MCAST_ALL_SYSTEMS "224.0.0.1" #define MCAST_ALL_ROUTERS "224.0.0.2" #define MCAST_ALL_PIM_ROUTERS "224.0.0.13" #define MCAST_ALL_IGMP_ROUTERS "224.0.0.22" #define PIM_FORCE_BOOLEAN(expr) ((expr) != 0) #define PIM_NET_INADDR_ANY (htonl(INADDR_ANY)) #define PIM_INADDR_IS_ANY(addr) ((addr).s_addr == PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ #define PIM_MASK_PIM_EVENTS (1 << 0) #define PIM_MASK_PIM_PACKETS (1 << 1) #define PIM_MASK_PIM_PACKETDUMP_SEND (1 << 2) #define PIM_MASK_PIM_PACKETDUMP_RECV (1 << 3) #define PIM_MASK_PIM_TRACE (1 << 4) #define PIM_MASK_IGMP_EVENTS (1 << 5) #define PIM_MASK_IGMP_PACKETS (1 << 6) #define PIM_MASK_IGMP_TRACE (1 << 7) #define PIM_MASK_ZEBRA (1 << 8) #define PIM_MASK_SSMPINGD (1 << 9) #define PIM_MASK_MROUTE (1 << 10) #define PIM_MASK_PIM_HELLO (1 << 11) #define PIM_MASK_PIM_J_P (1 << 12) const char *const PIM_ALL_SYSTEMS; const char *const PIM_ALL_ROUTERS; const char *const PIM_ALL_PIM_ROUTERS; const char *const PIM_ALL_IGMP_ROUTERS; struct thread_master *master; uint32_t qpim_debugs; int qpim_mroute_socket_fd; int64_t qpim_mroute_socket_creation; /* timestamp of creation */ struct thread *qpim_mroute_socket_reader; int qpim_mroute_oif_highest_vif_index; struct list *qpim_channel_oil_list; /* list of struct channel_oil */ struct in_addr qpim_all_pim_routers_addr; int qpim_t_periodic; /* Period between Join/Prune Messages */ struct list *qpim_upstream_list; /* list of struct pim_upstream */ struct zclient *qpim_zclient_update; struct zclient *qpim_zclient_lookup; struct pim_assert_metric qpim_infinite_assert_metric; long qpim_rpf_cache_refresh_delay_msec; struct thread *qpim_rpf_cache_refresher; int64_t qpim_rpf_cache_refresh_requests; int64_t qpim_rpf_cache_refresh_events; int64_t qpim_rpf_cache_refresh_last; struct in_addr qpim_inaddr_any; struct list *qpim_ssmpingd_list; /* list of struct ssmpingd_sock */ struct in_addr qpim_ssmpingd_group_addr; int64_t qpim_scan_oil_events; int64_t qpim_scan_oil_last; int64_t qpim_mroute_add_events; int64_t qpim_mroute_add_last; int64_t qpim_mroute_del_events; int64_t qpim_mroute_del_last; #define PIM_JP_HOLDTIME (qpim_t_periodic * 7 / 2) #define PIM_MROUTE_IS_ENABLED (qpim_mroute_socket_fd >= 0) #define PIM_MROUTE_IS_DISABLED (qpim_mroute_socket_fd < 0) #define PIM_DEBUG_PIM_EVENTS (qpim_debugs & PIM_MASK_PIM_EVENTS) #define PIM_DEBUG_PIM_PACKETS (qpim_debugs & PIM_MASK_PIM_PACKETS) #define PIM_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs & PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DEBUG_PIM_TRACE (qpim_debugs & PIM_MASK_PIM_TRACE) #define PIM_DEBUG_IGMP_EVENTS (qpim_debugs & PIM_MASK_IGMP_EVENTS) #define PIM_DEBUG_IGMP_PACKETS (qpim_debugs & PIM_MASK_IGMP_PACKETS) #define PIM_DEBUG_IGMP_TRACE (qpim_debugs & PIM_MASK_IGMP_TRACE) #define PIM_DEBUG_ZEBRA (qpim_debugs & PIM_MASK_ZEBRA) #define PIM_DEBUG_SSMPINGD (qpim_debugs & PIM_MASK_SSMPINGD) #define PIM_DEBUG_MROUTE (qpim_debugs & PIM_MASK_MROUTE) #define PIM_DEBUG_PIM_HELLO (qpim_debugs & PIM_MASK_PIM_HELLO) #define PIM_DEBUG_PIM_J_P (qpim_debugs & PIM_MASK_PIM_J_P) #define PIM_DEBUG_EVENTS (qpim_debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_IGMP_EVENTS)) #define PIM_DEBUG_PACKETS (qpim_debugs & (PIM_MASK_PIM_PACKETS | PIM_MASK_IGMP_PACKETS)) #define PIM_DEBUG_TRACE (qpim_debugs & (PIM_MASK_PIM_TRACE | PIM_MASK_IGMP_TRACE)) #define PIM_DO_DEBUG_PIM_EVENTS (qpim_debugs |= PIM_MASK_PIM_EVENTS) #define PIM_DO_DEBUG_PIM_PACKETS (qpim_debugs |= PIM_MASK_PIM_PACKETS) #define PIM_DO_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DO_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs |= PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DO_DEBUG_PIM_TRACE (qpim_debugs |= PIM_MASK_PIM_TRACE) #define PIM_DO_DEBUG_IGMP_EVENTS (qpim_debugs |= PIM_MASK_IGMP_EVENTS) #define PIM_DO_DEBUG_IGMP_PACKETS (qpim_debugs |= PIM_MASK_IGMP_PACKETS) #define PIM_DO_DEBUG_IGMP_TRACE (qpim_debugs |= PIM_MASK_IGMP_TRACE) #define PIM_DO_DEBUG_ZEBRA (qpim_debugs |= PIM_MASK_ZEBRA) #define PIM_DO_DEBUG_SSMPINGD (qpim_debugs |= PIM_MASK_SSMPINGD) #define PIM_DO_DEBUG_MROUTE (qpim_debugs |= PIM_MASK_MROUTE) #define PIM_DO_DEBUG_PIM_HELLO (qpim_debugs |= PIM_MASK_PIM_HELLO) #define PIM_DO_DEBUG_PIM_J_P (qpim_debugs |= PIM_MASK_PIM_J_P) #define PIM_DONT_DEBUG_PIM_EVENTS (qpim_debugs &= ~PIM_MASK_PIM_EVENTS) #define PIM_DONT_DEBUG_PIM_PACKETS (qpim_debugs &= ~PIM_MASK_PIM_PACKETS) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_SEND (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_SEND) #define PIM_DONT_DEBUG_PIM_PACKETDUMP_RECV (qpim_debugs &= ~PIM_MASK_PIM_PACKETDUMP_RECV) #define PIM_DONT_DEBUG_PIM_TRACE (qpim_debugs &= ~PIM_MASK_PIM_TRACE) #define PIM_DONT_DEBUG_IGMP_EVENTS (qpim_debugs &= ~PIM_MASK_IGMP_EVENTS) #define PIM_DONT_DEBUG_IGMP_PACKETS (qpim_debugs &= ~PIM_MASK_IGMP_PACKETS) #define PIM_DONT_DEBUG_IGMP_TRACE (qpim_debugs &= ~PIM_MASK_IGMP_TRACE) #define PIM_DONT_DEBUG_ZEBRA (qpim_debugs &= ~PIM_MASK_ZEBRA) #define PIM_DONT_DEBUG_SSMPINGD (qpim_debugs &= ~PIM_MASK_SSMPINGD) #define PIM_DONT_DEBUG_MROUTE (qpim_debugs &= ~PIM_MASK_MROUTE) #define PIM_DONT_DEBUG_PIM_HELLO (qpim_debugs &= ~PIM_MASK_PIM_HELLO) #define PIM_DONT_DEBUG_PIM_J_P (qpim_debugs &= ~PIM_MASK_PIM_J_P) void pim_init(void); void pim_terminate(void); #endif /* PIMD_H */ quagga-0.99.24.1/pimd/pimd.conf.sample0000644000175000017500000000172012476520570014245 00000000000000! ! pimd sample configuration file ! $QuaggaId: $Format:%an, %ai, %h$ $ ! hostname quagga-pimd-router password zebra !enable password zebra ! !log file pimd.log log stdout ! line vty exec-timeout 60 ! !debug igmp !debug pim !debug pim zebra ! ip multicast-routing ! ! ! You may want to enable ssmpingd for troubleshooting ! ! See http://www.venaas.no/multicast/ssmping/ ! ! ! ip ssmpingd 1.1.1.1 ! ip ssmpingd 2.2.2.2 ! ! ! HINTS: ! ! - Enable "ip pim ssm" on the interface directly attached to the ! ! multicast source host (if this is the first-hop router) ! ! - Enable "ip pim ssm" on pim-routers-facing interfaces ! ! - Enable "ip igmp" on IGMPv3-hosts-facing interfaces ! ! - In order to inject IGMPv3 local membership information in the ! ! PIM protocol state, enable both "ip pim ssm" and "ip igmp" on ! ! the same interface; otherwise PIM won't advertise ! ! IGMPv3-learned membership to other PIM routers ! interface eth0 ip pim ssm ip igmp ! -x- quagga-0.99.24.1/pimd/Makefile.am0000644000175000017500000000546112476520570013227 00000000000000## Process this file with automake to produce Makefile.in. ## $QuaggaId: $Format:%an, %ai, %h$ $ # qpimd - pimd for quagga # Copyright (C) 2008 Everton da Silva Marques # # qpimd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # # qpimd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with qpimd; see the file COPYING. If not, write # to the Free Software Foundation, Inc., 59 Temple Place - Suite # 330, Boston, MA 02111-1307, USA. # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall PIM_DEFS = #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT PIM_DEFS += -DPIM_CHECK_RECV_IFINDEX_SANITY #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS += -DPIM_ZCLIENT_DEBUG PIM_DEFS += -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libpim.a sbin_PROGRAMS = pimd bin_PROGRAMS = test_igmpv3_join libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ pim_igmp_join.c pim_ssmpingd.c pim_int.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) test_igmpv3_join_SOURCES = \ test_igmpv3_join.c pim_igmp_join.c pimd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = pimd.conf.sample quagga-0.99.24.1/pimd/Makefile.in0000644000175000017500000007716612476521251013250 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # qpimd - pimd for quagga # Copyright (C) 2008 Everton da Silva Marques # # qpimd is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2, # or (at your option) any later version. # # qpimd is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with qpimd; see the file COPYING. If not, write # to the Free Software Foundation, Inc., 59 Temple Place - Suite # 330, Boston, MA 02111-1307, USA. # PIM_DEBUG_BYDEFAULT: Automatically enables all pimd "debug ..." commands # PIM_ZCLIENT_DEBUG: Support for internal ZEBRA client debugging # PIM_CHECK_RECV_IFINDEX_SANITY: Compare socket ifindex with recv ifindex # PIM_REPORT_RECV_IFINDEX_MISMATCH: Report sock/recv ifindex mismatch # PIM_ENFORCE_LOOPFREE_MFC: Refuse adding looping MFC entries # PIM_UNEXPECTED_KERNEL_UPCALL: Report unexpected kernel upcall VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = pimd$(EXEEXT) bin_PROGRAMS = test_igmpv3_join$(EXEEXT) subdir = pimd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) \ AUTHORS COPYING README TODO ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libpim_a_AR = $(AR) $(ARFLAGS) libpim_a_LIBADD = am_libpim_a_OBJECTS = pimd.$(OBJEXT) pim_version.$(OBJEXT) \ pim_cmd.$(OBJEXT) pim_signals.$(OBJEXT) pim_iface.$(OBJEXT) \ pim_vty.$(OBJEXT) pim_igmp.$(OBJEXT) pim_sock.$(OBJEXT) \ pim_zebra.$(OBJEXT) pim_igmpv3.$(OBJEXT) pim_str.$(OBJEXT) \ pim_mroute.$(OBJEXT) pim_util.$(OBJEXT) pim_time.$(OBJEXT) \ pim_oil.$(OBJEXT) pim_zlookup.$(OBJEXT) pim_pim.$(OBJEXT) \ pim_tlv.$(OBJEXT) pim_neighbor.$(OBJEXT) pim_hello.$(OBJEXT) \ pim_ifchannel.$(OBJEXT) pim_join.$(OBJEXT) \ pim_assert.$(OBJEXT) pim_msg.$(OBJEXT) pim_upstream.$(OBJEXT) \ pim_rpf.$(OBJEXT) pim_rand.$(OBJEXT) pim_macro.$(OBJEXT) \ pim_igmp_join.$(OBJEXT) pim_ssmpingd.$(OBJEXT) \ pim_int.$(OBJEXT) libpim_a_OBJECTS = $(am_libpim_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(examplesdir)" PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) am__objects_1 = pimd.$(OBJEXT) pim_version.$(OBJEXT) pim_cmd.$(OBJEXT) \ pim_signals.$(OBJEXT) pim_iface.$(OBJEXT) pim_vty.$(OBJEXT) \ pim_igmp.$(OBJEXT) pim_sock.$(OBJEXT) pim_zebra.$(OBJEXT) \ pim_igmpv3.$(OBJEXT) pim_str.$(OBJEXT) pim_mroute.$(OBJEXT) \ pim_util.$(OBJEXT) pim_time.$(OBJEXT) pim_oil.$(OBJEXT) \ pim_zlookup.$(OBJEXT) pim_pim.$(OBJEXT) pim_tlv.$(OBJEXT) \ pim_neighbor.$(OBJEXT) pim_hello.$(OBJEXT) \ pim_ifchannel.$(OBJEXT) pim_join.$(OBJEXT) \ pim_assert.$(OBJEXT) pim_msg.$(OBJEXT) pim_upstream.$(OBJEXT) \ pim_rpf.$(OBJEXT) pim_rand.$(OBJEXT) pim_macro.$(OBJEXT) \ pim_igmp_join.$(OBJEXT) pim_ssmpingd.$(OBJEXT) \ pim_int.$(OBJEXT) am_pimd_OBJECTS = pim_main.$(OBJEXT) $(am__objects_1) pimd_OBJECTS = $(am_pimd_OBJECTS) pimd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_test_igmpv3_join_OBJECTS = test_igmpv3_join.$(OBJEXT) \ pim_igmp_join.$(OBJEXT) test_igmpv3_join_OBJECTS = $(am_test_igmpv3_join_OBJECTS) test_igmpv3_join_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libpim_a_SOURCES) $(pimd_SOURCES) \ $(test_igmpv3_join_SOURCES) DIST_SOURCES = $(libpim_a_SOURCES) $(pimd_SOURCES) \ $(test_igmpv3_join_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" $(PIM_DEFS) DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ #PIM_DEFS += -DPIM_DEBUG_BYDEFAULT #PIM_DEFS += -DPIM_REPORT_RECV_IFINDEX_MISMATCH PIM_DEFS = -DPIM_CHECK_RECV_IFINDEX_SANITY -DPIM_ZCLIENT_DEBUG \ -DPIM_ENFORCE_LOOPFREE_MFC #PIM_DEFS += -DPIM_UNEXPECTED_KERNEL_UPCALL AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libpim.a libpim_a_SOURCES = \ pimd.c pim_version.c pim_cmd.c pim_signals.c pim_iface.c \ pim_vty.c pim_igmp.c pim_sock.c pim_zebra.c \ pim_igmpv3.c pim_str.c pim_mroute.c pim_util.c pim_time.c \ pim_oil.c pim_zlookup.c pim_pim.c pim_tlv.c pim_neighbor.c \ pim_hello.c pim_ifchannel.c pim_join.c pim_assert.c \ pim_msg.c pim_upstream.c pim_rpf.c pim_rand.c pim_macro.c \ pim_igmp_join.c pim_ssmpingd.c pim_int.c noinst_HEADERS = \ pimd.h pim_version.h pim_cmd.h pim_signals.h pim_iface.h \ pim_vty.h pim_igmp.h pim_sock.h pim_zebra.h \ pim_igmpv3.h pim_str.h pim_mroute.h pim_util.h pim_time.h \ pim_oil.h pim_zlookup.h pim_pim.h pim_tlv.h pim_neighbor.h \ pim_hello.h pim_ifchannel.h pim_join.h pim_assert.h \ pim_msg.h pim_upstream.h pim_rpf.h pim_rand.h pim_macro.h \ pim_igmp_join.h pim_ssmpingd.h pim_int.h pimd_SOURCES = \ pim_main.c $(libpim_a_SOURCES) test_igmpv3_join_SOURCES = \ test_igmpv3_join.c pim_igmp_join.c pimd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = pimd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pimd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu pimd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libpim.a: $(libpim_a_OBJECTS) $(libpim_a_DEPENDENCIES) $(EXTRA_libpim_a_DEPENDENCIES) $(AM_V_at)-rm -f libpim.a $(AM_V_AR)$(libpim_a_AR) libpim.a $(libpim_a_OBJECTS) $(libpim_a_LIBADD) $(AM_V_at)$(RANLIB) libpim.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list pimd$(EXEEXT): $(pimd_OBJECTS) $(pimd_DEPENDENCIES) $(EXTRA_pimd_DEPENDENCIES) @rm -f pimd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pimd_OBJECTS) $(pimd_LDADD) $(LIBS) test_igmpv3_join$(EXEEXT): $(test_igmpv3_join_OBJECTS) $(test_igmpv3_join_DEPENDENCIES) $(EXTRA_test_igmpv3_join_DEPENDENCIES) @rm -f test_igmpv3_join$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_igmpv3_join_OBJECTS) $(test_igmpv3_join_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_assert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_hello.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_iface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_ifchannel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmp_join.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_igmpv3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_int.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_join.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_macro.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_mroute.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_neighbor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_oil.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_pim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_rand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_rpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_signals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_sock.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_ssmpingd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_str.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_tlv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_upstream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_vty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pim_zlookup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pimd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_igmpv3_join.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_examplesDATA \ uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-binPROGRAMS \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/solaris/0000755000175000017500000000000012476521377011776 500000000000000quagga-0.99.24.1/solaris/README.txt0000644000175000017500000001542212476520570013412 00000000000000To build packages for Solaris 10: Requirements: ------------- - Development environment including gcc (eg as shipped with Solaris 10) - The Package tools from Solaris 10 or Solaris Nevada/Express. - i.manifest and r.manifest scripts as supplied with Solaris Express in /usr/sadm/install/scripts/ or from OpenSolaris.org: http://cvs.opensolaris.org/source/xref/usr/src/pkgdefs/common_files/i.manifest http://cvs.opensolaris.org/source/xref/usr/src/pkgdefs/common_files/r.manifest i.manifest must be at least version 1.5. Place these scripts in this directory if you are using Solaris 10 GA (which does not ship with these scripts), or in the solaris/ directory in the Quagga source. Package creation instructions: ------------------------------ 1. Configure and build Quagga in the top level build directory as per normal, eg: ./configure --prefix=/usr/local/quagga \ --localstatedir=/var/run/quagga --enable-gcc-rdynamic --enable-opaque-lsa --enable-ospf-te \ --enable-multipath=64 --enable-user=quagga \ --enable-ospfclient=yes --enable-ospfapi=yes \ --enable-group=quagga --enable-nssa --enable-opaque-lsa You will need /usr/sfw/bin and /usr/ccs/bin in your path. 2. make install in the top-level build directory, it's a good idea to make use of DESTDIR to install to an alternate root, eg: gmake DESTDIR=/var/tmp/qroot install 3. In this directory (solaris/), run make packages, specifying DESTDIR if appropriate, eg: gmake DESTDIR=/var/tmp/qroot packages This should result in 4 packages being created: quagga-libs-...-$ARCH.pkg - QUAGGAlibs quagga-daemons-...-$ARCH.pkg - QUAGGAdaemons quagga-doc-...-$ARCH.pkg - QUAGGAdoc quagga-dev-...-$ARCH.pkg - QUAGGAdev quagga-smf-...-$ARCH.pkg - QUAGGAsmf QUAGGAlibs and QUAGGAdaemons are needed for daemon runtime. QUAGGAsmf provides the required bits for Solaris 10+ SMF support. Install and post-install configuration notes: --------------------------------------------- - If you specified a user/group which does not exist per default on Solaris (eg quagga/quagga) you *must* create these before installing these on a system. The packages do *not* create the users. - The configuration files are not created. You must create the configuration file yourself, either with your complete desired configuration, or else if you wish to use the telnet interface for further configuration you must create them containing at least: password whatever The user which quagga runs as must have write permissions on this file, no other user should have read permissions, and you would also have to enable the telnet interface (see below). - SMF notes: - QUAGGAsmf installs a svc:/network/routing/quagga service, with an instance for each daemon - The state of all instances of quagga service can be inspected with: svcs -l svc:/network/routing/quagga or typically just with a shortcut of 'quagga': svcs -l quagga - A specific instance of the quagga service can be inspected by specifying the daemon name as the instance, ie quagga:: svcs -l svc:/network/routing/quagga:zebra svcs -l svc:/network/routing/quagga:ospfd or typically just with the shortcut of 'quagga:' or even : svcs -l quagga:zebra svcs -l ospfd Eg: # # svcs -l ripd fmri svc:/network/routing/quagga:ripd name Quagga: ripd, RIPv1/2 IPv4 routing protocol daemon. enabled true state online next_state none state_time Wed Jun 15 16:21:02 2005 logfile /var/svc/log/network-routing-quagga:ripd.log restarter svc:/system/svc/restarter:default contract_id 93 dependency require_all/restart svc:/network/routing/quagga:zebra (online) dependency require_all/restart file://localhost//usr/local/quagga/etc/ripd.conf (online) dependency require_all/none svc:/system/filesystem/usr:default (online) dependency require_all/none svc:/network/loopback (online) - Configuration of startup options is by way of SMF properties in a property group named 'quagga'. The defaults should automatically be inline with how you configured Quagga in Step 1 above. - By default the VTY interface is disabled. To change this, see below for how to set the 'quagga/vty_port' property as appropriate for /each/ service. Also, the VTY is set to listen only to localhost by default, you may change the 'quagga/vty_addr' property as appropriate for both of the 'quagga' service and specific individual instances of the 'quagga' service (ie quagga:zebra, quagga:ospfd, etc..). - Properties belonging to the 'quagga' service are inherited by all instances. Eg: # svcprop -p quagga svc:/network/routing/quagga quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_addr astring 127.1 quagga/vty_port integer 0 # svcprop -p quagga svc:/network/routing/quagga:ospfd quagga/retain_routes boolean false quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_addr astring 127.1 quagga/vty_port integer 0 All instances will inherit these properties, unless the instance itself overrides these defaults. This also implies one can modify properties of the 'quagga' service and have them apply to all daemons. # svccfg -s svc:/network/routing/quagga \ setprop quagga/vty_addr = astring: ::1 # svcprop -p quagga svc:/network/routing/quagga quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_port integer 0 quagga/vty_addr astring ::1 # # You *must* refresh instances to have the property change # # take affect for the 'running snapshot' of service state. # svcadm refresh quagga:ospfd # svcprop -p quagga svc:/network/routing/quagga:ospfd quagga/retain_routes boolean false quagga/group astring root quagga/retain boolean false quagga/user astring root quagga/vty_port integer 0 quagga/vty_addr astring ::1 Other daemon-specific options/properties may be available, however they are not yet honoured/used (eg ospfd/apiserver on svc:/network/ospf). - As SMF is dependency aware, restarting network/zebra will restart all the other daemons. - To upgrade from one set of Quagga packages to a newer release, one must first pkgrm the installed packages. When one pkgrm's QUAGGAsmf all property configuration will be lost, and any customisations will have to redone after installing the updated QUAGGAsmf package. - These packages are not supported by Sun Microsystems, report bugs via the usual Quagga channels, ie Bugzilla. Improvements/contributions of course would be greatly appreciated. quagga-0.99.24.1/solaris/quagga.init.in0000755000175000017500000001643712476520570014465 00000000000000#!/sbin/sh # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This file is part of Quagga. # # Quagga is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2, or (at your option) any # later version. # # Quagga is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Quagga; see the file COPYING. If not, write to the Free # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Starts/stops the given daemon SMFINCLUDE=/lib/svc/share/smf_include.sh ROUTEADMINCLUDE=/lib/svc/share/routing_include.sh GLOBAL_OPTIONS="PAfiug" DAEMON_PATH=@sbindir@ USER=@enable_user@ GROUP=@enable_group@ # handle upgrade of daemon-args SMF property to new routeadm properties # used during upgrade too by routeadm. # relevant to S10U4+ only. handle_routeadm_upgrade () { GLOBAL_OPTIONS="PAfiug" daemon_args=`get_daemon_args $SMF_FMRI` if [ -n "$daemon_args" ]; then set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "P" vty_port 0 set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "A" vty_address set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "f" config_file set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "i" pid_file set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "u" user set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "$GLOBAL_OPTIONS" "g" group case "$1" in zebra) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}b" "b" batch true false ;; ripd|ripngd) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}r" "r" retain true false ;; bgpd) set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "r" retain true false set_daemon_boolean_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "n" no_kernel true false set_daemon_value_property "$SMF_FMRI" "$daemon_args" \ "${GLOBAL_OPTIONS}rnp" "p" bgp_port esac clear_daemon_args $SMF_FMRI fi } upgrade_config () { DAEMON=$1 # handle upgrade of SUNWzebra to Quagga if [ -d "/etc/quagga" -a ! -f "/etc/quagga/${DAEMON}.conf" ] ; then if [ -f "/etc/sfw/zebra/${DAEMON}.conf" ] ; then cp "/etc/sfw/zebra/${DAEMON}.conf" \ "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL chown "${USER}:${GROUP}" "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL chmod 0600 "/etc/quagga/${DAEMON}.conf.upgrade" \ || exit $SMF_EXIT_ERR_FATAL mv "/etc/quagga/${DAEMON}.conf.upgrade" "/etc/quagga/${DAEMON}.conf" \ || exit $SMF_EXIT_ERR_FATAL fi fi if [ ! -f "/etc/quagga/${DAEMON}.conf" ] ; then touch "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL chown "${USER}:${GROUP}" "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL chmod 0600 "/etc/quagga/${DAEMON}.conf.new" \ || exit $SMF_EXIT_ERR_FATAL mv "/etc/quagga/${DAEMON}.conf.new" "/etc/quagga/${DAEMON}.conf" \ || exit $SMF_EXIT_ERR_FATAL fi } # Relevant to S10+ quagga_is_globalzone () { if [ "${QUAGGA_INIT_ZONENAME:=`/sbin/zonename`}" = "global" \ -o `/sbin/zonename -t` = "exclusive" ]; then return 0 else return 1 fi } routeadm_daemon_args () { # globals args="`get_daemon_option_from_property $SMF_FMRI config_file f`" args="${args} `get_daemon_option_from_property $SMF_FMRI vty_port P`" args="${args} `get_daemon_option_from_property $SMF_FMRI vty_address A`" args="${args} `get_daemon_option_from_property $SMF_FMRI pid_file i`" # user and group we need for config file upgrade.. SMF_USER=`get_routeadm_property $SMF_FMRI user` SMF_GROUP=`get_routeadm_property()$SMF_FMRI group` if [ "${SMF_USER}" ] ; then USER="${SMF_USER}" args="${args} -u ${SMF_USER}" fi if [ "${SMF_GROUP}" ] ; then GROUP="${SMF_GROUP}" args="${args} -g ${SMF_GROUP}" fi case $1 in zebra) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI batch -b true`" ;; ripd|ripngd) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`" ;; bgpd) args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI retain -r true`" args="${args} `get_daemon_option_from_boolean_property $SMF_FMRI no_kernel -n true`" args="${args} `get_daemon_option_from_property $SMF_FMRI bgp_port p 179`" ;; esac echo ${args} } # Include smf functions, if available. If not, define smf_present to indicate # there is no SMF. Should allow this script to work pre-S10. if [ -f "$SMFINCLUDE" ] ; then . "$SMFINCLUDE"; # source the SMF-routeadm include if present.. if [ -f "$ROUTEADMINCLUDE" ] ; then . "$ROUTEADMINCLUDE" fi else # pre-SMF system, fake up any functions and exit codes # which SMFINCLUDE usually provides. smf_present () { return 1 } SMF_EXIT_OK=0; SMF_EXIT_ERR_CONFIG=96; SMF_EXIT_ERR_FATAL=95; fi # if there's no SMF, set some default DAEMON_ARGS smf_present || DAEMON_ARGS="" usage () { if smf_present ; then echo "Usage: $0 "; else echo "Usage: $0 "; fi echo "The --pid_file argument is implied"; echo "This help message: $0 "; } # parse arguments, different according to SMF or not. case $1 in 'help' | 'usage') usage exit $SMF_EXIT_OK ;; esac if smf_present ; then QUAGGA_METHOD="start" else QUAGGA_METHOD="$1" shift; fi DAEMON="$1" # daemon path must be given if [ -z "$DAEMON_PATH/$DAEMON" ]; then usage exit $SMF_EXIT_ERR_FATAL fi # only bgpd is suitable for running in a non-global zone, at this # time. case "${DAEMON}" in bgpd) ;; zebra | ospfd | ospf6d | ripd | ripngd ) quagga_is_globalzone || exit $SMF_EXIT_OK ;; *) usage exit $SMF_EXIT_ERR_CONFIG; ;; esac # Older Quagga SMF packages pass daemon args on the commandline # Newer SMF routeadm model uses properties for each argument # so we must handle that. if [ smf_present -a -f "$ROUTEADMINCLUDE" ]; then handle_routeadm_upgrade $DAEMON; DAEMON_ARGS=`routeadm_daemon_args`; else if [ $# -gt 0 ] ; then shift DAEMON_ARGS="$@" fi fi upgrade_config "$DAEMON" if [ ! -f "@sysconfdir@/${DAEMON}.conf" ] ; then echo "Could not find config file, @sysconfdir@/${DAEMON}.conf" exit $SMF_EXIT_ERR_CONFIG fi # we need @quagga_statedir@ to exist, it probably is on tmpfs. if [ ! -d @quagga_statedir@ ] ; then mkdir -p @quagga_statedir@ chown @enable_user@:@enable_group@ @quagga_statedir@ chmod 751 @quagga_statedir@ fi PIDFILE="@quagga_statedir@/${DAEMON}.pid" start () { if [ ! -x "$DAEMON_PATH/$DAEMON" ] ; then echo "Error, could not find daemon, $DAEMON_PATH/$DAEMON" exit $SMF_EXIT_ERR_FATAL fi eval exec $DAEMON_PATH/$DAEMON $DAEMON_ARGS --pid_file ${PIDFILE} & } stop_by_pidfile () { if [ -f "${PIDFILE}" ]; then /usr/bin/kill -TERM `/usr/bin/cat "${PIDFILE}"` fi } case "$QUAGGA_METHOD" in 'start') start ;; 'stop') stop_by_pidfile ;; *) usage exit $SMF_EXIT_ERR_FATAL ;; esac exit $SMF_EXIT_OK; quagga-0.99.24.1/solaris/depend.smf.in0000644000175000017500000000033712476520570014266 00000000000000P QUAGGAdaemons Quagga daemons @PACKAGE_VERSION@,REV=@CONFDATE@ P SUNWcsu Core Solaris, (Usr) P SUNWcsr Core Solaris Libraries (Root) P SUNWroute Network Routing daemons/commands (Usr) I SUNWzebrar I SUNWzebrau I CSWzebra quagga-0.99.24.1/solaris/depend.libs.in0000644000175000017500000000025512476520570014431 00000000000000P SUNWcslr Core Solaris Libraries (Root) P SUNWcsl Core Solaris, (Shared Libs) P SUNWlibmsr Math & Microtasking Libraries (Root) R QUAGGAdaemons Quagga daemons R QUAGGAdev quagga-0.99.24.1/solaris/depend.doc.in0000644000175000017500000000003612476520570014242 00000000000000P SUNWdoc Documentation Tools quagga-0.99.24.1/solaris/depend.dev.in0000644000175000017500000000011712476520570014253 00000000000000P QUAGGAlibs Quagga common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ quagga-0.99.24.1/solaris/depend.daemons.in0000644000175000017500000000036112476520570015124 00000000000000P QUAGGAlibs Quagga common runtime libraries @PACKAGE_VERSION@,REV=@CONFDATE@ P SUNWcsu Core Solaris, (Usr) P SUNWcsr Core Solaris Libraries (Root) P SUNWcnetr Core Solaris Network Infrastructure (Root) I SUNWzebrar I SUNWzebrau I CSWzebra quagga-0.99.24.1/solaris/pkginfo.tmpl.in0000644000175000017500000000041412476520570014647 00000000000000ARCH="@target_cpu@" CATEGORY="system" VERSION="@PACKAGE_VERSION@,REV=@CONFDATE@" VENDOR="http://www.quagga.net/" HOTLINE="@PACKAGE_BUGREPORT@" EMAIL=paul@quagga.net DESC="@PACKAGE_NAME@ Routing Protocols" MAXINST=1 CLASSES="none preserve renamenew manifest" BASEDIR=/ quagga-0.99.24.1/solaris/pkginfo.smf.tmpl.in0000644000175000017500000000010312476520570015426 00000000000000PKG="QUAGGAsmf" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ SMF support" quagga-0.99.24.1/solaris/pkginfo.libs.tmpl.in0000644000175000017500000000011712476520570015577 00000000000000PKG=QUAGGAlibs NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ common runtime libraries" quagga-0.99.24.1/solaris/pkginfo.doc.tmpl.in0000644000175000017500000000010312476520570015406 00000000000000PKG=QUAGGAdoc NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ documentation" quagga-0.99.24.1/solaris/pkginfo.dev.tmpl.in0000644000175000017500000000011012476520570015415 00000000000000PKG=QUAGGAdev NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ development files" quagga-0.99.24.1/solaris/pkginfo.daemons.tmpl.in0000644000175000017500000000010312476520570016267 00000000000000PKG="QUAGGAdaemons" NAME="@PACKAGE_NAME@ - @PACKAGE_NAME@ daemons" quagga-0.99.24.1/solaris/prototype.smf.in0000644000175000017500000000054712476520570015077 00000000000000i pkginfo=$abs_builddir/pkginfo.smf.full i depend=$abs_builddir/depend.smf i copying=$abs_top_srcdir/COPYING i i.manifest i r.manifest f manifest var/svc/manifest/network/quagga.xml 0444 root bin #f none var/svc/profile/@PACKAGE_TARNAME@_options.xml=$abs_builddir/options.xml 0755 root sys f none lib/svc/method/quagga=$abs_builddir/quagga.init 0755 root bin quagga-0.99.24.1/solaris/prototype.libs.in0000644000175000017500000000133712476520570015241 00000000000000i pkginfo=$abs_builddir/pkginfo.libs.full i depend=$abs_builddir/depend.libs i copying=$abs_top_srcdir/COPYING d none @libdir@=$DESTDIR/@libdir@ 0755 root bin s none @libdir@/libzebra.so.0=libzebra.so.0.0.0 f none @libdir@/libzebra.so.0.0.0=$DESTDIR/@libdir@/libzebra.so.0.0.0 0755 root bin s none @libdir@/libzebra.so=libzebra.so.0.0.0 s none @libdir@/libospf.so.0=libospf.so.0.0.0 f none @libdir@/libospf.so.0.0.0=$DESTDIR/@libdir@/libospf.so.0.0.0 0755 root bin s none @libdir@/libospf.so=libospf.so.0.0.0 f none @libdir@/libospfapiclient.so.0.0.0=$DESTDIR/@libdir@/libospfapiclient.so.0.0.0 0755 root bin s none @libdir@/libospfapiclient.so.0=libospfapiclient.so.0.0.0 s none @libdir@/libospfapiclient.so=libospfapiclient.so.0.0.0 quagga-0.99.24.1/solaris/prototype.doc.in0000644000175000017500000000203012476520570015044 00000000000000i pkginfo=$abs_builddir/pkginfo.doc.full i depend=$abs_builddir/depend.doc i copying=$abs_top_srcdir/COPYING d none @infodir@=$DESTDIR/@infodir@ 0755 root bin #f none @infodir@/dir=$DESTDIR/@infodir@/dir 0644 root bin f none @infodir@/quagga.info=$DESTDIR/@infodir@/quagga.info 0644 root bin d none @mandir@=$DESTDIR/@mandir@ 0755 root bin d none @mandir@/man1=$DESTDIR/@mandir@/man1 0755 root bin f none @mandir@/man1/vtysh.1=$DESTDIR/@mandir@/man1/vtysh.1 0644 root bin d none @mandir@/man8=$DESTDIR/@mandir@/man8 0755 root bin f none @mandir@/man8/bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin f none @mandir@/man8/ospf6d.8=$DESTDIR/@mandir@/man8/ospf6d.8 0644 root bin f none @mandir@/man8/ospfd.8=$DESTDIR/@mandir@/man8/ospfd.8 0644 root bin f none @mandir@/man8/ripd.8=$DESTDIR/@mandir@/man8/ripd.8 0644 root bin f none @mandir@/man8/ripngd.8=$DESTDIR/@mandir@/man8/ripngd.8 0644 root bin f none @mandir@/man8/zebra.8=$DESTDIR/@mandir@/man8/zebra.8 0644 root bin f none @mandir@/man8/isisd.8=$DESTDIR/@mandir@/man8/isisd.8 0644 root bin quagga-0.99.24.1/solaris/prototype.dev.in0000644000175000017500000001145112476520570015064 00000000000000i pkginfo=$abs_builddir/pkginfo.dev.full i depend=$abs_builddir/depend.dev i copying=$abs_top_srcdir/COPYING f none @libdir@/libzebra.la=$DESTDIR/@libdir@/libzebra.la 0755 root bin f none @libdir@/libzebra.a=$DESTDIR/@libdir@/libzebra.a 0644 root bin f none @libdir@/libospf.la=$DESTDIR/@libdir@/libospf.la 0755 root bin f none @libdir@/libospf.a=$DESTDIR/@libdir@/libospf.a 0644 root bin f none @libdir@/libospfapiclient.la=$DESTDIR/@libdir@/libospfapiclient.la 0755 root bin f none @libdir@/libospfapiclient.a=$DESTDIR/@libdir@/libospfapiclient.a 0644 root bin d none @includedir@=$DESTDIR/@includedir@ 0755 root bin d none @includedir@/quagga=$DESTDIR/@includedir@/quagga 0755 root bin d none @includedir@/quagga/ospfd=$DESTDIR/@includedir@/quagga/ospfd 0755 root bin f none @includedir@/quagga/ospfd/ospf_api.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_api.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_asbr.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_asbr.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_dump.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_dump.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_lsa.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_lsa.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_lsdb.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_lsdb.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_nsm.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_nsm.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_ism.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_ism.h 0644 root bin f none @includedir@/quagga/ospfd/ospf_opaque.h=$DESTDIR/@includedir@/quagga/ospfd/ospf_opaque.h 0644 root bin f none @includedir@/quagga/ospfd/ospfd.h=$DESTDIR/@includedir@/quagga/ospfd/ospfd.h 0644 root bin f none @includedir@/quagga/buffer.h=$DESTDIR/@includedir@/quagga/buffer.h 0644 root bin f none @includedir@/quagga/command.h=$DESTDIR/@includedir@/quagga/command.h 0644 root bin f none @includedir@/quagga/filter.h=$DESTDIR/@includedir@/quagga/filter.h 0644 root bin f none @includedir@/quagga/getopt.h=$DESTDIR/@includedir@/quagga/getopt.h 0644 root bin f none @includedir@/quagga/hash.h=$DESTDIR/@includedir@/quagga/hash.h 0644 root bin f none @includedir@/quagga/if.h=$DESTDIR/@includedir@/quagga/if.h 0644 root bin f none @includedir@/quagga/linklist.h=$DESTDIR/@includedir@/quagga/linklist.h 0644 root bin f none @includedir@/quagga/log.h=$DESTDIR/@includedir@/quagga/log.h 0644 root bin f none @includedir@/quagga/memory.h=$DESTDIR/@includedir@/quagga/memory.h 0644 root bin f none @includedir@/quagga/network.h=$DESTDIR/@includedir@/quagga/network.h 0644 root bin f none @includedir@/quagga/prefix.h=$DESTDIR/@includedir@/quagga/prefix.h 0644 root bin f none @includedir@/quagga/routemap.h=$DESTDIR/@includedir@/quagga/routemap.h 0644 root bin f none @includedir@/quagga/distribute.h=$DESTDIR/@includedir@/quagga/distribute.h 0644 root bin f none @includedir@/quagga/sockunion.h=$DESTDIR/@includedir@/quagga/sockunion.h 0644 root bin f none @includedir@/quagga/str.h=$DESTDIR/@includedir@/quagga/str.h 0644 root bin f none @includedir@/quagga/stream.h=$DESTDIR/@includedir@/quagga/stream.h 0644 root bin f none @includedir@/quagga/table.h=$DESTDIR/@includedir@/quagga/table.h 0644 root bin f none @includedir@/quagga/thread.h=$DESTDIR/@includedir@/quagga/thread.h 0644 root bin f none @includedir@/quagga/vector.h=$DESTDIR/@includedir@/quagga/vector.h 0644 root bin f none @includedir@/quagga/version.h=$DESTDIR/@includedir@/quagga/version.h 0644 root bin f none @includedir@/quagga/vty.h=$DESTDIR/@includedir@/quagga/vty.h 0644 root bin f none @includedir@/quagga/zebra.h=$DESTDIR/@includedir@/quagga/zebra.h 0644 root bin f none @includedir@/quagga/plist.h=$DESTDIR/@includedir@/quagga/plist.h 0644 root bin f none @includedir@/quagga/zclient.h=$DESTDIR/@includedir@/quagga/zclient.h 0644 root bin f none @includedir@/quagga/sockopt.h=$DESTDIR/@includedir@/quagga/sockopt.h 0644 root bin f none @includedir@/quagga/smux.h=$DESTDIR/@includedir@/quagga/smux.h 0644 root bin f none @includedir@/quagga/md5.h=$DESTDIR/@includedir@/quagga/md5.h 0644 root bin f none @includedir@/quagga/if_rmap.h=$DESTDIR/@includedir@/quagga/if_rmap.h 0644 root bin f none @includedir@/quagga/keychain.h=$DESTDIR/@includedir@/quagga/keychain.h 0644 root bin f none @includedir@/quagga/privs.h=$DESTDIR/@includedir@/quagga/privs.h 0644 root bin f none @includedir@/quagga/sigevent.h=$DESTDIR/@includedir@/quagga/sigevent.h 0644 root bin f none @includedir@/quagga/pqueue.h=$DESTDIR/@includedir@/quagga/pqueue.h 0644 root bin f none @includedir@/quagga/jhash.h=$DESTDIR/@includedir@/quagga/jhash.h 0644 root bin f none @includedir@/quagga/zassert.h=$DESTDIR/@includedir@/quagga/zassert.h 0644 root bin d none @includedir@/quagga/ospfapi=$DESTDIR/@includedir@/quagga/ospfapi 0755 root bin f none @includedir@/quagga/ospfapi/ospf_apiclient.h=$DESTDIR/@includedir@/quagga/ospfapi/ospf_apiclient.h 0644 root bin quagga-0.99.24.1/solaris/prototype.daemons.in0000644000175000017500000000261312476520570015734 00000000000000i pkginfo=$abs_builddir/pkginfo.daemons.full i depend=$abs_builddir/depend.daemons i copying=$abs_top_srcdir/COPYING d none @sbindir@=$DESTDIR/@sbindir@ 0755 root bin f none @sbindir@/zebra=$DESTDIR/@sbindir@/zebra 0755 root bin f none @sbindir@/bgpd=$DESTDIR/@sbindir@/bgpd 0755 root bin f none @sbindir@/ripd=$DESTDIR/@sbindir@/ripd 0755 root bin f none @sbindir@/ripngd=$DESTDIR/@sbindir@/ripngd 0755 root bin f none @sbindir@/ospfd=$DESTDIR/@sbindir@/ospfd 0755 root bin f none @sbindir@/ospf6d=$DESTDIR/@sbindir@/ospf6d 0755 root bin f none @sbindir@/watchquagga=$DESTDIR/@sbindir@/watchquagga 0755 root bin d none @sysconfdir@=$DESTDIR/@sysconfdir@ 0711 @enable_user@ @enable_group@ f none @sysconfdir@/zebra.conf.sample=$DESTDIR/@sysconfdir@/zebra.conf.sample 0644 root bin f none @sysconfdir@/bgpd.conf.sample=$DESTDIR/@sysconfdir@/bgpd.conf.sample 0644 root bin f none @sysconfdir@/bgpd.conf.sample2=$DESTDIR/@sysconfdir@/bgpd.conf.sample2 0644 root bin f none @sysconfdir@/ripd.conf.sample=$DESTDIR/@sysconfdir@/ripd.conf.sample 0644 root bin f none @sysconfdir@/ripngd.conf.sample=$DESTDIR/@sysconfdir@/ripngd.conf.sample 0644 root bin f none @sysconfdir@/ospfd.conf.sample=$DESTDIR/@sysconfdir@/ospfd.conf.sample 0644 root bin f none @sysconfdir@/ospf6d.conf.sample=$DESTDIR/@sysconfdir@/ospf6d.conf.sample 0644 root bin d none @quagga_statedir@=$DESTDIR/@quagga_statedir@ 0711 @enable_user@ @enable_group@ quagga-0.99.24.1/solaris/quagga.xml.in0000644000175000017500000005757212476520570014324 00000000000000 quagga-0.99.24.1/solaris/Makefile.am0000644000175000017500000001034412476520570013746 00000000000000# Solaris packages automake file # XXX This file uses GNU make extensions. .PHONY: packages # the names of the various subpackages, and some convenient # derived variables. pkg_names = daemons dev doc libs smf pkg_quagga_daemons = zebra bgpd ospfd ospf6d ripd ripngd pkg_name_rev = @PACKAGE_VERSION@-@CONFDATE@-@target_os@-@target_cpu@ pkg_depends = $(pkg_names:%=depend.%) pkg_packages = $(pkg_names:%=@PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg) pkg_pkginfos = $(pkg_names:%=pkginfo.%.full) pkg_prototypes = $(pkg_names:%=prototype.%) pkg_manifests = quagga.xml # pkgmk variable substitutions wont grok ${variable} in prototype # file, so we cant let autoconf generate the file sadly # wish automake would just provide a template for this edit = $(SED) \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix,$(exec_prefix),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@libexecdir\@,$(libexecdir),g' \ -e 's,@datadir\@,$(datadir),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@sharedstatedir\@,$(sharedstatedir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@libdir\@,$(libdir),g' \ -e 's,@includedir\@,$(includedir),g' \ -e 's,@infodir\@,$(infodir),g' \ -e 's,@mandir\@,$(mandir),g' \ -e 's,@enable_user\@,$(enable_user),g' \ -e 's,@enable_group\@,$(enable_group),g' \ -e 's,@enable_vty_group\@,$(enable_vty_group),g' \ -e 's,@quagga_statedir\@,$(quagga_statedir),g' \ -e 's,[@]PACKAGE_NAME[@],@PACKAGE_NAME@,g' \ -e 's,[@]PACKAGE_TARNAME[@],@PACKAGE_TARNAME@,g' \ -e 's,[@]PACKAGE_VERSION[@],@PACKAGE_VERSION@,g' \ -e 's,[@]PACKAGE_BUGREPORT[@],@PACKAGE_BUGREPORT@,g' \ -e 's,[@]CONFDATE[@],@CONFDATE@,g' \ -e 's,[@]target_cpu[@],$(target_cpu),g' \ -e 's,[@]target_host[@],$(target_host),g' \ -e 's,[@]target_os[@],$(target_os),g' # common options for pkgmk pkg_make_vars = exec_prefix=@exec_prefix@ prefix=@prefix@ \ builddir=@builddir@ srcdir=@srcdir@ \ top_builddir=@top_builddir@ top_srcdir=@top_srcdir@ \ abs_builddir=@abs_builddir@ abs_srcdir=@abs_srcdir@ \ abs_top_builddir=@abs_top_builddir@ abs_top_srcdir=@abs_top_srcdir@ # pkgmk: write the package to spool in build dir, to avoid root dependencies pkg_make = pkgmk -o -d @abs_builddir@ \ -f $< DESTDIR="$(DESTDIR)/" $(pkg_make_vars) # pkgtrans: write a pkg file stream, shame we cant pipe directly to it from # pkgmk.. pkg_trans = pkgtrans -s @abs_builddir@ "@abs_builddir@/$@" # pkgmk can only cope with a single pkginfo, cant 'stack' various # pkginfo template files and a package specific pkginfo file in the prototype # Create the package specific template here, and create the full pkginfo # by cating this and the common pkginfo.tmpl together. pkginfo.tmpl: $(srcdir)/pkginfo.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.tmpl: $(srcdir)/pkginfo.%.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.full: pkginfo.%.tmpl pkginfo.tmpl Makefile cat pkginfo.tmpl pkginfo.$*.tmpl > $@ # use 'edit' above to transform prototype.in to pkgmk acceptable prototype prototype.%: $(srcdir)/prototype.%.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the SMF manifest files %.xml: $(srcdir)/%.xml.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the depend files depend.%: $(srcdir)/depend.%.in Makefile rm -f $@ $(edit) $< > $@ # method file (bit like init script) quagga.init: $(srcdir)/quagga.init.in Makefile rm -f $@ $(edit) $< > $@ # construct the pkg @PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg: prototype.% \ depend.% quagga.init pkginfo.%.full ($(pkg_make) && \ $(pkg_trans) "QUAGGA$*") %.pkg.gz : %.pkg (gzip -c $< > $@) # pkginfo.package and prototype.package are all built sources #BUILT_SOURCES = pkginfo.daemons pkginfo.dev pkginfo.doc pkginfo.libs \ # prototype.daemons prototype.dev prototype.doc prototype.libs BUILT_SOURCES = $(pkg_pkginfos) pkginfo.tmpl $(pkg_prototypes) \ $(pkg_manifests) $(pkg_depends) quagga.init CLEANFILES = $(BUILT_SOURCES) $(pkg_packages) EXTRA_DIST = $(pkg_manifests:%=%.in) $(pkg_prototypes:%=%.in) \ $(pkg_names:%=pkginfo.%.tmpl.in) $(srcdir)/pkginfo.tmpl.in \ $(pkg_depends:%=%.in) quagga.init.in README.txt pkg-root-install: (cd $(top_builddir) && \ $(MAKE) DESTDIR=$(abs_builddir)/quagga-root install) packages: $(pkg_packages) #nodist_pkgdata_DATA = $(pkg_packages) quagga-0.99.24.1/solaris/Makefile.in0000644000175000017500000004243012476521251013755 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Solaris packages automake file # XXX This file uses GNU make extensions. VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = solaris DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # the names of the various subpackages, and some convenient # derived variables. pkg_names = daemons dev doc libs smf pkg_quagga_daemons = zebra bgpd ospfd ospf6d ripd ripngd pkg_name_rev = @PACKAGE_VERSION@-@CONFDATE@-@target_os@-@target_cpu@ pkg_depends = $(pkg_names:%=depend.%) pkg_packages = $(pkg_names:%=@PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg) pkg_pkginfos = $(pkg_names:%=pkginfo.%.full) pkg_prototypes = $(pkg_names:%=prototype.%) pkg_manifests = quagga.xml # pkgmk variable substitutions wont grok ${variable} in prototype # file, so we cant let autoconf generate the file sadly # wish automake would just provide a template for this edit = $(SED) \ -e 's,@prefix\@,$(prefix),g' \ -e 's,@exec_prefix,$(exec_prefix),g' \ -e 's,@bindir\@,$(bindir),g' \ -e 's,@sbindir\@,$(sbindir),g' \ -e 's,@libexecdir\@,$(libexecdir),g' \ -e 's,@datadir\@,$(datadir),g' \ -e 's,@sysconfdir\@,$(sysconfdir),g' \ -e 's,@sharedstatedir\@,$(sharedstatedir),g' \ -e 's,@localstatedir\@,$(localstatedir),g' \ -e 's,@libdir\@,$(libdir),g' \ -e 's,@includedir\@,$(includedir),g' \ -e 's,@infodir\@,$(infodir),g' \ -e 's,@mandir\@,$(mandir),g' \ -e 's,@enable_user\@,$(enable_user),g' \ -e 's,@enable_group\@,$(enable_group),g' \ -e 's,@enable_vty_group\@,$(enable_vty_group),g' \ -e 's,@quagga_statedir\@,$(quagga_statedir),g' \ -e 's,[@]PACKAGE_NAME[@],@PACKAGE_NAME@,g' \ -e 's,[@]PACKAGE_TARNAME[@],@PACKAGE_TARNAME@,g' \ -e 's,[@]PACKAGE_VERSION[@],@PACKAGE_VERSION@,g' \ -e 's,[@]PACKAGE_BUGREPORT[@],@PACKAGE_BUGREPORT@,g' \ -e 's,[@]CONFDATE[@],@CONFDATE@,g' \ -e 's,[@]target_cpu[@],$(target_cpu),g' \ -e 's,[@]target_host[@],$(target_host),g' \ -e 's,[@]target_os[@],$(target_os),g' # common options for pkgmk pkg_make_vars = exec_prefix=@exec_prefix@ prefix=@prefix@ \ builddir=@builddir@ srcdir=@srcdir@ \ top_builddir=@top_builddir@ top_srcdir=@top_srcdir@ \ abs_builddir=@abs_builddir@ abs_srcdir=@abs_srcdir@ \ abs_top_builddir=@abs_top_builddir@ abs_top_srcdir=@abs_top_srcdir@ # pkgmk: write the package to spool in build dir, to avoid root dependencies pkg_make = pkgmk -o -d @abs_builddir@ \ -f $< DESTDIR="$(DESTDIR)/" $(pkg_make_vars) # pkgtrans: write a pkg file stream, shame we cant pipe directly to it from # pkgmk.. pkg_trans = pkgtrans -s @abs_builddir@ "@abs_builddir@/$@" # pkginfo.package and prototype.package are all built sources #BUILT_SOURCES = pkginfo.daemons pkginfo.dev pkginfo.doc pkginfo.libs \ # prototype.daemons prototype.dev prototype.doc prototype.libs BUILT_SOURCES = $(pkg_pkginfos) pkginfo.tmpl $(pkg_prototypes) \ $(pkg_manifests) $(pkg_depends) quagga.init CLEANFILES = $(BUILT_SOURCES) $(pkg_packages) EXTRA_DIST = $(pkg_manifests:%=%.in) $(pkg_prototypes:%=%.in) \ $(pkg_names:%=pkginfo.%.tmpl.in) $(srcdir)/pkginfo.tmpl.in \ $(pkg_depends:%=%.in) quagga.init.in README.txt all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu solaris/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu solaris/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile installdirs: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am .PHONY: packages # pkgmk can only cope with a single pkginfo, cant 'stack' various # pkginfo template files and a package specific pkginfo file in the prototype # Create the package specific template here, and create the full pkginfo # by cating this and the common pkginfo.tmpl together. pkginfo.tmpl: $(srcdir)/pkginfo.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.tmpl: $(srcdir)/pkginfo.%.tmpl.in Makefile rm -f $@ $(edit) $< > $@ pkginfo.%.full: pkginfo.%.tmpl pkginfo.tmpl Makefile cat pkginfo.tmpl pkginfo.$*.tmpl > $@ # use 'edit' above to transform prototype.in to pkgmk acceptable prototype prototype.%: $(srcdir)/prototype.%.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the SMF manifest files %.xml: $(srcdir)/%.xml.in Makefile rm -f $@ $(edit) $< > $@ # use edit to construct the depend files depend.%: $(srcdir)/depend.%.in Makefile rm -f $@ $(edit) $< > $@ # method file (bit like init script) quagga.init: $(srcdir)/quagga.init.in Makefile rm -f $@ $(edit) $< > $@ # construct the pkg @PACKAGE_TARNAME@-%-$(pkg_name_rev).pkg: prototype.% \ depend.% quagga.init pkginfo.%.full ($(pkg_make) && \ $(pkg_trans) "QUAGGA$*") %.pkg.gz : %.pkg (gzip -c $< > $@) pkg-root-install: (cd $(top_builddir) && \ $(MAKE) DESTDIR=$(abs_builddir)/quagga-root install) packages: $(pkg_packages) #nodist_pkgdata_DATA = $(pkg_packages) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/tests/0000755000175000017500000000000012476521377011464 500000000000000quagga-0.99.24.1/tests/libzebra.tests/0000755000175000017500000000000012476521377014417 500000000000000quagga-0.99.24.1/tests/libzebra.tests/testnexthopiter.exp0000644000175000017500000000025112476520570020316 00000000000000set timeout 10 set testprefix "testnexthopiter " set aborted 0 spawn "./testnexthopiter" onesimple "simple" "Simple test passed." onesimple "prng" "PRNG test passed." quagga-0.99.24.1/tests/libzebra.tests/testcommands.exp0000644000175000017500000000130512476520570017547 00000000000000set timeout 30 set test_name "testcommands" if {![info exists env(QUAGGA_TEST_COMMANDS)]} { # sadly, the test randomly fails when configure parameters differ from # what was used to create testcommands.refout. this can be fixed by # shipping a matching vtysh_cmd.c, which we'll add after 0.99.23 unresolved "$test_name" exit 0 } spawn sh -c "./testcommands -e 0 < $env(srcdir)/testcommands.in | diff -au - $env(srcdir)/testcommands.refout" expect { eof { } timeout { exp_close fail "$test_name: timeout" } } catch wait result set os_error [lindex $result 2] set exit_status [lindex $result 3] if { $os_error == 0 && $exit_status == 0 } { pass "$test_name" } else { fail "$test_name" } quagga-0.99.24.1/tests/libzebra.tests/test-timer-correctness.exp0000644000175000017500000000024012476520570021470 00000000000000set timeout 10 set testprefix "test-timer-correctness" set aborted 0 spawn "./test-timer-correctness" onesimple "" "Expected output and actual output match." quagga-0.99.24.1/tests/libzebra.tests/tabletest.exp0000644000175000017500000000042112476520570017033 00000000000000set timeout 10 set testprefix "tabletest " set aborted 0 spawn "./tabletest" for {set i 0} {$i < 6} {incr i 1} { onesimple "cmp $i" "Verifying cmp"; } for {set i 0} {$i < 11} {incr i 1} { onesimple "succ $i" "Verifying successor"; } onesimple "pause" "Verified pausing" quagga-0.99.24.1/tests/libzebra.tests/Makefile.am0000644000175000017500000000014712476520570016367 00000000000000EXTRA_DIST = \ tabletest.exp \ test-timer-correctness.exp \ testcommands.exp \ testnexthopiter.exp quagga-0.99.24.1/tests/libzebra.tests/Makefile.in0000644000175000017500000003170712476521251016403 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = tests/libzebra.tests DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ tabletest.exp \ test-timer-correctness.exp \ testcommands.exp \ testnexthopiter.exp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/libzebra.tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/libzebra.tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/tests/bgpd.tests/0000755000175000017500000000000012476521377013541 500000000000000quagga-0.99.24.1/tests/bgpd.tests/testbgpmpattr.exp0000644000175000017500000000273012476520570017073 00000000000000set timeout 10 set testprefix "testbgpmpattr " set aborted 0 set color 1 spawn "./testbgpmpattr" # proc simpletest { start } { simpletest "IPv6: IPV6 MP Reach, global nexthop, 1 NLRI" simpletest "IPv6-2: IPV6 MP Reach, global nexthop, 2 NLRIs" simpletest "IPv6-default: IPV6 MP Reach, global nexthop, 2 NLRIs + default" simpletest "IPv6-lnh: IPV6 MP Reach, global+local nexthops, 2 NLRIs + default" simpletest "IPv6-nhlen: IPV6 MP Reach, inappropriate nexthop length" simpletest "IPv6-nhlen2: IPV6 MP Reach, invalid nexthop length" simpletest "IPv6-nhlen3: IPV6 MP Reach, nexthop length overflow" simpletest "IPv6-nhlen4: IPV6 MP Reach, nexthop length short" simpletest "IPv6-nlri: IPV6 MP Reach, NLRI bitlen overflow" simpletest "IPv4: IPv4 MP Reach, 2 NLRIs + default" simpletest "IPv4-nhlen: IPv4 MP Reach, nexthop lenth overflow" simpletest "IPv4-nlrilen: IPv4 MP Reach, nlri lenth overflow" simpletest "IPv4-MLVPN: IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs" simpletest "IPv6-bug: IPv6, global nexthop, 1 default NLRI" simpletest "IPv6-unreach: IPV6 MP Unreach, 1 NLRI" simpletest "IPv6-unreach2: IPV6 MP Unreach, 2 NLRIs" simpletest "IPv6-unreach-default: IPV6 MP Unreach, 2 NLRIs + default" simpletest "IPv6-unreach-nlri: IPV6 MP Unreach, NLRI bitlen overflow" simpletest "IPv4-unreach: IPv4 MP Unreach, 2 NLRIs + default" simpletest "IPv4-unreach-nlrilen: IPv4 MP Unreach, nlri length overflow" simpletest "IPv4-unreach-MLVPN: IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs" quagga-0.99.24.1/tests/bgpd.tests/testbgpmpath.exp0000644000175000017500000000034212476520570016672 00000000000000set timeout 10 set testprefix "testbgpmpath " set aborted 0 set color 1 spawn "./testbgpmpath" # proc simpletest { start } { simpletest "bgp maximum-paths config" simpletest "bgp_mp_list" simpletest "bgp_info_mpath_update" quagga-0.99.24.1/tests/bgpd.tests/testbgpcap.exp0000644000175000017500000000465212476520570016334 00000000000000set timeout 10 set testprefix "testbgpcap " set aborted 0 set color 1 spawn "./testbgpcap" # proc simpletest { start } { simpletest "MP4: MP IP/Uni" simpletest "MPv6: MP IPv6/Uni" simpletest "MP2: MP IP/Multicast" simpletest "MP3: MP IP6/MPLS-labeled VPN" simpletest "MP5: MP IP6/MPLS-VPN" simpletest "MP6: MP IP4/MPLS-laveled VPN" simpletest "MP8: MP unknown AFI/SAFI" simpletest "MP-short: MP IP4/Unicast, length too short (< minimum)" simpletest "MP-overflow: MP IP4/Unicast, length too long" simpletest "caphdr: capability header, and no more" simpletest "nodata: header, no data but length says there is" simpletest "padded: valid, with padding" simpletest "minsize: violates minsize requirement" simpletest "ORF: ORF, simple, single entry, single tuple" simpletest "ORF-many: ORF, multi entry/tuple" simpletest "ORFlo: ORF, multi entry/tuple, hdr length too short" simpletest "ORFlu: ORF, multi entry/tuple, length too long" simpletest "ORFnu: ORF, multi entry/tuple, entry number too long" simpletest "ORFno: ORF, multi entry/tuple, entry number too short" simpletest "ORFpad: ORF, multi entry/tuple, padded to align" simpletest "AS4: AS4 capability" simpletest "GR: GR capability" simpletest "GR-short: GR capability, but header length too short" simpletest "GR-long: GR capability, but header length too long" simpletest "GR-trunc: GR capability, but truncated" simpletest "GR-empty: GR capability, but empty." simpletest "MP-empty: MP capability, but empty." simpletest "ORF-empty: ORF capability, but empty." simpletest "AS4-empty: AS4 capability, but empty." simpletest "dyn-empty: Dynamic capability, but empty." simpletest "dyn-old: Dynamic capability (deprecated version)" simpletest "Cap-singlets: One capability per Optional-Param" simpletest "Cap-series: Series of capability, one Optional-Param" simpletest "AS4more: AS4 capability after other caps (singlets)" simpletest "AS4series: AS4 capability, in series of capabilities" simpletest "AS4real: AS4 capability, in series of capabilities" simpletest "AS4real2: AS4 capability, in series of capabilities" simpletest "DynCap: Dynamic Capability Message, IP/Multicast" simpletest "DynCapLong: Dynamic Capability Message, IP/Multicast, truncated" simpletest "DynCapPadded: Dynamic Capability Message, IP/Multicast, padded" simpletest "DynCapMPCpadded: Dynamic Capability Message, IP/Multicast, cap data padded" simpletest "DynCapMPCoverflow: Dynamic Capability Message, IP/Multicast, cap data != length" quagga-0.99.24.1/tests/bgpd.tests/ecommtest.exp0000644000175000017500000000031012476520570016163 00000000000000set timeout 10 set testprefix "ecommtest " set aborted 0 set color 0 spawn "./ecommtest" # proc simpletest { start } { simpletest "ipaddr" simpletest "ipaddr-so" simpletest "asn" simpletest "asn4" quagga-0.99.24.1/tests/bgpd.tests/aspathtest.exp0000644000175000017500000000407012476520570016352 00000000000000set timeout 10 set testprefix "aspathtest " set aborted 0 set color 1 spawn "./aspathtest" # proc onetest { test_name note start } { # proc headerline { line } { set parserno 0 proc parsertest { test_name } { global parserno headerline "test $parserno" onetest "parse $test_name" " ($parserno)" "$test_name:" onetest "parse $test_name +empty_prepend" " (#$parserno)" "empty prepend $test_name:" incr parserno 1 } set attrno 0 proc attrtest { test_name } { global attrno headerline "aspath_attr test $attrno" onetest "attr $test_name" " (#$attrno)" "$test_name" incr attrno 1 } parsertest "seq1" parsertest "seq2" parsertest "seq3" parsertest "seqset" parsertest "seqset2" parsertest "multi" parsertest "confed" parsertest "confed2" parsertest "confset" parsertest "confmulti" parsertest "seq4" parsertest "tripleseq1" parsertest "someprivate" parsertest "allprivate" parsertest "long" parsertest "seq1extra" parsertest "empty" parsertest "redundantset" parsertest "reconcile_lead_asp" parsertest "reconcile_new_asp" parsertest "reconcile_confed" parsertest "reconcile_start_trans" parsertest "reconcile_start_trans4" parsertest "reconcile_start_trans_error" parsertest "redundantset2" parsertest "zero-size overflow" parsertest "zero-size overflow + valid segment" parsertest "invalid segment type" for {set i 0} {$i < 10} {incr i 1} { onetest "prepend $i" "" "prepend test $i"; } for {set i 0} {$i < 5} {incr i 1} { onetest "aggregate $i" "" "aggregate test $i"; } for {set i 0} {$i < 5} {incr i 1} { onetest "reconcile $i" "" "reconcile test $i"; } for {set i 0} {$i < 22} {incr i 1} { onetest "compare $i" "" "left cmp "; } onetest "empty_get" "" "empty_get_test" attrtest "basic test" attrtest "length too short" attrtest "length too long" attrtest "incorrect flag" attrtest "as4_path, with as2 format data" attrtest "as4, with incorrect attr length" attrtest "basic 4-byte as-path" attrtest "4b AS_PATH: too short" attrtest "4b AS_PATH: too long" attrtest "4b AS_PATH: too long2" attrtest "4b AS_PATH: bad flags" attrtest "4b AS4_PATH w/o AS_PATH" attrtest "4b AS4_PATH: confed" quagga-0.99.24.1/tests/bgpd.tests/Makefile.am0000644000175000017500000000015412476520570015507 00000000000000EXTRA_DIST = \ aspathtest.exp \ ecommtest.exp \ testbgpcap.exp \ testbgpmpath.exp \ testbgpmpattr.exp quagga-0.99.24.1/tests/bgpd.tests/Makefile.in0000644000175000017500000003167712476521251015533 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = tests/bgpd.tests DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = \ aspathtest.exp \ ecommtest.exp \ testbgpcap.exp \ testbgpmpath.exp \ testbgpmpattr.exp all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/bgpd.tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/bgpd.tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/tests/testcommands.refout0000644000175000017500000042172412476520570015337 00000000000000execute relaxed 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' execute strict 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (authentication|) (message-digest|null) (message-digest-key|) <1-255> md5 KEY': '0', '1.2.3.4', 'authentication', 'null', 'message-digest-key', '1', 'VARIABLE' complete 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE'@23: rv==0 'KEY' 'The OSPF password (key)' execute relaxed 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' execute strict 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'dead-interval', '1', 'hello-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1' complete 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' execute strict 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '0', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'dead-interval', '1', 'retransmit-interval', '1' complete 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==2 describe 'area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'hello-interval', '1', 'dead-interval', '1' complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'retransmit-interval', '1', 'retransmit-interval', '1', 'transmit-delay', '1', 'dead-interval', '1' complete 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' execute strict 'clear bgp 1 out'@4: rv==0, 'clear bgp <1-4294967295> out': '1' complete 'clear bgp 1 out'@4: rv==7 'out' describe 'clear bgp 1 out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' execute strict 'clear bgp ipv6 2001:db8::1 out'@4: rv==0, 'clear bgp ipv6 (A.B.C.D|X:X::X:X) out': '2001:db8::1' complete 'clear bgp ipv6 2001:db8::1 out'@4: rv==7 'out' describe 'clear bgp ipv6 2001:db8::1 out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' execute strict 'clear bgp view VARIABLE * soft'@4: rv==0, 'clear bgp view WORD * soft': 'VARIABLE' complete 'clear bgp view VARIABLE * soft'@4: rv==7 'soft' describe 'clear bgp view VARIABLE * soft'@4: rv==0 'soft' 'Soft reconfig' execute relaxed 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' execute strict 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0, 'clear ip bgp A.B.C.D ipv4 (unicast|multicast) out': '1.2.3.4', 'multicast' complete 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==7 'out' describe 'clear ip bgp 1.2.3.4 ipv4 multicast out'@4: rv==0 'out' 'Soft reconfig outbound update' execute relaxed 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' execute strict 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0, 'ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) (<0-4294967295>|infinite) (no-autoconfig|)': '2001:db8::/32', 'infinite', 'infinite', 'no-autoconfig' complete 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==7 'no-autoconfig' describe 'ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig'@11: rv==0 'no-autoconfig' 'Do not use prefix for autoconfiguration' execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@5: rv==0 '<1-255>' 'Distance value for this prefix' execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@9: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@10: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@11: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@12: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@14: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@15: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@16: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@17: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@18: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@19: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@20: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@21: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@22: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@23: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@24: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@25: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@35: rv==2 execute relaxed 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==0, 'ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>': '2001:db8::/32', '2001:db8::1', 'VARIABLE', '1' execute strict 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 complete 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 describe 'ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1'@40: rv==2 execute relaxed 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' execute strict 'network 1.0.0.0/8 area 0'@23: rv==0, 'network A.B.C.D/M area (A.B.C.D|<0-4294967295>)': '1.0.0.0/8', '0' complete 'network 1.0.0.0/8 area 0'@23: rv==2 describe 'network 1.0.0.0/8 area 0'@23: rv==0 '<0-4294967295>' 'OSPF area ID as a decimal value' 'A.B.C.D' 'OSPF area ID in IP address format' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'hello-interval', 'transmit-delay' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==7 'transmit-delay' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay'@23: rv==0 'transmit-delay' 'Seconds' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'hello-interval', 'dead-interval', 'retransmit-interval', 'transmit-delay' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==7 'transmit-delay' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay'@23: rv==0 'transmit-delay' 'Seconds' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'retransmit-interval', 'dead-interval', 'retransmit-interval', 'hello-interval' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==7 'hello-interval' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval'@23: rv==0 'hello-interval' 'Link state transmit delay' execute relaxed 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' execute strict 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0, 'no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval) (hello-interval|retransmit-interval|transmit-delay|dead-interval)': '1.2.3.4', '1.2.3.4', 'transmit-delay', 'retransmit-interval', 'retransmit-interval', 'hello-interval' complete 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==7 'hello-interval' describe 'no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval'@23: rv==0 'hello-interval' 'Link state transmit delay' execute relaxed 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@17: rv==0, 'no bgp graceful-restart' complete 'no bgp graceful-restart'@17: rv==7 'graceful-restart' describe 'no bgp graceful-restart'@17: rv==0 'graceful-restart' 'Graceful restart capability parameters' execute relaxed 'no bgp graceful-restart'@18: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@18: rv==2 complete 'no bgp graceful-restart'@18: rv==2 describe 'no bgp graceful-restart'@18: rv==2 execute relaxed 'no bgp graceful-restart'@19: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@19: rv==2 complete 'no bgp graceful-restart'@19: rv==2 describe 'no bgp graceful-restart'@19: rv==2 execute relaxed 'no bgp graceful-restart'@20: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@20: rv==2 complete 'no bgp graceful-restart'@20: rv==2 describe 'no bgp graceful-restart'@20: rv==2 execute relaxed 'no bgp graceful-restart'@21: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@21: rv==2 complete 'no bgp graceful-restart'@21: rv==2 describe 'no bgp graceful-restart'@21: rv==2 execute relaxed 'no bgp graceful-restart'@22: rv==0, 'no bgp graceful-restart' execute strict 'no bgp graceful-restart'@22: rv==2 complete 'no bgp graceful-restart'@22: rv==2 describe 'no bgp graceful-restart'@22: rv==2 execute relaxed 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' execute strict 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' complete 'no ipv6 nd mtu 1'@11: rv==2 describe 'no ipv6 nd mtu 1'@11: rv==0 '<1-65535>' 'MTU in bytes' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0 'in' 'Filter incoming updates' execute relaxed 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@17: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@17: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@18: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@18: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@19: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@19: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@20: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@20: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@21: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@21: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' execute strict 'no neighbor 2001:db8::1 send-community both'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) send-community (both|extended|standard)': '2001:db8::1', 'both' complete 'no neighbor 2001:db8::1 send-community both'@22: rv==7 'both' describe 'no neighbor 2001:db8::1 send-community both'@22: rv==0 'both' 'Send Standard and Extended Community attributes' execute relaxed 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@17: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@17: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@18: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@18: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@19: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@19: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@20: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@20: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@21: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@21: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' execute strict 'no neighbor VARIABLE maximum-prefix'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) maximum-prefix': 'VARIABLE' complete 'no neighbor VARIABLE maximum-prefix'@22: rv==7 'maximum-prefix' describe 'no neighbor VARIABLE maximum-prefix'@22: rv==0 'maximum-prefix' 'Maximum number of prefix accept from this peer' execute relaxed 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' execute strict 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'isis', '0', '2', 'VARIABLE' complete 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==7 '2' describe 'redistribute isis route-map VARIABLE metric 0 metric-type 2'@23: rv==0 '2' 'Set OSPF External Type 2 metrics' execute relaxed 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' execute strict 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'rip', '0', '1', 'VARIABLE' complete 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==7 '1' describe 'redistribute rip metric 0 route-map VARIABLE metric-type 1'@23: rv==0 '1' 'Set OSPF External Type 1 metrics' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show bgp community VARIABLE local-AS no-export VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@1: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@2: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' execute strict 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-export', 'no-export', 'no-export' complete 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==7 'no-export' describe 'show bgp ipv6 community no-advertise no-export no-export no-export'@4: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' execute strict 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'local-AS', 'no-advertise' complete 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' execute strict 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'VARIABLE', 'local-AS' complete 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==7 'exact-match' describe 'show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp view VARIABLE'@1: rv==4 execute strict 'show bgp view VARIABLE'@1: rv==4 complete 'show bgp view VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE'@1: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' execute strict 'show bgp view VARIABLE'@2: rv==0, 'show bgp view WORD': 'VARIABLE' complete 'show bgp view VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE'@2: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' execute strict 'show bgp view VARIABLE'@4: rv==0, 'show bgp view WORD': 'VARIABLE' complete 'show bgp view VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE'@4: rv==0 'WORD' 'View name' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'no-export', 'no-export', 'local-AS', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertise', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@1: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@2: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' execute strict 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'no-export', 'VARIABLE', 'no-advertise' complete 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==7 'no-advertise' describe 'show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise'@4: rv==0 'AA:NN' 'community number' 'no-advertise' 'Do not advertise to any peer (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' execute strict 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'unicast', 'VARIABLE', 'local-AS', 'no-export', 'VARIABLE' complete 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==2 describe 'show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv6', 'multicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' execute strict 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'local-AS', 'no-advertise', 'VARIABLE' complete 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==2 describe 'show ip bgp community no-advertise local-AS no-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'VARIABLE', 'no-advertise', 'local-AS' complete 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'local-AS', 'VARIABLE' complete 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' execute strict 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-export', 'VARIABLE', 'no-export', 'local-AS' complete 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==2 describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' execute strict 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'no-export', 'VARIABLE', 'VARIABLE' complete 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==2 describe 'show ipv6 bgp community no-export no-export VARIABLE VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' execute strict 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABLE', 'local-AS', 'no-advertise', 'no-advertise' complete 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' execute strict 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'local-AS', 'VARIABLE' complete 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' execute strict 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'local-AS', 'local-AS', 'no-export', 'no-export' complete 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community local-AS local-AS no-export no-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==7 'exact-match' describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' execute strict 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0, 'show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'no-export', 'no-export', 'local-AS', 'no-export' complete 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==7 'exact-match' describe 'show ipv6 mbgp community no-export no-export local-AS no-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' execute strict 'show ipv6 ospf6 database as-external dump'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' complete 'show ipv6 ospf6 database as-external dump'@2: rv==7 'dump' describe 'show ipv6 ospf6 database as-external dump'@2: rv==0 'dump' 'Dump LSAs' execute relaxed 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' execute strict 'show ipv6 ospf6 database as-external dump'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) (detail|dump|internal)': 'as-external', 'dump' complete 'show ipv6 ospf6 database as-external dump'@4: rv==7 'dump' describe 'show ipv6 ospf6 database as-external dump'@4: rv==0 'dump' 'Dump LSAs' execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==7 'detail' describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@2: rv==0 'detail' 'Display details of LSAs' execute relaxed 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' execute strict 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'inter-prefix', '1.2.3.4', 'detail' complete 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==7 'detail' describe 'show ipv6 ospf6 database inter-prefix 1.2.3.4 detail'@4: rv==0 'detail' 'Display details of LSAs' execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==7 'internal' describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@2: rv==0 'internal' 'Display LSA's internal information' execute relaxed 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' execute strict 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0, 'show ipv6 ospf6 database (router|network|inter-prefix|inter-router|as-external|group-membership|type-7|link|intra-prefix) A.B.C.D (detail|dump|internal)': 'intra-prefix', '1.2.3.4', 'internal' complete 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==7 'internal' describe 'show ipv6 ospf6 database intra-prefix 1.2.3.4 internal'@4: rv==0 'internal' 'Display LSA's internal information' execute relaxed 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0, 'area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> (hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>': '1.2.3.4', '1.2.3.4', 'hello-interval', '1', 'dead-interva', '1', 'retransmit-interval', '1', 'transmit-delay', '1' execute strict 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 complete 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==2 describe 'area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1'@23: rv==0 '<1-65535>' 'Seconds' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' execute strict 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0, 'show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABL', 'no-agdvertise', 'locl-AS', 'no-advertise' complete 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==7 'exact-match' describe 'show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' execute strict 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'local-AS', 'no-expor', 'no-xport', 'VARIABCLE' complete 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==2 describe 'show bgp ipv6 community local-AS no-expor no-xport VARIABCLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-adsertise', 'local-AS', 'no8-advertise', 'VARIABLE' complete 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==2 describe 'show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' execute strict 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no6-export', 'lcal-AS', 'local-AS' complete 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==7 'local-AS' describe 'show bgp ipv6 community no-advertise no6-export lcal-AS local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' execute strict 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-advertise', 'no-advertise', 'no-advertiseno-xport', 'exact-math' complete 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==2 describe 'show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' execute strict 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'local-AS', 'no-adertise', 'no-adve-tie' complete 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==2 describe 'show bgp ipv6 community no-export local-AS no-adertise no-adve-tie'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' execute strict 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0, 'show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'yno-advertis', 'VAyRIABLE', 'no-advertise', 'VARIABLE' complete 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==2 describe 'show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@1: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@2: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' execute strict 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VAR0IABLE', 'ipv4', 'unicast', 'local-AS', 'no-advertie', 'no-advertise', 'local-AS' complete 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==7 'local-AS' describe 'show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS'@4: rv==0 'AA:NN' 'community number' 'local-AS' 'Do not send outside local AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@1: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@2: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' execute strict 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0, 'show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLE', 'ipv4', 'multicast', 'local-AS', 'VARIABLE', 'loqal-AS', 'no-export' complete 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==7 'no-export' describe 'show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export'@4: rv==0 'AA:NN' 'community number' 'no-export' 'Do not export to next AS (well-known community)' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' execute strict 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-expor', 'VARIABLEono-export', 'VARIAuBLE' complete 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==2 describe 'show ip bgp community no-expor VARIABLEono-export VARIAuBLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@1: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' execute strict 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0, 'show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'VARIABLElocal-AS', 'no-advertise', 'local-AS', 'xack-match' complete 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==2 describe 'show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@1: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' execute strict 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0, 'show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'unicast', 'no-advertise', 'no-export', 'no-advrtWise', 'mno-export' complete 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==7 'exact-match' describe 'show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' execute strict 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'noeexport', 'VARIABLE', 'VARIABLE', 'no-aMdverise' complete 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==2 describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' execute strict 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'no-export', 'loal-AS', 'noK-advertise', 'VARIABLE' complete 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==2 describe 'show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@2: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' execute strict 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match': 'VARIABaE', 'no-export', 'no-adertise', 'lo0cal-AS' complete 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==7 'exact-match' describe 'show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match'@4: rv==0 'exact-match' 'Exact match of the communities' execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==2 describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@2: rv==0 'AA:NN' 'community number' execute relaxed 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' execute strict 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0, 'show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)': 'wARIBLE', 'VARIABLE', '8ARIABLE' complete 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==2 describe 'show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE'@4: rv==0 'AA:NN' 'community number' execute relaxed 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@14: rv==7 'bgp' describe 'redistribute bgp'@14: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@15: rv==7 'bgp' describe 'redistribute bgp'@15: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' execute strict 'redistribute bgp'@16: rv==0, 'redistribute (kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp)': 'bgp' complete 'redistribute bgp'@16: rv==7 'bgp' describe 'redistribute bgp'@16: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' execute strict 'redistribute bgp'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', '(null)' complete 'redistribute bgp'@23: rv==7 'bgp' describe 'redistribute bgp'@23: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' execute strict 'redistribute bgp'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel)': 'bgp' complete 'redistribute bgp'@24: rv==7 'bgp' describe 'redistribute bgp'@24: rv==0 'bgp' 'Border Gateway Protocol (BGP)' execute relaxed 'redistribute bgp m 10'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) metric <0-16>': 'bgp', '10' execute strict 'redistribute bgp m 10'@14: rv==2 complete 'redistribute bgp m 10'@14: rv==2 describe 'redistribute bgp m 10'@14: rv==0 '<0-16>' 'Metric value' execute relaxed 'redistribute bgp m 10'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) metric <0-16>': 'bgp', '10' execute strict 'redistribute bgp m 10'@15: rv==2 complete 'redistribute bgp m 10'@15: rv==2 describe 'redistribute bgp m 10'@15: rv==0 '<0-16>' 'Metric value' execute relaxed 'redistribute bgp m 10'@23: rv==3 execute strict 'redistribute bgp m 10'@23: rv==2 complete 'redistribute bgp m 10'@23: rv==3 describe 'redistribute bgp m 10'@23: rv==3 execute relaxed 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' execute strict 'redistribute bgp metric 10 metric-type 1'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '10', '1', '(null)' complete 'redistribute bgp metric 10 metric-type 1'@23: rv==7 '1' describe 'redistribute bgp metric 10 metric-type 1'@23: rv==0 '1' 'Set OSPF External Type 1 metrics' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0, 'redistribute (kernel|connected|static|ospf|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@14: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0, 'redistribute (kernel|connected|static|ospf6|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@15: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0, 'redistribute (kernel|connected|static|rip|isis|bgp|babel) {metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'bgp', '(null)', '(null)', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@23: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' execute strict 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0, 'redistribute (kernel|connected|static|ripng|isis|bgp|babel) route-map WORD': 'bgp', 'RMAP_REDIST_BGP' complete 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==2 describe 'redistribute bgp route-map RMAP_REDIST_BGP'@24: rv==0 'WORD' 'Route map name' execute relaxed 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' execute strict 'default-information originate metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '1', '(null)' complete 'default-information originate metric-type 1 metric 10'@23: rv==2 describe 'default-information originate metric-type 1 metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' execute strict 'default-information originate always metric-type 1 metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '10', '1', '(null)' complete 'default-information originate always metric-type 1 metric 10'@23: rv==2 describe 'default-information originate always metric-type 1 metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' execute strict 'default-information originate route-map RMAP_DEFAULT'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '(null)', '(null)', 'RMAP_DEFAULT' complete 'default-information originate route-map RMAP_DEFAULT'@23: rv==2 describe 'default-information originate route-map RMAP_DEFAULT'@23: rv==0 'WORD' 'Pointer to route-map entries' execute relaxed 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' execute strict 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': '(null)', '10', '(null)', 'RMAP_DEFAULT' complete 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==2 describe 'default-information originate route-map RMAP_DEFAULT metric 10'@23: rv==0 '<0-16777214>' 'OSPF metric' execute relaxed 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' execute strict 'default-information originate always metric-type 2 metric 23'@23: rv==0, 'default-information originate {always|metric <0-16777214>|metric-type (1|2)|route-map WORD}': 'always', '23', '2', '(null)' complete 'default-information originate always metric-type 2 metric 23'@23: rv==2 describe 'default-information originate always metric-type 2 metric 23'@23: rv==0 '<0-16777214>' 'OSPF metric' quagga-0.99.24.1/tests/testcommands.in0000644000175000017500000003166112476520570014436 00000000000000# # # Some randomly chosen valid commands # # area 0 virtual-link 1.2.3.4 authentication null message-digest-key 1 md5 VARIABLE area 0 virtual-link 1.2.3.4 dead-interval 1 hello-interval 1 retransmit-interval 1 transmit-delay 1 area 0 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 dead-interval 1 retransmit-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 hello-interval 1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval 1 retransmit-interval 1 transmit-delay 1 dead-interval 1 clear bgp 1 out clear bgp ipv6 2001:db8::1 out clear bgp view VARIABLE * soft clear ip bgp 1.2.3.4 ipv4 multicast out ipv6 nd prefix 2001:db8::/32 infinite infinite no-autoconfig ipv6 route 2001:db8::/32 2001:db8::1 VARIABLE 1 network 1.0.0.0/8 area 0 no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval hello-interval transmit-delay no area 1.2.3.4 virtual-link 1.2.3.4 hello-interval dead-interval retransmit-interval transmit-delay no area 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval dead-interval retransmit-interval hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 transmit-delay retransmit-interval retransmit-interval hello-interval no bgp graceful-restart no ipv6 nd mtu 1 no neighbor 1.2.3.4 distribute-list 1 in no neighbor 2001:db8::1 send-community both no neighbor VARIABLE maximum-prefix redistribute isis route-map VARIABLE metric 0 metric-type 2 redistribute rip metric 0 route-map VARIABLE metric-type 1 show bgp community VARIABLE local-AS no-export VARIABLE exact-match show bgp ipv6 community no-advertise no-export no-export no-export show bgp ipv6 community VARIABLE local-AS local-AS no-advertise exact-match show bgp ipv6 community VARIABLE local-AS VARIABLE local-AS exact-match show bgp view VARIABLE show bgp view VARIABLE ipv4 multicast community no-export no-export local-AS VARIABLE show bgp view VARIABLE ipv4 unicast community local-AS no-advertise no-advertise local-AS show bgp view VARIABLE ipv4 unicast community no-export VARIABLE no-advertise show bgp view VARIABLE ipv4 unicast community VARIABLE local-AS no-export VARIABLE show bgp view VARIABLE ipv6 multicast community no-advertise VARIABLE no-advertise local-AS show ip bgp community no-advertise local-AS no-advertise VARIABLE show ip bgp ipv4 unicast community no-advertise VARIABLE no-advertise local-AS exact-match show ip bgp ipv4 unicast community no-export VARIABLE local-AS VARIABLE exact-match show ip bgp ipv4 unicast community no-export VARIABLE no-export local-AS exact-match show ipv6 bgp community no-export no-export VARIABLE VARIABLE show ipv6 bgp community VARIABLE local-AS no-advertise no-advertise exact-match show ipv6 mbgp community local-AS local-AS local-AS VARIABLE exact-match show ipv6 mbgp community local-AS local-AS no-export no-export exact-match show ipv6 mbgp community no-export no-export local-AS no-export exact-match show ipv6 ospf6 database as-external dump show ipv6 ospf6 database inter-prefix 1.2.3.4 detail show ipv6 ospf6 database intra-prefix 1.2.3.4 internal # # # Slightly Fuzzed commands # # a8ra 0 range 1.0.0.0/8 adverOise accept-lifetime VARIABE 1 VA6IABLE 19I3 VARIABLE 1 VARIABLE 1993 arAea 1.2.M.4 virtual-link 1.2.3.4 dead-interval 1 dead-interval 1 dead-inter6val 1 transmit-delay 1 area 0 virtu0al-link 1.2.3.i hello-interval 1 ello-interval 1 transmit-delay 1 retransmit-interval 1 area 0 virtual-lin 1.2.3.4 retransmit-interval 1 tranwmit-delay 1 retransmit-interval 1 retransmit-interval 1 area 0 virtual-link 1.2.3.4 retransmit-interal 1 trasmit-dely 1 area 1.2.3.4 virtual-link 1.2.3.4 deadCinterval 1 dead-intervalK 1 retransmit-interval 1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 dead-intervalo I1 dead-interval 1 retransmit-interval1 dead-interval 1 area 1.2.3.4 virtual-link 1.2.3.4 hello-interval 1 dead-interva 1 retransmit-interval 1 transmit-delay 1 area 1.2.3.4 virtuyl-link 1.2.3.4 dead-interval 1 dead-inervalI 1 retransmit-interval 1 dead-interval 1 area 1.2.3.4 virual-link 1.2.34 retransmit-interval 1 dead-interval 1 dead-interva 1 area1.2.83.4 virtual-link 1.2.3.4 retra0smit-interval 1 dead-interval 1 dead-interval 1 clear bgAp 2001g:dbK::1 clear ip bgp 1.2.3.4 pv4 mlticat out cleau bg i2001:db8::1 rsclient de:ug ospf6 messag2 lsreq :recv how ip bgp communiQy no-advertise no-adve:tise no-advertise ip route 1.0Q0.0/8 1.2.3.s4 reGject ipv6 nd prefix 2O01:db8::/32 0 infinEite off-link ipv6 nwd prefix 2001:db8::/32 0 infinite oUUff-link ipv6 route 2001:db8::/32q2001:db8:k: blackhole 1 kshow ip rIute bgp matcch peer .2.30.4 mcogin mhow ipv6 mbgp community o-advertise yocal-AS no-advertise neighbor1.2..4 attribute-unchnged next-hop neihbcr 2001:d b8::1 distribute-list 1 in nko key-tqring no area 0 viertual-link 1.2.3k.4 retransmit-iterval retransmit-interval retransmit-interval hello-interval no area 0 virtual-link 1.2.3.4 dead-intaerval dead-intervIl hello-interval retransmit-interval no area 0 virtual-link 1.2.3.4 retransmit-interval retransmit-intervIl dead-interval tranImit-deqlay no area 0 virtual-link S1.2.3.4 d-ead-interval hello-interval transmit-deay transmit-delay no area 1.2.3.4 virtua -link 1.2.3.4 transmit-delay hello-interval hello-interval retransmt-interval no area 1.2.3.4 virtual-link 1.2.3.4 dea-iterval retransmit-interva- dead-interval hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 hello-interSval dead-interval retransmit-interval transmitdelay no a:rea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interSvalW dead-interval retransmit-interval hello-interval noarea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval trynsmit-delay hello-interval no area 1.2.3.4 virtual-link 1.2.3.4 transmt:delay retransmit-interval retransmit-interval dead-Mnterval no ares 1.2.3.4 virtual-link 1.2.3.4 dead-interval retransmit-interval dead-inesval retransmit-interval no ayrea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval transmi-delay hello-interval no bg2 grace2fuy-restart no debug ospk6 nter2face noimatch ipv6 addrMss VARIABLE nomStch iA next-hop prefix-list no neighbCr 200 :db8::1oroute-map VARIABLE export no neighbor VARIABLE attributeaw8changed next-hop no orea 1.2.3.4 virtual-link 1.2.3.4 retransmit-interval ead-interval retransmit-inteSval hello-interval no ospcdead-inkerval no redistribute kernelrote-map VARIABLE metric 0 no redistribute s4taik metric 0 nos Ceighbor 1.2.3.4 route-mapEVARIABLE in o :neighbor VAIABLE attribute-unchanged next-hop ooa router ip redistribute isis meGtric-type2 Q route-map VARIABLE redistribute static metric-type 1 metri 0 rowute-map VARIABLE set-Koveroadbit sh2w ipv6 mbgp comAunity VARIABLE shgw bgp ipv6 community no-export VARIABLE no-xport no-expmrt shiow Wgp neighbors shoAw ip bgpipv4 unicast com6munity no-export no-export no-advertise no-export exact-match sho bgp view gARIABLE nyeighbors 2001:db8::1 received-routes shoow bgp ommunity local-AS no--export show6 bgp community no-advertise local4-AS no-advertise VARIABLE exact-math show8 bgp view VARIABLE ipv4 multicast community ARIABLE VARIABLE local-S show bgp cCommunity VARIABLE VOARIABL no-advertise show bgp cimAunity loal-AS local-AS no-export local-AS show bgp cmmunity n-advertise no-export local-S no-advertise show bgp communi0y no-export no-Cexport no-0xport no-export show bgp communityOlocal-A no-advertise local-WAS show bgp community VARIABL no-agdvertise locl-AS no-advertise exact-match show bgp communiy no-export no-adsvertise VARIABLOE local-AS show bgp communiYty no-export VARIABLE VARIABLE locali-AS exact-math show bgp commuUityW no-advertis local-AS no-advertise no-advertise show bgp commuWnity VAIABLE local-AS no-advertise n-export show bgp com:unity no-exportqno-export VARIABLE no-expoIrt exact-match show bgp ipv6 community local-AS no-expor no-xport VARIABCLE show bgp ipv6 community no-adsertise local-AS no8-advertise VARIABLE show bgp ipv6 community no-advertise no6-export lcal-AS local-AS show bgp ipv6 community no-advertise no-advertise no-advertiseno-xport exact-math show bgp ipv6 comm-unity no-advertise no-export local-AS local-kS exact-match show bgp ipv6 community no-export local-AS no-adertise no-adve-tie show bgp ipv6 community yno-advertis VAyRIABLE no-advertise VARIABLE show bgp naighbors 201:db8::1 rUeceived-routes show bgp viewVAIABLE ipv4 multicast community VARIABLE4no-export no-advertise local-AS show bgp view VAR0IABLE ipv4 unicast community local-AS no-advertie no-advertise local-AS show bgp view VARIABLE ipv4 multicast community local-AS VARIABLE loqal-AS no-export show bgp view VARIABLE ipv4 multicast omsunity local-AS VARIABLE no-advertise nUo-export show bgp view VARIABLE ipv4 mutiast community no-export no-export VARIBLE no-export show bgp view VARIABLE ipv4 unicast 0community VARIABqLE local-AS no-export VARIABwE show bgp view VARIABLE ipv4 unicast communeity no-export AcRIABLE no-advertise local-AS show bgp view VARIABLE ipv4 unicasU comunity no-export VARIABL no-advertise show bgp view VARIABLE ipv6 unicast cocmmunity VARIABLE no-advet6ise VARIABLE show bgp view VARIABLE ipvk4 unicast communty no-advertie local-AS local-AS no-export show bgp view VARIALE ipv4 multicast cyommunity no-xport local-AS local-AS show i6 bge community no-export VARIABLE no-advegtise VARIABLE exact-match show iI bgp community no-advertise no-ad2vertsse VARIABLE exact-match show ip6osp6 database dump show ipA6 bgp community local-AS local-AS no-advertse lo:cal-AS show ip bg comunity VARIABLE lcal-AS no-advertise show ip bgp communityno-export2no-export no-advertise locaE-AS Show ip bgp community no-export loqcal-AS no-adverise no-export show ip bgp community no-expor VARIABLEono-export VARIAuBLE show ip bgp community VARIABLElocal-AS no-advertise local-AS xack-match show ip bgp cWmmunity no-expoWrt VARIABLE no-advertise VARIABLEexact-match show ip bgp ip4 nicast community no-advertise no-expoIt local-AS local-AS exact-match show ip bgp ipAv4 multicast community no-export no-export no-export no-advertiqe exact-mach show ip bgp ipv4 Aulticast community no-advertise VARIABLE no-advertisKe no-exort show ip bgp ipv4 meuqlticast community VARIABLE VARIABLE no-export n-export show ip bgp ipv4 mlticast coQmmunity localg-AS local-AS no-advertise local-AS show ip bgp ipv4 multicast communiy VARIABLE no-export VARIABLE no-advertise yxact-atch show ip bgp ipv4 unicast commu0nity local-AS no-export no-exrt VARIABLE exact-match show ip bgp ipv4 unicast community no-advertise no-export no-advrtWise mno-export exact-match showip bgp ipv4 unicast community no-export VARIABLE no-exp-ort VAR6IABLE exact-match show ip bgp ipv4 unicat community no-exportlocal-AS VARIABLE no-export exa0t-match show ip bgp ipv4 unicst community no-advertiseG local-AS no-advertise show ip bgp i:v4 multicast community VARIABLE VARIABLE VARIABLE no-export eMxact-match show ip bgp Mv4 unicast community no-export VARIABLE VARIABLE VAoRIABLE show ipgexecommunity-list 1 show ipkv6 bgp community no-export no-export VARIABL VARIBLE show ipv6 bgp commu2nity local-AS local-AS noEadvertise local-AS show ipv6 bgp communitK VARIABLE lcocal-AS no-advertie no-advertise exact-match show ipv6 bgp community noeexport VARIABLE VARIABLE no-aMdverise exact-match show ipv6 bgp community no-export loal-AS noK-advertise VARIABLE show ipv6 bgp community VARIABaE no-export no-adertise lo0cal-AS exact-match show ipv6 bgp community wARIBLE VARIABLE 8ARIABLE show ipv6 bgp comu-ity VARIABLE local-AS no-advertise no-export exact-match show ipv6 bgp comunity no- export local-AS no-advertisge VARIABLE show ipv6 bgp ommunity sno-advcrtise VARIABLE no-export no-advertise exact-match show ipv6 igp community no-advertise no-advertise no-ecxpo0rt no-export show ipv6 mb communyty VARIABLE show ipv6 osp8f6 database nQtwork adv-ruter 1.2.3.4 detail show ipv6 ospf6 dataase type-7 adv-router 1.2.3.4 inernal show ipv6 ospf6 Edatabase intuer8-prefix 1.2.3.4 detail show ipvq6 ospf6 database as-externa detil show ip Wbgp ipv4 unicast community no-advertise no-exprt no-export VARIABLEK exact-match show ip Ybgp attribute-in ufo showMbgp ipv6 community ARIABLE local-AS local-AS no8advertise exact-match show p bgp community no-dvertise no-export no-advertiseIno-export exact-match show uipv6 mbgp coqmmunKty VARIABLE shQw ipv6 mbgp community no-advetise local-AS no-export no-export ex8ct-match shuw ipv6 mbgp community VARIABLyUE no-export no-export no-advertise shw bgp view VARIABLE ipv4 un0icast Gcommunity no-export VARIABLE no-advertise sow ip bgp ipv4 mulicast community no-export no-adertise no-export no-advertise sow ipv6 ospf6 databIase as-external adv-router 1.2.3.4 Whow bgp view VARIAeBLE ipv4 unicast community local-AS no-advrtise no-advertise local-AS Wneighbor 1.2.3.4 dot-capabiliy-negotiate # # # Some teststrings explicitly used for keyword commands # # redistribute bgp redistribute bgp m 10 redistribute bgp metric 10 metric-type 1 redistribute bgp metric 10 metric 10 redistribute bgp route-map RMAP_REDIST_BGP default-information originate metric-type 1 metric 10 default-information originate always metric-type 1 metric 10 default-information originate route-map RMAP_DEFAULT default-information originate route-map RMAP_DEFAULT metric 10 default-information originate always metric-type 2 metric 23 quagga-0.99.24.1/tests/global-conf.exp0000644000175000017500000000000012476520570014265 00000000000000quagga-0.99.24.1/tests/test-stream.c0000644000175000017500000000347312476520570014021 00000000000000/* Simple stream test. * * Copyright (C) 2006 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include static long int ham = 0xdeadbeefdeadbeef; struct thread_master *master; static void print_stream (struct stream *s) { size_t getp = stream_get_getp (s); printf ("endp: %ld, readable: %ld, writeable: %ld\n", stream_get_endp (s), STREAM_READABLE (s), STREAM_WRITEABLE (s)); while (STREAM_READABLE (s)) { printf ("0x%x ", *stream_pnt (s)); stream_forward_getp (s, 1); } printf ("\n"); /* put getp back to where it was */ stream_set_getp (s, getp); } int main (void) { struct stream *s; s = stream_new (1024); stream_putc (s, ham); stream_putw (s, ham); stream_putl (s, ham); stream_putq (s, ham); print_stream (s); stream_resize (s, stream_get_endp (s)); print_stream (s); printf ("c: 0x%hhx\n", stream_getc (s)); printf ("w: 0x%hx\n", stream_getw (s)); printf ("l: 0x%x\n", stream_getl (s)); printf ("q: 0x%lx\n", stream_getq (s)); return 0; } quagga-0.99.24.1/tests/test-sig.c0000644000175000017500000000330112476520570013276 00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "lib/log.h" #include "lib/memory.h" void sighup (void) { printf ("processed hup\n"); } void sigusr1 (void) { printf ("processed usr1\n"); } void sigusr2 (void) { printf ("processed usr2\n"); } struct quagga_signal_t sigs[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGUSR2, .handler = &sigusr2, } }; struct thread_master *master; struct thread t; int main (void) { master = thread_master_create (); signal_init (master, array_size(sigs), sigs); zlog_default = openzlog("testsig", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG); zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); while (thread_fetch (master, &t)) thread_call (&t); exit (0); } quagga-0.99.24.1/tests/test-segv.c0000644000175000017500000000316012476520570013463 00000000000000/* * SEGV / backtrace handling test. * * copied from test-sig.c * * Copyright (C) 2013 by David Lamparter, Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "lib/log.h" #include "lib/memory.h" struct quagga_signal_t sigs[] = { }; struct thread_master *master; int threadfunc (struct thread *thread) { int *null = NULL; *null += 1; return 0; } int main (void) { master = thread_master_create (); signal_init (master, array_size(sigs), sigs); zlog_default = openzlog("testsegv", ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level (NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED); zlog_set_level (NULL, ZLOG_DEST_STDOUT, LOG_DEBUG); zlog_set_level (NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); thread_execute (master, threadfunc, 0, 0); exit (0); } quagga-0.99.24.1/tests/test-privs.c0000644000175000017500000000654212476520570013671 00000000000000/* * $Id: test-privs.c,v 1.1 2005/10/11 03:48:28 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "privs.h" #include "memory.h" zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_DAC_OVERRIDE, }; struct zebra_privs_t test_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof(_caps_p)/sizeof(_caps_p[0]), .cap_num_i = 0 }; struct option longopts[] = { { "help", no_argument, NULL, 'h'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { 0 } }; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which does 'slow' things.\n\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } struct thread_master *master; /* main routine. */ int main (int argc, char **argv) { char *p; char *progname; struct zprivs_ids_t ids; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); while (1) { int opt; opt = getopt_long (argc, argv, "hu:g:", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'u': test_privs.user = optarg; break; case 'g': test_privs.group = optarg; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Library inits. */ memory_init (); zprivs_init (&test_privs); #define PRIV_STATE() \ ((test_privs.current_state() == ZPRIVS_RAISED) ? "Raised" : "Lowered") printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_RAISE); printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_LOWER); printf ("%s\n", PRIV_STATE()); zprivs_get_ids (&ids); /* terminate privileges */ zprivs_terminate(&test_privs); /* but these should continue to work... */ printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_RAISE); printf ("%s\n", PRIV_STATE()); test_privs.change(ZPRIVS_LOWER); printf ("%s\n", PRIV_STATE()); zprivs_get_ids (&ids); printf ("terminating\n"); return 0; } quagga-0.99.24.1/tests/test-nexthop-iter.c0000644000175000017500000001445112476520570015152 00000000000000/* * Recursive Nexthop Iterator test. * This tests the ALL_NEXTHOPS_RO macro. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "zebra/rib.h" #include "prng.h" struct thread_master *master; static int verbose; static void str_append(char **buf, const char *repr) { if (*buf) { *buf = realloc(*buf, strlen(*buf) + strlen(repr) + 1); assert(*buf); strncpy((*buf) + strlen(*buf), repr, strlen(repr) + 1); } else { *buf = strdup(repr); assert(*buf); } } static void str_appendf(char **buf, const char *format, ...) { va_list ap; int rv; char *pbuf; va_start(ap, format); rv = vasprintf(&pbuf, format, ap); va_end(ap); assert(rv >= 0); str_append(buf, pbuf); free(pbuf); } /* This structure contains a nexthop chain * and its expected representation */ struct nexthop_chain { /* Head of the chain */ struct nexthop *head; /* Last nexthop in top chain */ struct nexthop *current_top; /* Last nexthop in current recursive chain */ struct nexthop *current_recursive; /* Expected string representation. */ char *repr; }; static struct nexthop_chain* nexthop_chain_new(void) { struct nexthop_chain *rv; rv = calloc(sizeof(*rv), 1); assert(rv); return rv; } static void nexthop_chain_add_top(struct nexthop_chain *nc) { struct nexthop *nh; nh = calloc(sizeof(*nh), 1); assert(nh); if (nc->head) { nc->current_top->next = nh; nh->prev = nc->current_top; nc->current_top = nh; } else { nc->head = nc->current_top = nh; } nc->current_recursive = NULL; str_appendf(&nc->repr, "%p\n", nh); } static void nexthop_chain_add_recursive(struct nexthop_chain *nc) { struct nexthop *nh; nh = calloc(sizeof(*nh), 1); assert(nh); assert(nc->current_top); if (nc->current_recursive) { nc->current_recursive->next = nh; nh->prev = nc->current_recursive; nc->current_recursive = nh; } else { SET_FLAG(nc->current_top->flags, NEXTHOP_FLAG_RECURSIVE); nc->current_top->resolved = nh; nc->current_recursive = nh; } str_appendf(&nc->repr, " %p\n", nh); } static void nexthop_chain_clear(struct nexthop_chain *nc) { struct nexthop *tcur, *tnext; for (tcur = nc->head; tcur; tcur = tnext) { tnext = tcur->next; if (CHECK_FLAG(tcur->flags, NEXTHOP_FLAG_RECURSIVE)) { struct nexthop *rcur, *rnext; for (rcur = tcur->resolved; rcur; rcur = rnext) { rnext = rcur->next; free(rcur); } } free(tcur); } nc->head = nc->current_top = nc->current_recursive = NULL; free(nc->repr); nc->repr = NULL; } static void nexthop_chain_free(struct nexthop_chain *nc) { if (!nc) return; nexthop_chain_clear(nc); free(nc); } /* This function builds a string representation of * the nexthop chain using the ALL_NEXTHOPS_RO macro. * It verifies that the ALL_NEXTHOPS_RO macro iterated * correctly over the nexthop chain by comparing the * generated representation with the expected representation. */ static void nexthop_chain_verify_iter(struct nexthop_chain *nc) { struct nexthop *nh, *tnh; int recursing; char *repr = NULL; for (ALL_NEXTHOPS_RO(nc->head, nh, tnh, recursing)) { if (recursing) str_appendf(&repr, " %p\n", nh); else str_appendf(&repr, "%p\n", nh); } if (repr && verbose) printf("===\n%s", repr); assert((!repr && !nc->repr) || (repr && nc->repr && !strcmp(repr, nc->repr))); free(repr); } /* This test run builds a simple nexthop chain * with some recursive nexthops and verifies that * the iterator works correctly in each stage along * the way. */ static void test_run_first(void) { struct nexthop_chain *nc; nc = nexthop_chain_new(); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_top(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_add_recursive(nc); nexthop_chain_verify_iter(nc); nexthop_chain_free(nc); } /* This test run builds numerous random * nexthop chain configurations and verifies * that the iterator correctly progresses * through each. */ static void test_run_prng(void) { struct nexthop_chain *nc; struct prng *prng; int i; nc = nexthop_chain_new(); prng = prng_new(0); for (i = 0; i < 1000000; i++) { switch (prng_rand(prng) % 10) { case 0: nexthop_chain_clear(nc); break; case 1: case 2: case 3: case 4: case 5: nexthop_chain_add_top(nc); break; case 6: case 7: case 8: case 9: if (nc->current_top) nexthop_chain_add_recursive(nc); break; } nexthop_chain_verify_iter(nc); } nexthop_chain_free(nc); prng_free(prng); } int main(int argc, char **argv) { if (argc >= 2 && !strcmp("-v", argv[1])) verbose = 1; test_run_first(); printf("Simple test passed.\n"); test_run_prng(); printf("PRNG test passed.\n"); } quagga-0.99.24.1/tests/test-memory.c0000644000175000017500000000670412476520570014036 00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include /* Memory torture tests * * Tests below are generic but comments are focused on interaction with * Paul's proposed memory 'quick' cache, which may never be included in * CVS */ struct thread_master *master; #if 0 /* set to 1 to use system alloc directly */ #undef XMALLOC #undef XCALLOC #undef XREALLOC #undef XFREE #define XMALLOC(T,S) malloc((S)) #define XCALLOC(T,S) calloc(1, (S)) #define XREALLOC(T,P,S) realloc((P),(S)) #define XFREE(T,P) free((P)) #endif #define TIMES 10 int main(int argc, char **argv) { void *a[10]; int i; printf ("malloc x, malloc x, free, malloc x, free free\n\n"); /* simple case, test cache */ for (i = 0; i < TIMES; i++) { a[0] = XMALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024); a[1] = XMALLOC (MTYPE_VTY, 1024); memset (a[1], 1, 1024); XFREE(MTYPE_VTY, a[0]); /* should go to cache */ a[0] = XMALLOC (MTYPE_VTY, 1024); /* should be satisfied from cache */ XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[1]); } printf ("malloc x, malloc y, free x, malloc y, free free\n\n"); /* cache should go invalid, valid, invalid, etc.. */ for (i = 0; i < TIMES; i++) { a[0] = XMALLOC (MTYPE_VTY, 512); memset (a[0], 1, 512); a[1] = XMALLOC (MTYPE_VTY, 1024); /* invalidate cache */ memset (a[1], 1, 1024); XFREE(MTYPE_VTY, a[0]); a[0] = XMALLOC (MTYPE_VTY, 1024); XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[1]); /* cache should become valid again on next request */ } printf ("calloc\n\n"); /* test calloc */ for (i = 0; i < TIMES; i++) { a[0] = XCALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024); a[1] = XCALLOC (MTYPE_VTY, 512); /* invalidate cache */ memset (a[1], 1, 512); XFREE(MTYPE_VTY, a[1]); XFREE(MTYPE_VTY, a[0]); /* alloc == 0, cache can become valid again on next request */ } printf ("calloc and realloc\n\n"); /* check calloc + realloc */ for (i = 0; i < TIMES; i++) { printf ("calloc a0 1024\n"); a[0] = XCALLOC (MTYPE_VTY, 1024); memset (a[0], 1, 1024/2); printf ("calloc 1 1024\n"); a[1] = XCALLOC (MTYPE_VTY, 1024); memset (a[1], 1, 1024/2); printf ("realloc 0 1024\n"); a[3] = XREALLOC (MTYPE_VTY, a[0], 2048); /* invalidate cache */ if (a[3] != NULL) a[0] = a[3]; memset (a[0], 1, 1024); printf ("calloc 2 512\n"); a[2] = XCALLOC (MTYPE_VTY, 512); memset (a[2], 1, 512); printf ("free 1 0 2\n"); XFREE(MTYPE_VTY, a[1]); XFREE(MTYPE_VTY, a[0]); XFREE(MTYPE_VTY, a[2]); /* alloc == 0, cache valid next request */ } return 0; } quagga-0.99.24.1/tests/test-commands.c0000644000175000017500000002321712476520570014325 00000000000000/* * Test code for lib/command.c * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This program reads in a list of commandlines from stdin * and calls all the public functions of lib/command.c for * both the given command lines and fuzzed versions thereof. * * The output is currently not validated but only logged. It can * be diffed to find regressions between versions. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #define REALLY_NEED_PLAIN_GETOPT 1 #include #include #include #include #include "command.h" #include "memory.h" #include "vector.h" #include "prng.h" extern vector cmdvec; extern struct cmd_node vty_node; extern void test_init_cmd(void); /* provided in test-commands-defun.c */ struct thread_master *master; /* dummy for libzebra*/ static vector test_cmds; static char test_buf[32768]; static struct cmd_node bgp_node = { BGP_NODE, "%s(config-router)# ", }; static struct cmd_node rip_node = { RIP_NODE, "%s(config-router)# ", }; static struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", }; static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", }; static struct cmd_node rmap_node = { RMAP_NODE, "%s(config-route-map)# " }; static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# " }; static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv4_node = { BGP_IPV4_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv4m_node = { BGP_IPV4M_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6_node = { BGP_IPV6_NODE, "%s(config-router-af)# " }; static struct cmd_node bgp_ipv6m_node = { BGP_IPV6M_NODE, "%s(config-router-af)# " }; static struct cmd_node ospf_node = { OSPF_NODE, "%s(config-router)# " }; static struct cmd_node ripng_node = { RIPNG_NODE, "%s(config-router)# " }; static struct cmd_node ospf6_node = { OSPF6_NODE, "%s(config-ospf6)# " }; static struct cmd_node babel_node = { BABEL_NODE, "%s(config-babel)# " }; static struct cmd_node keychain_node = { KEYCHAIN_NODE, "%s(config-keychain)# " }; static struct cmd_node keychain_key_node = { KEYCHAIN_KEY_NODE, "%s(config-keychain-key)# " }; static int test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[]) { int offset; int rv; int i; offset = 0; rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string); if (rv < 0) abort(); offset += rv; for (i = 0; i < argc; i++) { rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'", (i == 0) ? ": " : ", ", argv[i]); if (rv < 0) abort(); offset += rv; } return CMD_SUCCESS; } static void test_load(void) { char line[4096]; test_cmds = vector_init(VECTOR_MIN_SIZE); while (fgets(line, sizeof(line), stdin) != NULL) { if (strlen(line)) line[strlen(line) - 1] = '\0'; if (line[0] == '#') continue; vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line)); } } static void test_init(void) { unsigned int node; unsigned int i; struct cmd_node *cnode; struct cmd_element *cmd; cmd_init(1); install_node (&bgp_node, NULL); install_node (&rip_node, NULL); install_node (&interface_node, NULL); install_node (&rmap_node, NULL); install_node (&zebra_node, NULL); install_node (&bgp_vpnv4_node, NULL); install_node (&bgp_ipv4_node, NULL); install_node (&bgp_ipv4m_node, NULL); install_node (&bgp_ipv6_node, NULL); install_node (&bgp_ipv6m_node, NULL); install_node (&ospf_node, NULL); install_node (&ripng_node, NULL); install_node (&ospf6_node, NULL); install_node (&babel_node, NULL); install_node (&keychain_node, NULL); install_node (&keychain_key_node, NULL); install_node (&isis_node, NULL); install_node (&vty_node, NULL); test_init_cmd(); for (node = 0; node < vector_active(cmdvec); node++) if ((cnode = vector_slot(cmdvec, node)) != NULL) for (i = 0; i < vector_active(cnode->cmd_vector); i++) if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL) { cmd->daemon = 0; cmd->func = test_callback; } test_load(); vty_init_vtysh(); } static void test_terminate(void) { unsigned int i; vty_terminate(); for (i = 0; i < vector_active(test_cmds); i++) XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i)); vector_free(test_cmds); cmd_terminate(); } static void test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose) { const char *test_str; vector vline; int ret; unsigned int i; char **completions; unsigned int j; struct cmd_node *cnode; vector descriptions; int appended_null; int no_match; test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist); vline = cmd_make_strvec(test_str); if (vline == NULL) return; appended_null = 0; for (i = 0; i < vector_active(cmdvec); i++) if ((cnode = vector_slot(cmdvec, i)) != NULL) { if (node_index != (unsigned int)-1 && i != node_index) continue; if (appended_null) { vector_unset(vline, vector_active(vline) - 1); appended_null = 0; } vty->node = cnode->node; test_buf[0] = '\0'; ret = cmd_execute_command(vline, vty, NULL, 0); no_match = (ret == CMD_ERR_NO_MATCH); if (verbose || !no_match) printf("execute relaxed '%s'@%d: rv==%d%s%s\n", test_str, cnode->node, ret, (test_buf[0] != '\0') ? ", " : "", test_buf); vty->node = cnode->node; test_buf[0] = '\0'; ret = cmd_execute_command_strict(vline, vty, NULL); if (verbose || !no_match) printf("execute strict '%s'@%d: rv==%d%s%s\n", test_str, cnode->node, ret, (test_buf[0] != '\0') ? ", " : "", test_buf); if (isspace((int) test_str[strlen(test_str) - 1])) { vector_set (vline, NULL); appended_null = 1; } vty->node = cnode->node; completions = cmd_complete_command(vline, vty, &ret); if (verbose || !no_match) printf("complete '%s'@%d: rv==%d\n", test_str, cnode->node, ret); if (completions != NULL) { for (j = 0; completions[j] != NULL; j++) { printf(" '%s'\n", completions[j]); XFREE(MTYPE_TMP, completions[j]); } XFREE(MTYPE_VECTOR_INDEX, completions); } vty->node = cnode->node; descriptions = cmd_describe_command(vline, vty, &ret); if (verbose || !no_match) printf("describe '%s'@%d: rv==%d\n", test_str, cnode->node, ret); if (descriptions != NULL) { for (j = 0; j < vector_active(descriptions); j++) { struct cmd_token *cmd = vector_slot(descriptions, j); printf(" '%s' '%s'\n", cmd->cmd, cmd->desc); } vector_free(descriptions); } } cmd_free_strvec(vline); } int main(int argc, char **argv) { int opt; struct prng *prng; struct vty *vty; unsigned int edit_distance; unsigned int max_edit_distance; unsigned int node_index; int verbose; unsigned int test_cmd; unsigned int iteration; unsigned int num_iterations; max_edit_distance = 3; node_index = -1; verbose = 0; while ((opt = getopt(argc, argv, "e:n:v")) != -1) { switch (opt) { case 'e': max_edit_distance = atoi(optarg); break; case 'n': node_index = atoi(optarg); break; case 'v': verbose++; break; default: fprintf(stderr, "Usage: %s [-e ] [-n ] [-v]\n", argv[0]); exit(1); break; } } test_init(); prng = prng_new(0); vty = vty_new(); vty->type = VTY_TERM; fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds)); for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++) { for (edit_distance = 0; edit_distance <= max_edit_distance; edit_distance++) { num_iterations = 1 << edit_distance; num_iterations *= num_iterations * num_iterations; for (iteration = 0; iteration < num_iterations; iteration++) test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose); } fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds)); } fprintf(stderr, "\nDone.\n"); vty_close(vty); prng_free(prng); test_terminate(); return 0; } quagga-0.99.24.1/tests/test-commands-defun.c0000644000175000017500000341354212476521377015441 00000000000000#include #include "command.h" DEFSH (0, no_isis_metric_l2_arg_cmd_vtysh, "no isis metric <0-16777215> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") DEFSH (0, no_debug_bgp_as4_segment_cmd_vtysh, "no debug bgp as4 segment", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, ipv6_access_list_remark_cmd_vtysh, "ipv6 access-list WORD remark .LINE", "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") DEFSH (0, debug_zebra_fpm_cmd_vtysh, "debug zebra fpm", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra FPM events\n") DEFSH (0, show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_ip_bgp_filter_list_cmd_vtysh, "show ip bgp filter-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, no_debug_ospf6_spf_database_cmd_vtysh, "no debug ospf6 spf database", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug SPF Calculation\n" "Quit Logging number of LSAs at SPF Calculation time\n" ) DEFSH (0, clear_bgp_all_in_cmd_vtysh, "clear bgp * in", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound update\n") DEFSH (0, neighbor_disable_connected_check_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "disable-connected-check", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "one-hop away EBGP peer using loopback address\n") DEFSH (0, show_isis_topology_cmd_vtysh, "show isis topology", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n") DEFSH (0, show_bgp_view_ipv4_safi_rsclient_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, show_ipv6_ospf6_database_router_detail_cmd_vtysh, "show ipv6 ospf6 database * * A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_ospf_passive_interface_default_cmd_vtysh, "no passive-interface default", "Negate a command or set its defaults\n" "Allow routing updates on an interface\n" "Allow routing updates on interfaces by default\n") DEFSH (0, debug_ospf_ism_sub_cmd_vtysh, "debug ospf ism (status|events|timers)", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Interface State Machine\n" "ISM Status Information\n" "ISM Event Information\n" "ISM TImer Information\n") DEFSH (0, no_debug_mroute_cmd_vtysh, "no debug mroute", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM interaction with kernel MFC cache\n") DEFSH (0, no_ripng_route_cmd_vtysh, "no route IPV6ADDR", "Negate a command or set its defaults\n" "Static route setup\n" "Delete static RIPng route announcement\n") DEFSH (0, ip_extcommunity_list_standard_cmd_vtysh, "ip extcommunity-list <1-99> (deny|permit) .AA:NN", "IP information\n" "Add a extended community list entry\n" "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n") DEFSH (0, ip_extcommunity_list_name_expanded_cmd_vtysh, "ip extcommunity-list expanded WORD (deny|permit) .LINE", "IP information\n" "Add a extended community list entry\n" "Specify expanded extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, neighbor_default_originate_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Originate default route to this neighbor\n") DEFSH (0, show_bgp_ipv4_safi_summary_cmd_vtysh, "show bgp ipv4 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, no_ospf_area_vlink_param3_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, babel_set_hello_interval_cmd_vtysh, "babel hello-interval <20-655340>", "Babel interface commands\n" "Time between scheduled hellos\n" "Milliseconds\n") DEFSH (0, debug_isis_lupd_cmd_vtysh, "debug isis local-updates", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS local update packets\n") DEFSH (0, send_lifetime_duration_day_month_cmd_vtysh, "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", "Set send lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Duration of the key\n" "Duration seconds\n") DEFSH (0, mpls_te_router_addr_cmd_vtysh, "mpls-te router-address A.B.C.D", "MPLS-TE specific commands\n" "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") DEFSH (0|0|0|0, no_match_ip_next_hop_prefix_list_cmd_vtysh, "no match ip next-hop prefix-list", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n" "Match entries of prefix-lists\n") DEFSH (0, show_bgp_ipv4_safi_rsclient_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, show_ip_bgp_community_list_exact_cmd_vtysh, "show ip bgp community-list (<1-500>|WORD) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, no_lsp_gen_interval_cmd_vtysh, "no lsp-gen-interval", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n") DEFSH (0, no_ripng_aggregate_address_cmd_vtysh, "no aggregate-address X:X::X:X/M", "Negate a command or set its defaults\n" "Delete aggregate RIPng route announcement\n" "Aggregate network") DEFSH (0, no_match_probability_val_cmd_vtysh, "no match probability <1-99>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match portion of routes defined by percentage value\n" "Percentage of routes\n") DEFSH (0, no_bgp_network_mask_natural_backdoor_cmd_vtysh, "no network A.B.C.D backdoor", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") DEFSH (0, ipv6_ospf6_transmitdelay_cmd_vtysh, "ipv6 ospf6 transmit-delay <1-3600>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Transmit delay of this interface\n" "<1-65535> Seconds\n" ) DEFSH (0, undebug_pim_packetdump_send_cmd_vtysh, "undebug pim packet-dump send", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0, no_ip_extcommunity_list_expanded_cmd_vtysh, "no ip extcommunity-list <100-500> (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Extended Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, show_bgp_view_neighbor_damp_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFSH (0, no_ripng_default_metric_cmd_vtysh, "no default-metric", "Negate a command or set its defaults\n" "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, access_list_standard_host_cmd_vtysh, "access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "A single host address\n" "Address to match\n") DEFSH (0, no_ip_ospf_transmit_delay_cmd_vtysh, "no ip ospf transmit-delay", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n") DEFSH (0|0|0|0, no_match_ip_address_val_cmd_vtysh, "no match ip address (<1-199>|<1300-2699>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFSH (0, ospf_area_range_not_advertise_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "DoNotAdvertise this range\n") DEFSH (0, no_access_list_extended_host_host_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "A single destination host\n" "Destination address\n") DEFSH (0, no_debug_ospf6_zebra_cmd_vtysh, "no debug ospf6 zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug connection between zebra\n" ) DEFSH (0, clear_ip_bgp_instance_all_soft_out_cmd_vtysh, "clear ip bgp view WORD * soft out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_igmp_join_cmd_vtysh, "show ip igmp join", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP static join information\n") DEFSH (0, clear_ip_bgp_instance_all_cmd_vtysh, "clear ip bgp view WORD *", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n") DEFSH (0, neighbor_activate_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Enable the Address Family for this Neighbor\n") DEFSH (0, no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " route-map WORD metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, ipv6_ospf6_ifmtu_cmd_vtysh, "ipv6 ospf6 ifmtu <1-65535>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface MTU\n" "OSPFv3 Interface MTU\n" ) DEFSH (0|0|0|0, show_ipv6_prefix_list_name_seq_cmd_vtysh, "show ipv6 prefix-list WORD seq <1-4294967295>", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n") DEFSH (0, debug_igmp_events_cmd_vtysh, "debug igmp events", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0, ipv6_nd_prefix_val_offlink_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_prefix_longer_cmd_vtysh, "show ipv6 prefix-list WORD X:X::X:X/M longer", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Lookup longer prefix\n") DEFSH (0, no_neighbor_send_community_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Send Community attribute to this neighbor\n") DEFSH (0|0|0|0, clear_ipv6_prefix_list_cmd_vtysh, "clear ipv6 prefix-list", "Reset functions\n" "IPv6 information\n" "Build a prefix list\n") DEFSH (0, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, ipv6_ospf6_network_cmd_vtysh, "ipv6 ospf6 network (broadcast|point-to-point)", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Network Type\n" "Specify OSPFv6 broadcast network\n" "Specify OSPF6 point-to-point network\n" ) DEFSH (0, clear_bgp_external_in_prefix_filter_cmd_vtysh, "clear bgp external in prefix-filter", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, show_ip_pim_dr_cmd_vtysh, "show ip pim designated-router", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface designated router\n") DEFSH (0, match_community_exact_cmd_vtysh, "match community (<1-99>|<100-500>|WORD) exact-match", "Match values from routing table\n" "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") DEFSH (0, bgp_maxpaths_cmd_vtysh, "maximum-paths <1-255>", "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0, no_ipv6_access_list_any_cmd_vtysh, "no ipv6 access-list WORD (deny|permit) any", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any prefixi to match\n") DEFSH (0, bgp_default_ipv4_unicast_cmd_vtysh, "bgp default ipv4-unicast", "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") DEFSH (0, no_ospf_network_cmd_vtysh, "no ospf network", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Network type\n") DEFSH (0, no_ip_community_list_standard_all_cmd_vtysh, "no ip community-list <1-99>", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Community list number (standard)\n") DEFSH (0, no_rip_network_cmd_vtysh, "no network (A.B.C.D/M|WORD)", "Negate a command or set its defaults\n" "Enable routing on an IP network\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Interface name\n") DEFSH (0, no_isis_metric_arg_cmd_vtysh, "no isis metric <0-16777215>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFSH (0, no_aggregate_address_as_set_cmd_vtysh, "no aggregate-address A.B.C.D/M as-set", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n") DEFSH (0, show_ip_bgp_vpnv4_rd_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") DEFSH (0, ospf_area_import_list_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) import-list NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the filter for networks from other areas announced to the specified one\n" "Name of the access-list\n") DEFSH (0, show_bgp_ipv6_community2_exact_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, ospf_area_vlink_authtype_args_md5_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null) " "(message-digest-key|) <1-255> md5 KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n" "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, router_ospf_id_cmd_vtysh, "router-id A.B.C.D", "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") DEFSH (0, clear_bgp_ipv6_peer_group_in_cmd_vtysh, "clear bgp ipv6 peer-group WORD in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFSH (0, clear_ip_bgp_external_in_cmd_vtysh, "clear ip bgp external in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig inbound update\n") DEFSH (0, show_bgp_neighbor_flap_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0, match_origin_cmd_vtysh, "match origin (egp|igp|incomplete)", "Match values from routing table\n" "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFSH (0, show_ip_ospf_database_cmd_vtysh, "show ip ospf database", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n") DEFSH (0, domain_passwd_md5_snpauth_cmd_vtysh, "domain-password md5 WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, no_set_ipv6_nexthop_global_val_cmd_vtysh, "no set ipv6 next-hop global X:X::X:X", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") DEFSH (0, show_debugging_ospf_cmd_vtysh, "show debugging ospf", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n") DEFSH (0, no_ip_rip_send_version_num_cmd_vtysh, "no ip rip send version (1|2)", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "Version 1\n" "Version 2\n") DEFSH (0, show_bgp_ipv4_safi_route_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") DEFSH (0, no_is_type_cmd_vtysh, "no is-type (level-1|level-1-2|level-2-only)", "Negate a command or set its defaults\n" "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") DEFSH (0, show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh, "show ipv6 ospf6 interface prefix (X:X::X:X|X:X::X:X/M|detail)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Display connected prefixes to advertise\n" "Display the route bestmatches the address\n" "Display the route\n" "Display details of the prefixes\n" ) DEFSH (0, no_debug_ospf6_neighbor_detail_cmd_vtysh, "no debug ospf6 neighbor (state|event)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) DEFSH (0, clear_bgp_ipv6_instance_all_rsclient_cmd_vtysh, "clear bgp ipv6 view WORD * rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_ospf_timers_throttle_spf_cmd_vtysh, "no timers throttle spf", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n") DEFSH (0, no_bgp_config_type_cmd_vtysh, "no bgp config-type", "Negate a command or set its defaults\n" "BGP information\n" "Display configuration type\n") DEFSH (0, clear_ip_bgp_peer_rsclient_cmd_vtysh, "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh, "show ipv6 ospf6 interface IFNAME prefix (X:X::X:X|X:X::X:X/M|detail)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" "Display the route bestmatches the address\n" "Display the route\n" "Display details of the prefixes\n" ) DEFSH (0, show_ipv6_ospf6_database_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database linkstate-id A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, show_ipv6_mbgp_community3_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, clear_ip_bgp_external_soft_out_cmd_vtysh, "clear ip bgp external soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, bgp_network_mask_cmd_vtysh, "network A.B.C.D mask A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") DEFSH (0, show_isis_interface_cmd_vtysh, "show isis interface", "Show running system information\n" "ISIS network information\n" "ISIS interface\n") DEFSH (0, show_ip_bgp_prefix_list_cmd_vtysh, "show ip bgp prefix-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, debug_ospf_nsm_sub_cmd_vtysh, "debug ospf nsm (status|events|timers)", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Neighbor State Machine\n" "NSM Status Information\n" "NSM Event Information\n" "NSM Timer Information\n") DEFSH (0, show_ipv6_mbgp_community3_exact_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_terminal_monitor_cmd_vtysh, "no terminal monitor", "Negate a command or set its defaults\n" "Set terminal line parameters\n" "Copy debug output to the current terminal line\n") DEFSH (0, no_lsp_gen_interval_l1_cmd_vtysh, "no lsp-gen-interval level-1", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n") DEFSH (0, no_ospf_dead_interval_cmd_vtysh, "no ospf dead-interval", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_seq_le_cmd_vtysh, "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, ipv6_nd_prefix_val_rev_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") DEFSH (0, aggregate_address_summary_as_set_cmd_vtysh, "aggregate-address A.B.C.D/M summary-only as-set", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFSH (0, no_ospf_cost_cmd_vtysh, "no ospf cost", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n") DEFSH (0, neighbor_maximum_prefix_threshold_warning_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> warning-only", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Only give warning message when limit is exceeded\n") DEFSH (0, debug_zebra_events_cmd_vtysh, "debug zebra events", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra events\n") DEFSH (0, ospf_neighbor_poll_interval_priority_cmd_vtysh, "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>", "Specify neighbor router\n" "Neighbor address\n" "OSPF dead-router polling interval\n" "Seconds\n" "OSPF priority of non-broadcast neighbor\n" "Priority\n") DEFSH (0, no_isis_hello_multiplier_cmd_vtysh, "no isis hello-multiplier", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n") DEFSH (0, show_database_detail_arg_cmd_vtysh, "show isis database detail WORD", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "Detailed information\n" "LSP ID\n") DEFSH (0, ospf_area_vlink_param4_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, show_ipv6_mbgp_community_list_exact_cmd_vtysh, "show ipv6 mbgp community-list WORD exact-match", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, no_ip_route_flags2_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ip_igmp_groups_cmd_vtysh, "show ip igmp groups", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP groups information\n") DEFSH (0, ospf_compatible_rfc1583_cmd_vtysh, "compatible rfc1583", "OSPF compatibility list\n" "compatible with RFC 1583\n") DEFSH (0, no_set_originator_id_val_cmd_vtysh, "no set originator-id A.B.C.D", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP originator ID attribute\n" "IP address of originator\n") DEFSH (0|0|0|0, no_ip_prefix_list_seq_ge_le_cmd_vtysh, "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_ospf_neighbor_poll_interval_cmd_vtysh, "no neighbor A.B.C.D poll-interval <1-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor IP address\n" "Dead Neighbor Polling interval\n" "Seconds\n") DEFSH (0, no_neighbor_timers_connect_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "timers connect", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "BGP per neighbor timers\n" "BGP connect timer\n") DEFSH (0, rip_redistribute_type_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_lsp_gen_interval_l2_arg_cmd_vtysh, "no lsp-gen-interval level-2 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") DEFSH (0, no_bgp_network_import_check_cmd_vtysh, "no bgp network import-check", "Negate a command or set its defaults\n" "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") DEFSH (0, no_debug_ospf_ism_sub_cmd_vtysh, "no debug ospf ism (status|events|timers)", "Negate a command or set its defaults\n" "Debugging functions\n" "OSPF information\n" "OSPF Interface State Machine\n" "ISM Status Information\n" "ISM Event Information\n" "ISM Timer Information\n") DEFSH (0, test_pim_receive_dump_cmd_vtysh, "test pim receive dump INTERFACE A.B.C.D .LINE", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM packet dump reception from neighbor\n" "Interface\n" "Neighbor address\n" "Packet dump\n") DEFSH (0, no_neighbor_route_server_client_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure a neighbor as Route Server client\n") DEFSH (0, match_ipv6_next_hop_cmd_vtysh, "match ipv6 next-hop X:X::X:X", "Match values from routing table\n" "IPv6 information\n" "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") DEFSH (0, show_ip_bgp_cmd_vtysh, "show ip bgp", "Show running system information\n" "IP information\n" "BGP information\n") DEFSH (0, send_lifetime_day_month_day_month_cmd_vtysh, "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", "Set send lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Time to expire\n" "Day of th month to expire\n" "Month of the year to expire\n" "Year to expire\n") DEFSH (0, show_ipv6_ospf6_spf_tree_cmd_vtysh, "show ipv6 ospf6 spf tree", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Shortest Path First caculation\n" "Show SPF tree\n") DEFSH (0, show_ip_bgp_ipv4_cidr_only_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) cidr-only", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display only routes with non-natural netmasks\n") DEFSH (0, no_neighbor_dont_capability_negotiate_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Do not perform capability negotiation\n") DEFSH (0, show_isis_neighbor_arg_cmd_vtysh, "show isis neighbor WORD", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") DEFSH (0, no_ip_ospf_message_digest_key_addr_cmd_vtysh, "no ip ospf message-digest-key <1-255> A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Address of interface") DEFSH (0, clear_bgp_ipv6_external_cmd_vtysh, "clear bgp ipv6 external", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n") DEFSH (0, no_access_list_standard_any_cmd_vtysh, "no access-list (<1-99>|<1300-1999>) (deny|permit) any", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any source host\n") DEFSH (0, show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv6 rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, test_pim_receive_prune_cmd_vtysh, "test pim receive prune INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM prune reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") DEFSH (0, show_bgp_ipv6_rsclient_summary_cmd_vtysh, "show bgp ipv6 rsclient summary", "Show running system information\n" "BGP information\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, no_ip_ospf_cost_u32_cmd_vtysh, "no ip ospf cost <1-65535>", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, show_bgp_community_all_cmd_vtysh, "show bgp community", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n") DEFSH (0, debug_isis_err_cmd_vtysh, "debug isis protocol-errors", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS LSP protocol errors\n") DEFSH (0, no_ripng_redistribute_type_metric_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " metric <0-16> route-map WORD", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, ip_route_flags_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, ospf_network_area_cmd_vtysh, "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", "Enable routing on an IP network\n" "OSPF network prefix\n" "Set the OSPF area ID\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") DEFSH (0, show_ip_bgp_ipv4_prefix_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ip_bgp_flap_cidr_only_cmd_vtysh, "show ip bgp flap-statistics cidr-only", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") DEFSH (0, no_ip_rip_authentication_string_cmd_vtysh, "no ip rip authentication string", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n") DEFSH (0, no_debug_ospf_lsa_sub_cmd_vtysh, "no debug ospf lsa (generate|flooding|install|refresh)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Link State Advertisement\n" "LSA Generation\n" "LSA Flooding\n" "LSA Install/Delete\n" "LSA Refres\n") DEFSH (0, old_ipv6_aggregate_address_summary_only_cmd_vtysh, "ipv6 bgp aggregate-address X:X::X:X/M summary-only", "IPv6 information\n" "BGP information\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, debug_bgp_filter_cmd_vtysh, "debug bgp filters", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP filters\n") DEFSH (0, ip_extcommunity_list_standard2_cmd_vtysh, "ip extcommunity-list <1-99> (deny|permit)", "IP information\n" "Add a extended community list entry\n" "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n") DEFSH (0, no_isis_hello_multiplier_l2_arg_cmd_vtysh, "no isis hello-multiplier <2-100> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, show_ip_pim_assert_internal_cmd_vtysh, "show ip pim assert-internal", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface internal assert state\n") DEFSH (0, no_ipv6_nd_homeagent_config_flag_cmd_vtysh, "no ipv6 nd home-agent-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") DEFSH (0, rip_allow_ecmp_cmd_vtysh, "allow-ecmp", "Allow Equal Cost MultiPath\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_seq_cmd_vtysh, "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Any prefix match. Same as \"::0/0 le 128\"\n") DEFSH (0, ripng_redistribute_type_metric_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " metric <0-16> route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_ip_mroute_count_cmd_vtysh, "show ip mroute count", "Show running system information\n" "IP information\n" "IP multicast routing table\n" "Route and packet count data\n") DEFSH (0, show_ipv6_ripng_cmd_vtysh, "show ipv6 ripng", "Show running system information\n" "IPv6 information\n" "Show RIPng routes\n") DEFSH (0, no_ospf_area_vlink_authtype_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n") DEFSH (0, no_ip_address_cmd_vtysh, "no ip address A.B.C.D/M", "Negate a command or set its defaults\n" "Interface Internet Protocol config commands\n" "Set the IP address of an interface\n" "IP Address (e.g. 10.0.0.1/8)") DEFSH (0, neighbor_description_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Neighbor specific description\n" "Up to 80 characters describing this neighbor\n") DEFSH (0, show_ip_route_prefix_cmd_vtysh, "show ip route A.B.C.D/M", "Show running system information\n" "IP information\n" "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_flap_prefix_list_cmd_vtysh, "show ip bgp flap-statistics prefix-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh, "clear ip bgp A.B.C.D in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFSH (0, show_hostname_cmd_vtysh, "show isis hostname", "Show running system information\n" "IS-IS information\n" "IS-IS Dynamic hostname mapping\n") DEFSH (0, no_bgp_cluster_id_arg_cmd_vtysh, "no bgp cluster-id A.B.C.D", "Negate a command or set its defaults\n" "BGP information\n" "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id in IP address format\n") DEFSH (0, show_ip_forwarding_cmd_vtysh, "show ip forwarding", "Show running system information\n" "IP information\n" "IP forwarding status\n") DEFSH (0, clear_ip_bgp_all_in_prefix_filter_cmd_vtysh, "clear ip bgp * in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, ip_address_cmd_vtysh, "ip address A.B.C.D/M", "Interface Internet Protocol config commands\n" "Set the IP address of an interface\n" "IP address (e.g. 10.0.0.1/8)\n") DEFSH (0, show_bgp_view_cmd_vtysh, "show bgp view WORD", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n") DEFSH (0, no_rip_allow_ecmp_cmd_vtysh, "no allow-ecmp", "Negate a command or set its defaults\n" "Allow Equal Cost MultiPath\n") DEFSH (0, ospf6_redistribute_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|isis|bgp|babel)" " route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Route map name\n" ) DEFSH (0, show_ip_bgp_flap_address_cmd_vtysh, "show ip bgp flap-statistics A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") DEFSH (0, no_set_ecommunity_rt_cmd_vtysh, "no set extcommunity rt", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Route Target extended community\n") DEFSH (0, no_debug_isis_packet_dump_cmd_vtysh, "no debug isis packet-dump", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS packet dump\n") DEFSH (0, show_bgp_rsclient_prefix_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, clear_bgp_ipv6_peer_group_soft_cmd_vtysh, "clear bgp ipv6 peer-group WORD soft", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") DEFSH (0, ip_route_mask_flags_distance2_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0|0|0|0, no_match_ip_next_hop_val_cmd_vtysh, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFSH (0, isis_passive_cmd_vtysh, "isis passive", "IS-IS commands\n" "Configure the passive mode for interface\n") DEFSH (0, no_ip_route_distance_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") DEFSH (0|0, show_ip_mroute_cmd_vtysh, "show ip mroute", "Show running system information\n" "IP information\n" "IP Multicast routing table\n") DEFSH (0|0|0, no_router_zebra_cmd_vtysh, "no router zebra", "Negate a command or set its defaults\n" "Disable a routing process\n" "Stop connection to zebra daemon\n") DEFSH (0, no_vty_login_cmd_vtysh, "no login", "Negate a command or set its defaults\n" "Enable password checking\n") DEFSH (0, show_ipv6_ospf6_database_type_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_area_range_cmd_vtysh, "no area A.B.C.D range X:X::X:X/M", "OSPF area parameters\n" "Area ID (as an IPv4 notation)\n" "Configured address range\n" "Specify IPv6 prefix\n" ) DEFSH (0, no_ospf_area_stub_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) stub", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") DEFSH (0, ospf_area_vlink_authtype_args_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n") DEFSH (0, show_ipv6_route_protocol_cmd_vtysh, "show ipv6 route " "(kernel|connected|static|ripng|ospf6|isis|bgp|babel)", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n") DEFSH (0, clear_bgp_peer_soft_in_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) soft in", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, dump_bgp_routes_interval_cmd_vtysh, "dump bgp routes-mrt PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") DEFSH (0, show_ip_bgp_vpnv4_rd_tags_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") DEFSH (0, clear_ip_bgp_dampening_address_cmd_vtysh, "clear ip bgp dampening A.B.C.D", "Reset functions\n" "IP information\n" "BGP information\n" "Clear route flap dampening information\n" "Network to clear damping information\n") DEFSH (0, show_bgp_cmd_vtysh, "show bgp", "Show running system information\n" "BGP information\n") DEFSH (0, show_ipv6_mroute_cmd_vtysh, "show ipv6 mroute", "Show running system information\n" "IP information\n" "IPv6 Multicast routing table\n") DEFSH (0, no_set_community_delete_val_cmd_vtysh, "no set comm-list (<1-99>|<100-500>|WORD) delete", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "set BGP community list (for deletion)\n" "Community-list number (standard)\n" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFSH (0, no_domain_passwd_cmd_vtysh, "no domain-password", "Negate a command or set its defaults\n" "Set the authentication password for a routing domain\n") DEFSH (0, clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " vpnv4 unicast soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_rip_redistribute_type_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, test_igmp_receive_report_cmd_vtysh, "test igmp receive report <0-65535> A.B.C.D <1-6> .LINE", "Test\n" "Test IGMP protocol\n" "Test IGMP message\n" "Test IGMP report\n" "Socket\n" "IGMP group address\n" "Record type\n" "Sources\n") DEFSH (0, show_ipv6_mbgp_community4_exact_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_lsp_refresh_interval_cmd_vtysh, "no lsp-refresh-interval", "Negate a command or set its defaults\n" "LSP refresh interval in seconds\n") DEFSH (0, neighbor_attr_unchanged4_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") DEFSH (0, clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh, "clear ip bgp peer-group WORD in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, clear_ip_bgp_external_out_cmd_vtysh, "clear ip bgp external out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig outbound update\n") DEFSH (0, no_set_community_none_cmd_vtysh, "no set community none", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP community attribute\n" "No community attribute\n") DEFSH (0, no_ospf_log_adjacency_changes_detail_cmd_vtysh, "no log-adjacency-changes detail", "Negate a command or set its defaults\n" "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, show_bgp_community_list_exact_cmd_vtysh, "show bgp community-list (<1-500>|WORD) exact-match", "Show running system information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, clear_bgp_ipv6_peer_soft_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") DEFSH (0, clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, ip_rip_authentication_key_chain_cmd_vtysh, "ip rip authentication key-chain LINE", "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n" "name of key-chain\n") DEFSH (0, no_rip_distance_source_access_list_cmd_vtysh, "no distance <1-255> A.B.C.D/M WORD", "Negate a command or set its defaults\n" "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") DEFSH (0, show_bgp_rsclient_route_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, debug_bgp_update_direct_cmd_vtysh, "debug bgp updates (in|out)", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP updates\n" "Inbound updates\n" "Outbound updates\n") DEFSH (0, show_bgp_instance_neighbors_peer_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, show_bgp_ipv6_neighbors_peer_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, no_ipv6_bgp_network_route_map_cmd_vtysh, "no network X:X::X:X/M route-map WORD", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, show_ip_ospf_database_type_adv_router_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") adv-router A.B.C.D", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") DEFSH (0, no_bgp_network_mask_route_map_cmd_vtysh, "no network A.B.C.D mask A.B.C.D route-map WORD", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, show_ip_pim_lan_prune_delay_cmd_vtysh, "show ip pim lan-prune-delay", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbors LAN prune delay parameters\n") DEFSH (0, show_ipv6_mbgp_summary_cmd_vtysh, "show ipv6 mbgp summary", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, show_isis_topology_l1_cmd_vtysh, "show isis topology level-1", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-1 routers in the area\n") DEFSH (0, no_isis_hello_padding_cmd_vtysh, "no isis hello padding", "Negate a command or set its defaults\n" "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") DEFSH (0, no_ip_multicast_mode_cmd_vtysh, "no ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", "Negate a command or set its defaults\n" "IP information\n" "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") DEFSH (0, show_isis_neighbor_cmd_vtysh, "show isis neighbor", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n") DEFSH (0, no_neighbor_nexthop_local_unchanged_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "nexthop-local unchanged", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure treatment of outgoing link-local-nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") DEFSH (0, ip_route_mask_flags_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ipv6_ospf6_linkstate_detail_cmd_vtysh, "show ipv6 ospf6 linkstate detail", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display linkstate routing table\n" ) DEFSH (0, no_access_list_exact_cmd_vtysh, "no access-list WORD (deny|permit) A.B.C.D/M exact-match", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n" "Exact match of the prefixes\n") DEFSH (0, undebug_pim_packetdump_recv_cmd_vtysh, "undebug pim packet-dump receive", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, clear_bgp_ipv6_peer_soft_out_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_bgp_ipv6_safi_prefix_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, debug_ospf6_message_sendrecv_cmd_vtysh, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) DEFSH (0, clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0|0|0|0, ipv6_prefix_list_le_cmd_vtysh, "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, match_peer_cmd_vtysh, "match peer (A.B.C.D|X:X::X:X)", "Match values from routing table\n" "Match peer address\n" "IPv6 address of peer\n" "IP address of peer\n") DEFSH (0, clear_ip_bgp_external_ipv4_in_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, access_list_any_cmd_vtysh, "access-list WORD (deny|permit) any", "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") DEFSH (0, clear_ip_bgp_peer_in_cmd_vtysh, "clear ip bgp A.B.C.D in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig inbound update\n") DEFSH (0, bgp_redistribute_ipv6_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_ip_bgp_neighbor_routes_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, no_neighbor_attr_unchanged3_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") DEFSH (0, ip_ospf_authentication_cmd_vtysh, "ip ospf authentication", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n") DEFSH (0, clear_bgp_peer_group_cmd_vtysh, "clear bgp peer-group WORD", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n") DEFSH (0, show_bgp_ipv6_neighbors_cmd_vtysh, "show bgp ipv6 neighbors", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, ospf6_timers_throttle_spf_cmd_vtysh, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") DEFSH (0, ospf_log_adjacency_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, no_if_ipv6_rmap_cmd_vtysh, "no route-map ROUTEMAP_NAME (in|out) IFNAME", "Negate a command or set its defaults\n" "Route map unset\n" "Route map name\n" "Route map for input filtering\n" "Route map for output filtering\n" "Route map interface name\n") DEFSH (0, show_ip_multicast_cmd_vtysh, "show ip multicast", "Show running system information\n" "IP information\n" "Multicast global information\n") DEFSH (0, no_bgp_redistribute_ipv6_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, is_type_cmd_vtysh, "is-type (level-1|level-1-2|level-2-only)", "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") DEFSH (0, no_match_ipv6_address_cmd_vtysh, "no match ipv6 address WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "IPv6 information\n" "Match IPv6 address of route\n" "IPv6 access-list name\n") DEFSH (0|0|0|0, ip_prefix_list_sequence_number_cmd_vtysh, "ip prefix-list sequence-number", "IP information\n" "Build a prefix list\n" "Include/exclude sequence numbers in NVGEN\n") DEFSH (0, debug_isis_spfevents_cmd_vtysh, "debug isis spf-events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Shortest Path First Events\n") DEFSH (0, no_ospf_distance_cmd_vtysh, "no distance <1-255>", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF Administrative distance\n") DEFSH (0, rip_offset_list_cmd_vtysh, "offset-list WORD (in|out) <0-16>", "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0, ipv6_nd_prefix_noval_rev_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, show_ipv6_bgp_community_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, bgp_deterministic_med_cmd_vtysh, "bgp deterministic-med", "BGP specific commands\n" "Pick the best-MED path among paths advertised from the neighboring AS\n") DEFSH (0, no_debug_ripng_packet_cmd_vtysh, "no debug ripng packet", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng packet\n") DEFSH (0, bgp_bestpath_med_cmd_vtysh, "bgp bestpath med (confed|missing-as-worst)", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_cmd_vtysh, "show ipv6 prefix-list", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n") DEFSH (0, no_ospf_hello_interval_cmd_vtysh, "no ospf hello-interval", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Time between HELLO packets\n") DEFSH (0, no_ipv6_access_list_remark_arg_cmd_vtysh, "no ipv6 access-list WORD remark .LINE", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") DEFSH (0, no_ip_ospf_message_digest_key_cmd_vtysh, "no ip ospf message-digest-key <1-255>", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n") DEFSH (0, clear_bgp_peer_group_out_cmd_vtysh, "clear bgp peer-group WORD out", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_ssmpingd_cmd_vtysh, "show ip ssmpingd", "Show running system information\n" "IP information\n" "ssmpingd operation\n") DEFSH (0, show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, ripng_offset_list_cmd_vtysh, "offset-list WORD (in|out) <0-16>", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0, bgp_network_route_map_cmd_vtysh, "network A.B.C.D/M route-map WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, no_router_ospf6_cmd_vtysh, "no router ospf6", "Negate a command or set its defaults\n" "Enable a routing process\n") DEFSH (0, no_dump_bgp_routes_cmd_vtysh, "no dump bgp routes-mrt [PATH] [INTERVAL]", "Negate a command or set its defaults\n" "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n") DEFSH (0, bgp_router_id_cmd_vtysh, "bgp router-id A.B.C.D", "BGP information\n" "Override configured router identifier\n" "Manually configured router identifier\n") DEFSH (0, clear_bgp_ipv6_all_out_cmd_vtysh, "clear bgp ipv6 * out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig outbound update\n") DEFSH (0, no_debug_pim_packetdump_recv_cmd_vtysh, "no debug pim packet-dump receive", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, ospf_area_vlink_param1_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, ip_ospf_authentication_args_addr_cmd_vtysh, "ip ospf authentication (null|message-digest) A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n" "Address of interface") DEFSH (0, ip_rip_receive_version_2_cmd_vtysh, "ip rip receive version 2 1", "IP information\n" "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 2\n" "RIP version 1\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_prefix_cmd_vtysh, "no ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Any prefix match. Same as \"::0/0 le 128\"\n") DEFSH (0, no_debug_zebra_kernel_cmd_vtysh, "no debug zebra kernel", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra between kernel interface\n") DEFSH (0, ip_rip_receive_version_1_cmd_vtysh, "ip rip receive version 1 2", "IP information\n" "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") DEFSH (0, show_ip_bgp_instance_neighbors_cmd_vtysh, "show ip bgp view WORD neighbors", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, show_ipv6_route_prefix_cmd_vtysh, "show ipv6 route X:X::X:X/M", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 prefix\n") DEFSH (0, no_ip_community_list_standard_cmd_vtysh, "no ip community-list <1-99> (deny|permit) .AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n") DEFSH (0, show_bgp_view_afi_safi_community_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0|0|0|0, show_ip_prefix_list_summary_cmd_vtysh, "show ip prefix-list summary", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Summary of prefix lists\n") DEFSH (0, neighbor_attr_unchanged7_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "Med attribute\n" "As-path attribute\n") DEFSH (0, ip_route_mask_distance_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") DEFSH (0, babel_set_wired_cmd_vtysh, "babel wired", "Babel interface commands\n" "Enable wired optimisations") DEFSH (0, bgp_confederation_identifier_cmd_vtysh, "bgp confederation identifier " "<1-4294967295>", "BGP specific commands\n" "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") DEFSH (0, set_weight_cmd_vtysh, "set weight <0-4294967295>", "Set values in destination routing protocol\n" "BGP weight for routing table\n" "Weight value\n") DEFSH (0, no_isis_metric_cmd_vtysh, "no isis metric", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n") DEFSH (0, no_lsp_refresh_interval_l2_cmd_vtysh, "no lsp-refresh-interval level-2", "Negate a command or set its defaults\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, show_ip_bgp_ipv4_paths_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) paths", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Path information\n") DEFSH (0, neighbor_timers_connect_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") DEFSH (0, debug_pim_packets_cmd_vtysh, "debug pim packets", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n") DEFSH (0, no_access_list_extended_any_mask_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, show_ipv6_ospf6_linkstate_router_cmd_vtysh, "show ipv6 ospf6 linkstate router A.B.C.D", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display linkstate routing table\n" "Display Router Entry\n" "Specify Router ID as IPv4 address notation\n" ) DEFSH (0, ip_extcommunity_list_name_standard_cmd_vtysh, "ip extcommunity-list standard WORD (deny|permit) .AA:NN", "IP information\n" "Add a extended community list entry\n" "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n") DEFSH (0, show_ip_bgp_ipv4_community3_exact_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ip_pim_assert_metric_cmd_vtysh, "show ip pim assert-metric", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert metric\n") DEFSH (0, ipv6_aggregate_address_cmd_vtysh, "aggregate-address X:X::X:X/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, debug_bgp_events_cmd_vtysh, "debug bgp events", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP events\n") DEFSH (0, no_router_ospf_cmd_vtysh, "no router ospf", "Negate a command or set its defaults\n" "Enable a routing process\n" "Start OSPF configuration\n") DEFSH (0, no_router_bgp_cmd_vtysh, "no router bgp " "<1-4294967295>", "Negate a command or set its defaults\n" "Enable a routing process\n" "BGP information\n" "AS number\n") DEFSH (0, show_ip_pim_upstream_join_desired_cmd_vtysh, "show ip pim upstream-join-desired", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream join-desired\n") DEFSH (0, show_ip_bgp_instance_rsclient_summary_cmd_vtysh, "show ip bgp view WORD rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " metric <0-4294967295> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0|0|0|0|0|0, rmap_show_name_cmd_vtysh, "show route-map [WORD]", "Show running system information\n" "route-map information\n" "route-map name\n") DEFSH (0, show_ip_ospf_neighbor_int_detail_cmd_vtysh, "show ip ospf neighbor IFNAME detail", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "Interface name\n" "detail of all neighbors") DEFSH (0, show_ip_route_supernets_cmd_vtysh, "show ip route supernets-only", "Show running system information\n" "IP information\n" "IP routing table\n" "Show supernet entries only\n") DEFSH (0, set_ipv6_nexthop_global_cmd_vtysh, "set ipv6 next-hop global X:X::X:X", "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") DEFSH (0, ip_rip_split_horizon_poisoned_reverse_cmd_vtysh, "ip rip split-horizon poisoned-reverse", "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0|0|0|0|0, no_match_interface_cmd_vtysh, "no match interface", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match first hop interface of route\n") DEFSH (0, bgp_scan_time_cmd_vtysh, "bgp scan-time <5-60>", "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") DEFSH (0, ipv6_nd_homeagent_lifetime_cmd_vtysh, "ipv6 nd home-agent-lifetime <0-65520>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFSH (0, vty_restricted_mode_cmd_vtysh, "anonymous restricted", "Restrict view commands available in anonymous, unauthenticated vty\n") DEFSH (0, clear_ip_bgp_peer_vpnv4_out_cmd_vtysh, "clear ip bgp A.B.C.D vpnv4 unicast out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFSH (0, no_rip_offset_list_ifname_cmd_vtysh, "no offset-list WORD (in|out) <0-16> IFNAME", "Negate a command or set its defaults\n" "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, show_bgp_route_map_cmd_vtysh, "show bgp route-map WORD", "Show running system information\n" "BGP information\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, debug_ospf6_brouter_router_cmd_vtysh, "debug ospf6 border-routers router-id A.B.C.D", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug specific border router\n" "Specify border-router's router-id\n" ) DEFSH (0, no_match_ip_route_source_cmd_vtysh, "no match ip route-source", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n") DEFSH (0, no_bgp_network_backdoor_cmd_vtysh, "no network A.B.C.D/M backdoor", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") DEFSH (0, isis_hello_multiplier_cmd_vtysh, "isis hello-multiplier <2-100>", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFSH (0, show_ipv6_bgp_community4_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_area_import_list_cmd_vtysh, "no area A.B.C.D import-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Unset the filter for networks announced to other areas\n" "NAme of the access-list\n") DEFSH (0|0|0|0|0|0, no_rmap_description_cmd_vtysh, "no description", "Negate a command or set its defaults\n" "Route-map comment\n") DEFSH (0, no_debug_bgp_fsm_cmd_vtysh, "no debug bgp fsm", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "Finite State Machine\n") DEFSH (0, no_ospf_auto_cost_reference_bandwidth_cmd_vtysh, "no auto-cost reference-bandwidth", "Negate a command or set its defaults\n" "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n") DEFSH (0, show_ipv6_mbgp_community_list_cmd_vtysh, "show ipv6 mbgp community-list WORD", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the community-list\n" "community-list name\n") DEFSH (0, debug_isis_snp_cmd_vtysh, "debug isis snp-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") DEFSH (0, show_ipv6_ospf6_database_adv_router_detail_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, debug_babel_cmd_vtysh, "debug babel (common|kernel|filter|timeout|interface|route|all)", "Enable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") DEFSH (0, show_ipv6_ospf6_database_type_id_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, no_ip_ospf_transmit_delay_addr_cmd_vtysh, "no ip ospf transmit-delay A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Address of interface") DEFSH (0, ip_ospf_authentication_args_cmd_vtysh, "ip ospf authentication (null|message-digest)", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n") DEFSH (0, show_ipv6_bgp_regexp_cmd_vtysh, "show ipv6 bgp regexp .LINE", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, clear_ip_bgp_external_soft_in_cmd_vtysh, "clear ip bgp external soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, neighbor_attr_unchanged3_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop (as-path|med)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") DEFSH (0, neighbor_remove_private_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Remove private AS number from outbound updates\n") DEFSH (0|0|0|0, ip_prefix_list_le_cmd_vtysh, "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, ip_rip_authentication_mode_cmd_vtysh, "ip rip authentication mode (md5|text)", "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n") DEFSH (0, ospf_default_metric_cmd_vtysh, "default-metric <0-16777214>", "Set metric of redistributed routes\n" "Default metric\n") DEFSH (0, neighbor_maximum_prefix_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_ge_cmd_vtysh, "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_neighbor_set_peer_group_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Member of the peer-group\n" "peer-group name\n") DEFSH (0, debug_ospf6_abr_cmd_vtysh, "debug ospf6 abr", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 ABR function\n" ) DEFSH (0, no_match_ecommunity_val_cmd_vtysh, "no match extcommunity (<1-99>|<100-500>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") DEFSH (0, no_babel_network_cmd_vtysh, "no network IF_OR_ADDR", "Negate a command or set its defaults\n" "Disable Babel protocol on specified interface or network.\n" "Interface or address") DEFSH (0, show_ip_bgp_ipv4_community4_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_match_community_exact_cmd_vtysh, "no match community (<1-99>|<100-500>|WORD) exact-match", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") DEFSH (0, ip_rip_receive_version_cmd_vtysh, "ip rip receive version (1|2)", "IP information\n" "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") DEFSH (0, ipv6_router_isis_cmd_vtysh, "ipv6 router isis WORD", "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") DEFSH (0, ip_rip_split_horizon_cmd_vtysh, "ip rip split-horizon", "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, debug_bgp_as4_cmd_vtysh, "debug bgp as4", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, clear_ip_bgp_all_vpnv4_out_cmd_vtysh, "clear ip bgp * vpnv4 unicast out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFSH (0, no_dump_bgp_updates_cmd_vtysh, "no dump bgp updates [PATH] [INTERVAL]", "Negate a command or set its defaults\n" "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n") DEFSH (0, debug_bgp_update_cmd_vtysh, "debug bgp updates", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP updates\n") DEFSH (0, clear_ip_bgp_as_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_match_aspath_cmd_vtysh, "no match as-path", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP AS path list\n") DEFSH (0, no_babel_split_horizon_cmd_vtysh, "no babel split-horizon", "Negate a command or set its defaults\n" "Babel interface commands\n" "Disable split horizon processing") DEFSH (0, show_ip_bgp_ipv4_community_list_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") DEFSH (0, show_ipv6_ospf6_interface_ifname_cmd_vtysh, "show ipv6 ospf6 interface IFNAME", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Interface name(e.g. ep0)\n" ) DEFSH (0, accept_lifetime_duration_day_month_cmd_vtysh, "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> duration <1-2147483646>", "Set accept lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Duration of the key\n" "Duration seconds\n") DEFSH (0|0|0|0, match_ip_address_prefix_list_cmd_vtysh, "match ip address prefix-list WORD", "Match values from routing table\n" "IP information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, show_bgp_ipv6_community_all_cmd_vtysh, "show bgp ipv6 community", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n") DEFSH (0, no_ip_rip_split_horizon_poisoned_reverse_cmd_vtysh, "no ip rip split-horizon poisoned-reverse", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, no_csnp_interval_l1_cmd_vtysh, "no isis csnp-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, show_ipv6_ospf6_interface_cmd_vtysh, "show ipv6 ospf6 interface", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" ) DEFSH (0, no_ospf_neighbor_priority_cmd_vtysh, "no neighbor A.B.C.D priority <0-255>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor IP address\n" "Neighbor Priority\n" "Priority\n") DEFSH (0, show_bgp_instance_ipv6_safi_summary_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, clear_bgp_external_soft_in_cmd_vtysh, "clear bgp external soft in", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, clear_bgp_ipv6_all_rsclient_cmd_vtysh, "clear bgp ipv6 * rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_ip_community_list_arg_cmd_vtysh, "show ip community-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "List community-list\n" "Community-list number\n" "Community-list name\n") DEFSH (0, area_passwd_clear_cmd_vtysh, "area-password clear WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") DEFSH (0, rip_redistribute_type_metric_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " metric <0-16> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, interface_no_ip_igmp_query_interval_cmd_vtysh, "no" " " "ip igmp query-interval", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP host query interval\n") DEFSH (0, show_ip_route_protocol_cmd_vtysh, "show ip route " "(kernel|connected|static|rip|ospf|isis|bgp|pim|babel)", "Show running system information\n" "IP information\n" "IP routing table\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, show_bgp_summary_cmd_vtysh, "show bgp summary", "Show running system information\n" "BGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, csnp_interval_cmd_vtysh, "isis csnp-interval <1-600>", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFSH (0, no_ripng_timers_val_cmd_vtysh, "no timers basic <0-65535> <0-65535> <0-65535>", "Negate a command or set its defaults\n" "RIPng timers setup\n" "Basic timer\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") DEFSH (0, ospf_area_nssa_translate_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Configure NSSA-ABR for translate election (default)\n" "Configure NSSA-ABR to never translate\n" "Configure NSSA-ABR to always translate\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_summary_cmd_vtysh, "show ipv6 prefix-list summary", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Summary of prefix lists\n") DEFSH (0|0|0, match_metric_cmd_vtysh, "match metric <0-4294967295>", "Match values from routing table\n" "Match metric of route\n" "Metric value\n") DEFSH (0, debug_ospf_lsa_cmd_vtysh, "debug ospf lsa", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Link State Advertisement\n") DEFSH (0, show_bgp_instance_rsclient_summary_cmd_vtysh, "show bgp view WORD rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_ip_bgp_ipv4_filter_list_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) filter-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, show_ipv6_ospf6_database_adv_router_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0|0|0|0|0|0, rmap_continue_index_cmd_vtysh, "continue <1-65536>", "Exit policy on matches\n" "Goto Clause number\n") DEFSH (0, debug_ospf6_neighbor_cmd_vtysh, "debug ospf6 neighbor", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Neighbor\n" ) DEFSH (0, no_lsp_gen_interval_l1_arg_cmd_vtysh, "no lsp-gen-interval level-1 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFSH (0, show_bgp_view_ipv6_prefix_cmd_vtysh, "show bgp view WORD ipv6 X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "IPv6 prefix /\n") DEFSH (0, ipv6_nd_managed_config_flag_cmd_vtysh, "ipv6 nd managed-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") DEFSH (0, clear_bgp_peer_soft_out_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) soft out", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, clear_ip_bgp_peer_ipv4_out_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, show_bgp_prefix_longer_cmd_vtysh, "show bgp X:X::X:X/M longer-prefixes", "Show running system information\n" "BGP information\n" "IPv6 prefix /\n" "Display route and more specific routes\n") DEFSH (0, no_debug_bgp_keepalive_cmd_vtysh, "no debug bgp keepalives", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP keepalives\n") DEFSH (0, no_ipv6_route_flags_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, show_bgp_ipv6_route_map_cmd_vtysh, "show bgp ipv6 route-map WORD", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") DEFSH (0, no_ospf_refresh_timer_cmd_vtysh, "no refresh timer", "Adjust refresh parameters\n" "Unset refresh timer\n") DEFSH (0, show_ip_bgp_flap_prefix_cmd_vtysh, "show ip bgp flap-statistics A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_exec_timeout_cmd_vtysh, "no exec-timeout", "Negate a command or set its defaults\n" "Set the EXEC timeout\n") DEFSH (0, no_ip_extcommunity_list_name_standard_cmd_vtysh, "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n") DEFSH (0, show_ip_bgp_rsclient_summary_cmd_vtysh, "show ip bgp rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_bgp_view_afi_safi_community4_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, show_ip_as_path_access_list_all_cmd_vtysh, "show ip as-path-access-list", "Show running system information\n" "IP information\n" "List AS path access lists\n") DEFSH (0, no_isis_circuit_type_cmd_vtysh, "no isis circuit-type (level-1|level-1-2|level-2-only)", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") DEFSH (0, show_ip_bgp_view_prefix_cmd_vtysh, "show ip bgp view WORD A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, ospf_area_vlink_authtype_authkey_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(authentication-key|) AUTH_KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, show_ip_pim_address_cmd_vtysh, "show ip pim address", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface address\n") DEFSH (0, no_rip_version_val_cmd_vtysh, "no version <1-2>", "Negate a command or set its defaults\n" "Set routing protocol version\n" "version\n") DEFSH (0, max_lsp_lifetime_cmd_vtysh, "max-lsp-lifetime <350-65535>", "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFSH (0, no_ip_route_mask_flags_distance_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, clear_bgp_external_soft_out_cmd_vtysh, "clear bgp external soft out", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_access_list_standard_nomask_cmd_vtysh, "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_sequence_number_cmd_vtysh, "no ipv6 prefix-list sequence-number", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Include/exclude sequence numbers in NVGEN\n") DEFSH (0, no_ip_ospf_dead_interval_addr_cmd_vtysh, "no ip ospf dead-interval A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Address of interface") DEFSH (0, show_ip_rpf_addr_cmd_vtysh, "show ip rpf A.B.C.D", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n" "IP multicast source address (e.g. 10.0.0.0)\n") DEFSH (0, show_bgp_ipv4_safi_cmd_vtysh, "show bgp ipv4 (unicast|multicast)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, no_ip_ospf_cost_u32_inet4_cmd_vtysh, "no ip ospf cost <1-65535> A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, vty_access_class_cmd_vtysh, "access-class WORD", "Filter connections based on an IP access list\n" "IP access list\n") DEFSH (0, show_ipv6_ospf6_border_routers_detail_cmd_vtysh, "show ipv6 ospf6 border-routers (A.B.C.D|detail)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display routing table for ABR and ASBR\n" "Specify Router-ID\n" "Display Detail\n" ) DEFSH (0, no_area_passwd_cmd_vtysh, "no area-password", "Negate a command or set its defaults\n" "Configure the authentication password for an area\n") DEFSH (0, interface_no_ip_igmp_cmd_vtysh, "no ip igmp", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n") DEFSH (0, show_ip_bgp_ipv4_route_map_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) route-map WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0, show_bgp_view_ipv6_neighbor_advertised_route_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, debug_ospf_nssa_cmd_vtysh, "debug ospf nssa", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF nssa information\n") DEFSH (0, show_ip_pim_neighbor_cmd_vtysh, "show ip pim neighbor", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbor information\n") DEFSH (0, clear_bgp_all_soft_out_cmd_vtysh, "clear bgp * soft out", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_neighbor_attr_unchanged7_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop med as-path", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "Med attribute\n" "As-path attribute\n") DEFSH (0, clear_bgp_ipv6_as_soft_out_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_neighbor_default_originate_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Originate default route to this neighbor\n") DEFSH (0, ospf_redistribute_source_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|isis|bgp|pim|babel)" " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "OSPF default metric\n" "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, debug_pim_packets_filter_cmd_vtysh, "debug pim packets (hello|joins)", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, bgp_network_mask_backdoor_cmd_vtysh, "network A.B.C.D mask A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") DEFSH (0, ip_route_distance_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n" "Distance value for this route\n") DEFSH (0, no_ipv6_access_list_exact_cmd_vtysh, "no ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 3ffe:506::/32\n" "Exact match of the prefixes\n") DEFSH (0, no_ospf_default_information_originate_cmd_vtysh, "no default-information originate", "Negate a command or set its defaults\n" "Control distribution of default information\n" "Distribute a default route\n") DEFSH (0, show_ip_ospf_interface_cmd_vtysh, "show ip ospf interface [INTERFACE]", "Show running system information\n" "IP information\n" "OSPF information\n" "Interface information\n" "Interface name\n") DEFSH (0, ospf_max_metric_router_lsa_startup_cmd_vtysh, "max-metric router-lsa on-startup <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") DEFSH (0, show_bgp_ipv6_safi_rsclient_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, no_ospf_refresh_timer_val_cmd_vtysh, "no refresh timer <10-1800>", "Adjust refresh parameters\n" "Unset refresh timer\n" "Timer value in seconds\n") DEFSH (0, no_ripng_timers_cmd_vtysh, "no timers basic", "Negate a command or set its defaults\n" "RIPng timers setup\n" "Basic timer\n") DEFSH (0, show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 3ffe::/16\n") DEFSH (0, no_isis_passive_cmd_vtysh, "no isis passive", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure the passive mode for interface\n") DEFSH (0, ipv6_nd_other_config_flag_cmd_vtysh, "ipv6 nd other-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") DEFSH (0, clear_bgp_instance_all_soft_in_cmd_vtysh, "clear bgp view WORD * soft in", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, old_no_ipv6_bgp_network_cmd_vtysh, "no ipv6 bgp network X:X::X:X/M", "Negate a command or set its defaults\n" "IPv6 information\n" "BGP information\n" "Specify a network to announce via BGP\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_bgp_statistics_view_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, ip_irdp_shutdown_cmd_vtysh, "ip irdp shutdown", "IP information\n" "ICMP Router discovery shutdown on this interface\n") DEFSH (0, show_ipv6_route_summary_prefix_cmd_vtysh, "show ipv6 route summary prefix", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n" "Prefix routes\n") DEFSH (0, show_ipv6_ospf6_database_type_id_self_originated_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, bgp_cluster_id32_cmd_vtysh, "bgp cluster-id <1-4294967295>", "BGP information\n" "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id as 32 bit quantity\n") DEFSH (0, ospf_area_vlink_authkey_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication-key|) AUTH_KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, ospf_area_vlink_authtype_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n") DEFSH (0, undebug_pim_packets_cmd_vtysh, "undebug pim packets", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM protocol packets\n") DEFSH (0, no_bgp_network_mask_cmd_vtysh, "no network A.B.C.D mask A.B.C.D", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") DEFSH (0, clear_ip_interfaces_cmd_vtysh, "clear ip interfaces", "Reset functions\n" "IP information\n" "Reset interfaces\n") DEFSH (0, show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh, "show ipv6 ospf6 interface IFNAME prefix", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" ) DEFSH (0, show_ipv6_ripng_status_cmd_vtysh, "show ipv6 ripng status", "Show running system information\n" "IPv6 information\n" "Show RIPng routes\n" "IPv6 routing protocol process parameters and statistics\n") DEFSH (0, no_ip_rip_receive_version_cmd_vtysh, "no ip rip receive version", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n") DEFSH (0, neighbor_update_source_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source " "(A.B.C.D|X:X::X:X|WORD)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Source of routing updates\n" "IPv4 address\n" "IPv6 address\n" "Interface name (requires zebra to be running)\n") DEFSH (0, ospf6_interface_area_cmd_vtysh, "interface IFNAME area A.B.C.D", "Enable routing on an IPv6 interface\n" "Interface name(e.g. ep0)\n" "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) DEFSH (0, ospf_area_vlink_authtype_md5_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(message-digest-key|) <1-255> md5 KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, show_ip_bgp_neighbor_prefix_counts_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") DEFSH (0, no_neighbor_advertise_interval_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Minimum interval between sending BGP routing updates\n") DEFSH (0, no_ip_rip_authentication_key_chain2_cmd_vtysh, "no ip rip authentication key-chain LINE", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n" "name of key-chain\n") DEFSH (0, ip_irdp_debug_messages_cmd_vtysh, "ip irdp debug messages", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh, "clear ip bgp A.B.C.D vpnv4 unicast soft out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_ipv6_ospf6_database_type_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, show_ip_bgp_community3_exact_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ipv6_ospf6_database_type_id_router_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D " "(dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, ospf_area_nssa_no_summary_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) nssa no-summary", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Do not inject inter-area routes into nssa\n") DEFSH (0, no_match_origin_val_cmd_vtysh, "no match origin (egp|igp|incomplete)", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFSH (0, service_advanced_vty_cmd_vtysh, "service advanced-vty", "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") DEFSH (0, no_key_cmd_vtysh, "no key <0-2147483647>", "Negate a command or set its defaults\n" "Delete a key\n" "Key identifier number\n") DEFSH (0, no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " metric <0-4294967295> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_ip_ospf_database_type_id_adv_router_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") A.B.C.D adv-router A.B.C.D", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_summary_name_cmd_vtysh, "show ipv6 prefix-list summary WORD", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Summary of prefix lists\n" "Name of a prefix list\n") DEFSH (0, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 peer-group WORD in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_isis_priority_l1_arg_cmd_vtysh, "no isis priority <0-127> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFSH (0, show_ip_bgp_neighbor_flap_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0, interface_ip_pim_ssm_cmd_vtysh, "ip pim ssm", "IP information\n" "PIM information\n" "Enable PIM SSM operation\n") DEFSH (0, no_ospf_area_range_advertise_cost_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFSH (0, ripng_offset_list_ifname_cmd_vtysh, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, bgp_distance_source_cmd_vtysh, "distance <1-255> A.B.C.D/M", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") DEFSH (0|0|0|0|0|0, no_rmap_call_cmd_vtysh, "no call", "Negate a command or set its defaults\n" "Jump to another Route-Map after match+set\n") DEFSH (0, clear_bgp_external_cmd_vtysh, "clear bgp external", "Reset functions\n" "BGP information\n" "Clear all external peers\n") DEFSH (0, no_ospf_area_vlink_param2_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, show_ip_bgp_ipv4_community_all_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") DEFSH (0, no_neighbor_passive_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Don't send open messages to this neighbor\n") DEFSH (0, no_set_overload_bit_cmd_vtysh, "no set-overload-bit", "Reset overload bit to accept transit traffic\n" "Reset overload bit\n") DEFSH (0, neighbor_attr_unchanged9_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "Nexthop attribute\n" "As-path attribute\n") DEFSH (0, bgp_bestpath_med3_cmd_vtysh, "bgp bestpath med missing-as-worst confed", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") DEFSH (0, bgp_distance_source_access_list_cmd_vtysh, "distance <1-255> A.B.C.D/M WORD", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") DEFSH (0, clear_ip_bgp_all_ipv4_soft_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0|0, set_tag_cmd_vtysh, "set tag <0-65535>", "Set values in destination routing protocol\n" "Tag value for routing protocol\n" "Tag value\n") DEFSH (0, no_debug_bgp_update_cmd_vtysh, "no debug bgp updates", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP updates\n") DEFSH (0, clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 * in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, show_version_ospf6_cmd_vtysh, "show version ospf6", "Show running system information\n" "Displays ospf6d version\n" ) DEFSH (0, show_bgp_ipv6_prefix_cmd_vtysh, "show bgp ipv6 X:X::X:X/M", "Show running system information\n" "BGP information\n" "Address family\n" "IPv6 prefix /\n") DEFSH (0, no_rip_default_metric_val_cmd_vtysh, "no default-metric <1-16>", "Negate a command or set its defaults\n" "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, no_access_list_remark_arg_cmd_vtysh, "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") DEFSH (0, auto_cost_reference_bandwidth_cmd_vtysh, "auto-cost reference-bandwidth <1-4294967>", "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") DEFSH (0, clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, accept_lifetime_duration_month_day_cmd_vtysh, "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", "Set accept lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Duration of the key\n" "Duration seconds\n") DEFSH (0, ospf_area_authentication_message_digest_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) authentication message-digest", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n" "Use message-digest authentication\n") DEFSH (0, isis_priority_l1_cmd_vtysh, "isis priority <0-127> level-1", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFSH (0, isis_network_cmd_vtysh, "isis network point-to-point", "IS-IS commands\n" "Set network type\n" "point-to-point network type\n") DEFSH (0, no_match_probability_cmd_vtysh, "no match probability", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match portion of routes defined by percentage value\n") DEFSH (0, bgp_multiple_instance_cmd_vtysh, "bgp multiple-instance", "BGP information\n" "Enable bgp multiple instance\n") DEFSH (0, no_lsp_gen_interval_l2_cmd_vtysh, "no lsp-gen-interval level-2", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n") DEFSH (0, no_ipv6_route_ifname_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Distance value for this prefix\n") DEFSH (0, no_ospf_retransmit_interval_cmd_vtysh, "no ospf retransmit-interval", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n") DEFSH (0, clear_ip_bgp_peer_group_soft_in_cmd_vtysh, "clear ip bgp peer-group WORD soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, ospf_cost_u32_cmd_vtysh, "ospf cost <1-65535>", "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, no_bgp_redistribute_ipv6_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n") DEFSH (0, no_ospf_cost_u32_cmd_vtysh, "no ospf cost <1-65535>", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, domain_passwd_md5_cmd_vtysh, "domain-password md5 WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") DEFSH (0, show_ipv6_bgp_cmd_vtysh, "show ipv6 bgp", "Show running system information\n" "IP information\n" "BGP information\n") DEFSH (0, no_debug_igmp_cmd_vtysh, "no debug igmp", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n") DEFSH (0, psnp_interval_l1_cmd_vtysh, "isis psnp-interval <1-120> level-1", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, no_bgp_network_route_map_cmd_vtysh, "no network A.B.C.D/M route-map WORD", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, no_ipv6_nd_suppress_ra_cmd_vtysh, "no ipv6 nd suppress-ra", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") DEFSH (0, no_ip_address_label_cmd_vtysh, "no ip address A.B.C.D/M label LINE", "Negate a command or set its defaults\n" "Interface Internet Protocol config commands\n" "Set the IP address of an interface\n" "IP address (e.g. 10.0.0.1/8)\n" "Label of this address\n" "Label\n") DEFSH (0, no_neighbor_disable_connected_check_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "disable-connected-check", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "one-hop away EBGP peer using loopback address\n") DEFSH (0, show_ip_rpf_cmd_vtysh, "show ip rpf", "Show running system information\n" "IP information\n" "Display RPF information for multicast source\n") DEFSH (0, show_ip_bgp_community4_exact_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ipv6_bgp_community_exact_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, clear_ip_bgp_external_in_prefix_filter_cmd_vtysh, "clear ip bgp external in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, bgp_damp_unset2_cmd_vtysh, "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", "Negate a command or set its defaults\n" "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") DEFSH (0, show_ipv6_mbgp_route_cmd_vtysh, "show ipv6 mbgp X:X::X:X", "Show running system information\n" "IP information\n" "MBGP information\n" "Network in the MBGP routing table to display\n") DEFSH (0, no_ip_ospf_mtu_ignore_cmd_vtysh, "no ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFSH (0, no_ospf_passive_interface_addr_cmd_vtysh, "no passive-interface IFNAME A.B.C.D", "Negate a command or set its defaults\n" "Allow routing updates on an interface\n" "Interface's name\n") DEFSH (0, show_ipv6_mbgp_filter_list_cmd_vtysh, "show ipv6 mbgp filter-list WORD", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, clear_bgp_ipv6_all_in_cmd_vtysh, "clear bgp ipv6 * in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n") DEFSH (0, neighbor_weight_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set default weight for routes from this neighbor\n" "default weight\n") DEFSH (0, show_bgp_neighbor_received_routes_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, show_database_cmd_vtysh, "show isis database", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n") DEFSH (0, show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, no_max_lsp_lifetime_l1_cmd_vtysh, "no max-lsp-lifetime level-1", "Negate a command or set its defaults\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, no_ipv6_nd_homeagent_lifetime_val_cmd_vtysh, "no ipv6 nd home-agent-lifetime <0-65520>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFSH (0, show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, no_debug_isis_lupd_cmd_vtysh, "no debug isis local-updates", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS local update packets\n") DEFSH (0, aggregate_address_as_set_cmd_vtysh, "aggregate-address A.B.C.D/M as-set", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n") DEFSH (0, no_ipv6_address_cmd_vtysh, "no ipv6 address X:X::X:X/M", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Set the IP address of an interface\n" "IPv6 address (e.g. 3ffe:506::1/48)\n") DEFSH (0, clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 external in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_ip_route_mask_flags_distance2_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, show_interface_cmd_vtysh, "show interface [IFNAME]", "Show running system information\n" "Interface status and configuration\n" "Inteface name\n") DEFSH (0|0, no_match_tag_cmd_vtysh, "no match tag", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match tag of route\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, ipv6_nd_prefix_noval_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") DEFSH (0, no_ospf_area_vlink_md5_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(message-digest-key|) <1-255>", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, test_pim_receive_assert_cmd_vtysh, "test pim receive assert INTERFACE A.B.C.D A.B.C.D A.B.C.D <0-65535> <0-65535> <0-1>", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of PIM assert\n" "Interface\n" "Neighbor address\n" "Assert multicast group address\n" "Assert unicast source address\n" "Assert metric preference\n" "Assert route metric\n" "Assert RPT bit flag\n") DEFSH (0, show_bgp_community_exact_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_bgp_graceful_restart_stalepath_time_val_cmd_vtysh, "no bgp graceful-restart stalepath-time <1-3600>", "Negate a command or set its defaults\n" "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") DEFSH (0, no_ipv6_route_ifname_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n") DEFSH (0|0|0|0|0, no_match_interface_val_cmd_vtysh, "no match interface WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match first hop interface of route\n" "Interface name\n") DEFSH (0, ipv6_bgp_network_route_map_cmd_vtysh, "network X:X::X:X/M route-map WORD", "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, ipv6_nd_router_preference_cmd_vtysh, "ipv6 nd router-preference (high|medium|low)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFSH (0, undebug_pim_cmd_vtysh, "undebug pim", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n") DEFSH (0, show_ipv6_ospf6_database_id_router_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, access_list_cmd_vtysh, "access-list WORD (deny|permit) A.B.C.D/M", "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") DEFSH (0, no_neighbor_remote_as_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "remote-as " "<1-4294967295>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Specify a BGP neighbor\n" "AS number\n") DEFSH (0, isis_passwd_md5_cmd_vtysh, "isis password md5 WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") DEFSH (0, show_bgp_view_rsclient_prefix_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0|0|0|0, ipv6_prefix_list_cmd_vtysh, "ipv6 prefix-list WORD (deny|permit) (X:X::X:X/M|any)", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Any prefix match. Same as \"::0/0 le 128\"\n") DEFSH (0, no_ip_ospf_network_cmd_vtysh, "no ip ospf network", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Network type\n") DEFSH (0, no_set_origin_cmd_vtysh, "no set origin", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP origin code\n") DEFSH (0|0|0|0, ipv6_prefix_list_seq_le_cmd_vtysh, "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, show_ip_bgp_view_route_cmd_vtysh, "show ip bgp view WORD A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") DEFSH (0, bgp_fast_external_failover_cmd_vtysh, "bgp fast-external-failover", "BGP information\n" "Immediately reset session if a link to a directly connected external peer goes down\n") DEFSH (0, show_ip_access_list_cmd_vtysh, "show ip access-list", "Show running system information\n" "IP information\n" "List IP access lists\n") DEFSH (0, clear_bgp_peer_out_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) out", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh, "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_ip_protocol_cmd_vtysh, "show ip protocol", "Show running system information\n" "IP information\n" "IP protocol filtering status\n") DEFSH (0, no_csnp_interval_arg_cmd_vtysh, "no isis csnp-interval <1-600>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFSH (0, no_ipv6_ripng_split_horizon_cmd_vtysh, "no ipv6 ripng split-horizon", "Negate a command or set its defaults\n" "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, no_rip_redistribute_type_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, show_ip_igmp_sources_cmd_vtysh, "show ip igmp sources", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP sources information\n") DEFSH (0, show_ipv6_ospf6_database_adv_router_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, no_ip_extcommunity_list_expanded_all_cmd_vtysh, "no ip extcommunity-list <100-500>", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Extended Community list number (expanded)\n") DEFSH (0, accept_lifetime_month_day_day_month_cmd_vtysh, "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", "Set accept lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Time to expire\n" "Day of th month to expire\n" "Month of the year to expire\n" "Year to expire\n") DEFSH (0, no_ospf_area_vlink_param1_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, debug_ospf6_lsa_hex_cmd_vtysh, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFSH (0, ipv6_ospf6_cost_cmd_vtysh, "ipv6 ospf6 cost <1-65535>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface cost\n" "Outgoing metric of this interface\n" ) DEFSH (0, ip_irdp_minadvertinterval_cmd_vtysh, "ip irdp minadvertinterval <3-1800>", "IP information\n" "ICMP Router discovery on this interface\n" "Set minimum time between advertisement\n" "Minimum advertisement interval in seconds\n") DEFSH (0, clear_bgp_ipv6_as_out_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") DEFSH (0, no_ip_extcommunity_list_standard_cmd_vtysh, "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n") DEFSH (0, show_bgp_neighbor_routes_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0|0|0|0, no_ip_prefix_list_seq_le_cmd_vtysh, "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_ip_ospf_authentication_cmd_vtysh, "no ip ospf authentication", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n") DEFSH (0, show_ip_bgp_vpnv4_all_prefix_cmd_vtysh, "show ip bgp vpnv4 all A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_ip_rip_split_horizon_cmd_vtysh, "no ip rip split-horizon", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0|0|0|0|0|0, no_route_map_all_cmd_vtysh, "no route-map WORD", "Negate a command or set its defaults\n" "Create route-map or enter route-map command mode\n" "Route map tag\n") DEFSH (0, set_ecommunity_soo_cmd_vtysh, "set extcommunity soo .ASN:nn_or_IP-address:nn", "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Site-of-Origin extended community\n" "VPN extended community\n") DEFSH (0, debug_ospf6_lsa_hex_detail_cmd_vtysh, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFSH (0, no_rip_version_cmd_vtysh, "no version", "Negate a command or set its defaults\n" "Set routing protocol version\n") DEFSH (0, rip_redistribute_type_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, show_ipv6_access_list_name_cmd_vtysh, "show ipv6 access-list WORD", "Show running system information\n" "IPv6 information\n" "List IPv6 access lists\n" "IPv6 zebra access-list\n") DEFSH (0, no_capability_opaque_cmd_vtysh, "no capability opaque", "Negate a command or set its defaults\n" "Enable specific OSPF feature\n" "Opaque LSA\n") DEFSH (0, clear_ip_bgp_as_soft_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, ip_irdp_multicast_cmd_vtysh, "ip irdp multicast", "IP information\n" "ICMP Router discovery on this interface using multicast\n") DEFSH (0, send_lifetime_infinite_day_month_cmd_vtysh, "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", "Set send lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Never expires") DEFSH (0, show_ip_pim_interface_cmd_vtysh, "show ip pim interface", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface information\n") DEFSH (0|0|0|0, clear_ip_prefix_list_name_cmd_vtysh, "clear ip prefix-list WORD", "Reset functions\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0, clear_ip_bgp_as_cmd_vtysh, "clear ip bgp " "<1-4294967295>", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n") DEFSH (0, no_aggregate_address_mask_as_set_summary_cmd_vtysh, "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") DEFSH (0, isis_circuit_type_cmd_vtysh, "isis circuit-type (level-1|level-1-2|level-2-only)", "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") DEFSH (0, ip_ospf_mtu_ignore_addr_cmd_vtysh, "ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") DEFSH (0, show_ip_extcommunity_list_arg_cmd_vtysh, "show ip extcommunity-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "List extended-community list\n" "Extcommunity-list number\n" "Extcommunity-list name\n") DEFSH (0, no_match_community_val_cmd_vtysh, "no match community (<1-99>|<100-500>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") DEFSH (0, ipv6_nd_ra_lifetime_cmd_vtysh, "ipv6 nd ra-lifetime <0-9000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFSH (0|0|0|0, ip_prefix_list_seq_ge_le_cmd_vtysh, "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_ripng_redistribute_type_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, ip_rip_authentication_string_cmd_vtysh, "ip rip authentication string LINE", "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n" "Authentication string\n") DEFSH (0, show_ip_bgp_scan_detail_cmd_vtysh, "show ip bgp scan detail", "Show running system information\n" "IP information\n" "BGP information\n" "BGP scan status\n" "More detailed output\n") DEFSH (0, undebug_bgp_update_cmd_vtysh, "undebug bgp updates", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP updates\n") DEFSH (0, ospf_neighbor_poll_interval_cmd_vtysh, "neighbor A.B.C.D poll-interval <1-65535>", "Specify neighbor router\n" "Neighbor IP address\n" "Dead Neighbor Polling interval\n" "Seconds\n") DEFSH (0, show_bgp_route_cmd_vtysh, "show bgp X:X::X:X", "Show running system information\n" "BGP information\n" "Network in the BGP routing table to display\n") DEFSH (0, neighbor_local_as_no_prepend_replace_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend replace-as", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") DEFSH (0, no_ipv6_route_ifname_flags_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, no_ripng_default_information_originate_cmd_vtysh, "no default-information originate", "Negate a command or set its defaults\n" "Default route information\n" "Distribute default route\n") DEFSH (0, no_auto_summary_cmd_vtysh, "no auto-summary", "Negate a command or set its defaults\n" "Enable automatic network number summarization\n") DEFSH (0, no_rip_passive_interface_cmd_vtysh, "no passive-interface (IFNAME|default)", "Negate a command or set its defaults\n" "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") DEFSH (0, show_bgp_view_ipv6_safi_rsclient_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, no_access_list_any_cmd_vtysh, "no access-list WORD (deny|permit) any", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") DEFSH (0, show_ip_ospf_database_type_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" "|max-age|self-originate)", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "LSAs in MaxAge list\n" "Self-originated link states\n") DEFSH (0, no_lsp_refresh_interval_l1_arg_cmd_vtysh, "no lsp-refresh-interval level-1 <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, no_rip_redistribute_rip_cmd_vtysh, "no redistribute rip", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") DEFSH (0, no_match_peer_cmd_vtysh, "no match peer", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n") DEFSH (0, show_babel_parameters_cmd_vtysh, "show babel parameters", "Show running system information\n" "IP information\n" "Babel information\n" "Configuration information\n" "No attributes\n") DEFSH (0, no_ip_ospf_authentication_addr_cmd_vtysh, "no ip ospf authentication A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Address of interface") DEFSH (0, ospf_dead_interval_cmd_vtysh, "ospf dead-interval <1-65535>", "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, show_bgp_filter_list_cmd_vtysh, "show bgp filter-list WORD", "Show running system information\n" "BGP information\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, no_match_ip_route_source_prefix_list_cmd_vtysh, "no match ip route-source prefix-list", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n" "Match entries of prefix-lists\n") DEFSH (0, no_ospf_compatible_rfc1583_cmd_vtysh, "no compatible rfc1583", "Negate a command or set its defaults\n" "OSPF compatibility list\n" "compatible with RFC 1583\n") DEFSH (0, bgp_network_import_check_cmd_vtysh, "bgp network import-check", "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") DEFSH (0|0|0|0, show_ip_prefix_list_prefix_cmd_vtysh, "show ip prefix-list WORD A.B.C.D/M", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ipv6_ospf6_database_type_adv_router_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, ip_irdp_address_preference_cmd_vtysh, "ip irdp address A.B.C.D preference <0-2147483647>", "IP information\n" "Alter ICMP Router discovery preference this interface\n" "Specify IRDP non-default preference to advertise\n" "Set IRDP address for advertise\n" "Preference level\n") DEFSH (0, show_isis_interface_detail_cmd_vtysh, "show isis interface detail", "Show running system information\n" "ISIS network information\n" "ISIS interface\n" "show detailed information\n") DEFSH (0, show_ip_bgp_rsclient_route_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, no_debug_ospf_zebra_sub_cmd_vtysh, "no debug ospf zebra (interface|redistribute)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Zebra information\n" "Zebra interface\n" "Zebra redistribute\n") DEFSH (0, show_bgp_ipv6_neighbor_flap_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0, interface_ip_igmp_query_max_response_time_cmd_vtysh, "ip igmp query-max-response-time" " <1-25>", "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (seconds)\n" "Query response value in seconds\n") DEFSH (0, ipv6_mbgp_neighbor_received_routes_cmd_vtysh, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, clear_bgp_peer_soft_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) soft", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") DEFSH (0, show_ip_ospf_neighbor_cmd_vtysh, "show ip ospf neighbor", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n") DEFSH (0, no_isis_priority_l2_cmd_vtysh, "no isis priority level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-2 routing\n") DEFSH (0, no_neighbor_shutdown_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Administratively shut down this neighbor\n") DEFSH (0, debug_pim_zebra_cmd_vtysh, "debug pim zebra", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0, show_ip_igmp_interface_cmd_vtysh, "show ip igmp interface", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP interface information\n") DEFSH (0, no_bgp_bestpath_aspath_ignore_cmd_vtysh, "no bgp bestpath as-path ignore", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Ignore as-path length in selecting a route\n") DEFSH (0, no_debug_pim_cmd_vtysh, "no debug pim", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n") DEFSH (0, debug_pim_trace_cmd_vtysh, "debug pim trace", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, show_ip_bgp_neighbor_advertised_route_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, no_bgp_redistribute_ipv4_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, ipv6_ospf6_priority_cmd_vtysh, "ipv6 ospf6 priority <0-255>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Router priority\n" "Priority value\n" ) DEFSH (0, clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, debug_ospf6_spf_time_cmd_vtysh, "debug ospf6 spf time", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug SPF Calculation\n" "Measure time taken by SPF Calculation\n" ) DEFSH (0, no_access_list_extended_any_any_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "Any destination host\n") DEFSH (0, show_table_cmd_vtysh, "show table", "Show running system information\n" "default routing table to use for all clients\n") DEFSH (0, max_lsp_lifetime_l1_cmd_vtysh, "max-lsp-lifetime level-1 <350-65535>", "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, no_match_pathlimit_as_val_cmd_vtysh, "no match pathlimit as <1-65535>", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") DEFSH (0, show_bgp_neighbors_peer_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, no_ospf_area_shortcut_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Deconfigure the area's shortcutting mode\n" "Deconfigure enabled shortcutting through the area\n" "Deconfigure disabled shortcutting through the area\n") DEFSH (0, no_ospf6_stub_router_admin_cmd_vtysh, "no stub-router administrative", "Negate a command or set its defaults\n" "Make router a stub router\n" "Advertise ability to be a transit router\n" "Administratively applied, for an indefinite period\n") DEFSH (0, no_neighbor_maximum_prefix_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n") DEFSH (0, debug_ripng_packet_cmd_vtysh, "debug ripng packet", "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng packet\n") DEFSH (0, show_ip_pim_hello_cmd_vtysh, "show ip pim hello", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface hello information\n") DEFSH (0, no_debug_pim_packets_cmd_vtysh, "no debug pim packets", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, ospf_default_information_originate_cmd_vtysh, "default-information originate " "{always|metric <0-16777214>|metric-type (1|2)|route-map WORD}", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_ospf6_log_adjacency_changes_cmd_vtysh, "no log-adjacency-changes", "Negate a command or set its defaults\n" "Log changes in adjacency state\n") DEFSH (0, no_access_list_all_cmd_vtysh, "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list name\n") DEFSH (0, no_debug_rip_zebra_cmd_vtysh, "no debug rip zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP and ZEBRA communication\n") DEFSH (0, no_ospf_redistribute_source_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|isis|bgp|pim|babel)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, no_match_aspath_val_cmd_vtysh, "no match as-path WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP AS path list\n" "AS path access-list name\n") DEFSH (0, ip_community_list_name_standard_cmd_vtysh, "ip community-list standard WORD (deny|permit) .AA:NN", "IP information\n" "Add a community list entry\n" "Add a standard community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n") DEFSH (0, clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh, "clear bgp ipv6 peer-group WORD soft out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_bgp_router_id_cmd_vtysh, "no bgp router-id", "Negate a command or set its defaults\n" "BGP information\n" "Override configured router identifier\n") DEFSH (0, ripng_redistribute_type_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " metric <0-16>", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n") DEFSH (0, no_debug_babel_cmd_vtysh, "no debug babel (common|kernel|filter|timeout|interface|route|all)", "Negate a command or set its defaults\n" "Disable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") DEFSH (0, access_list_remark_cmd_vtysh, "access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark .LINE", "Add an access list entry\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n" "Access list entry comment\n" "Comment up to 100 characters\n") DEFSH (0, no_ospf_area_range_substitute_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") DEFSH (0, ip_irdp_debug_disable_cmd_vtysh, "ip irdp debug disable", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, show_ip_bgp_regexp_cmd_vtysh, "show ip bgp regexp .LINE", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, set_community_delete_cmd_vtysh, "set comm-list (<1-99>|<100-500>|WORD) delete", "Set values in destination routing protocol\n" "set BGP community list (for deletion)\n" "Community-list number (standard)\n" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFSH (0, neighbor_advertise_interval_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Minimum interval between sending BGP routing updates\n" "time in seconds\n") DEFSH (0, set_ip_nexthop_peer_cmd_vtysh, "set ip next-hop peer-address", "Set values in destination routing protocol\n" "IP information\n" "Next hop address\n" "Use peer address (for BGP only)\n") DEFSH (0, no_set_ecommunity_soo_val_cmd_vtysh, "no set extcommunity soo .ASN:nn_or_IP-address:nn", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Site-of-Origin extended community\n" "VPN extended community\n") DEFSH (0, debug_bgp_keepalive_cmd_vtysh, "debug bgp keepalives", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP keepalives\n") DEFSH (0|0|0|0, ipv6_prefix_list_seq_le_ge_cmd_vtysh, "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_neighbor_capability_dynamic_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Advertise capability to the peer\n" "Advertise dynamic capability to this neighbor\n") DEFSH (0, no_set_community_delete_cmd_vtysh, "no set comm-list", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "set BGP community list (for deletion)\n") DEFSH (0, no_neighbor_prefix_list_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Filter updates to/from this neighbor\n" "Name of a prefix list\n" "Filter incoming updates\n" "Filter outgoing updates\n") DEFSH (0, no_ip_rip_authentication_mode_type_cmd_vtysh, "no ip rip authentication mode (md5|text)", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n") DEFSH (0, show_ip_pim_upstream_rpf_cmd_vtysh, "show ip pim upstream-rpf", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream source rpf\n") DEFSH (0, ipv6_nd_mtu_cmd_vtysh, "ipv6 nd mtu <1-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") DEFSH (0, no_ip_mroute_dist_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") DEFSH (0, show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd_vtysh, "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") DEFSH (0, clear_ip_bgp_as_ipv4_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, clear_bgp_as_out_cmd_vtysh, "clear bgp " "<1-4294967295>" " out", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") DEFSH (0, no_debug_ospf6_zebra_sendrecv_cmd_vtysh, "no debug ospf6 zebra (send|recv)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) DEFSH (0, show_ip_ospf_neighbor_id_cmd_vtysh, "show ip ospf neighbor A.B.C.D", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "Neighbor ID\n") DEFSH (0, no_ipv6_aggregate_address_cmd_vtysh, "no aggregate-address X:X::X:X/M", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, ipv6_forwarding_cmd_vtysh, "ipv6 forwarding", "IPv6 information\n" "Turn on IPv6 forwarding") DEFSH (0, show_ip_bgp_summary_cmd_vtysh, "show ip bgp summary", "Show running system information\n" "IP information\n" "BGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, show_bgp_ipv6_filter_list_cmd_vtysh, "show bgp ipv6 filter-list WORD", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, no_bgp_timers_arg_cmd_vtysh, "no timers bgp <0-65535> <0-65535>", "Negate a command or set its defaults\n" "Adjust routing timers\n" "BGP timers\n" "Keepalive interval\n" "Holdtime\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, max_lsp_lifetime_l2_cmd_vtysh, "max-lsp-lifetime level-2 <350-65535>", "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0, domain_passwd_clear_cmd_vtysh, "domain-password clear WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") DEFSH (0, ipv6_bgp_neighbor_advertised_route_cmd_vtysh, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, clear_ip_bgp_peer_group_soft_out_cmd_vtysh, "clear ip bgp peer-group WORD soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0|0|0|0, no_ip_prefix_list_ge_cmd_vtysh, "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, show_ipv6_bgp_community2_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, clear_zebra_fpm_stats_cmd_vtysh, "clear zebra fpm stats", "Reset functions\n" "Zebra information\n" "Clear Forwarding Path Manager information\n" "Statistics\n") DEFSH (0, debug_pim_packetdump_send_cmd_vtysh, "debug pim packet-dump send", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0, no_ospf_distribute_list_out_cmd_vtysh, "no distribute-list WORD out " "(kernel|connected|static|rip|isis|bgp|pim|babel)", "Negate a command or set its defaults\n" "Filter networks in routing updates\n" "Access-list name\n" "Filter outgoing routing updates\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, no_aggregate_address_mask_summary_as_set_cmd_vtysh, "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFSH (0, no_ipv6_nd_ra_lifetime_val_cmd_vtysh, "no ipv6 nd ra-lifetime <0-9000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFSH (0, show_ip_bgp_ipv4_prefix_list_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") DEFSH (0, show_ip_bgp_vpnv4_all_tags_cmd_vtysh, "show ip bgp vpnv4 all tags", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Display BGP tags for prefixes\n") DEFSH (0, no_ipv6_ospf6_cost_cmd_vtysh, "no ipv6 ospf6 cost", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Calculate interface cost from bandwidth\n" ) DEFSH (0, no_ospf_area_nssa_no_summary_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) nssa no-summary", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Do not inject inter-area routes into nssa\n") DEFSH (0, show_ip_bgp_vpnv4_all_summary_cmd_vtysh, "show ip bgp vpnv4 all summary", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Summary of BGP neighbor status\n") DEFSH (0, ip_ospf_transmit_delay_addr_cmd_vtysh, "ip ospf transmit-delay <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n" "Address of interface") DEFSH (0, show_ipv6_ospf6_route_longer_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M longer", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" ) DEFSH (0, show_ipv6_ospf6_database_type_id_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, show_bgp_ipv6_neighbor_damp_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFSH (0|0|0|0, show_ip_prefix_list_prefix_first_match_cmd_vtysh, "show ip prefix-list WORD A.B.C.D/M first-match", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "IP prefix /, e.g., 35.0.0.0/8\n" "First matched prefix\n") DEFSH (0, ip_irdp_maxadvertinterval_cmd_vtysh, "ip irdp maxadvertinterval <4-1800>", "IP information\n" "ICMP Router discovery on this interface\n" "Set maximum time between advertisement\n" "Maximum advertisement interval in seconds\n") DEFSH (0, no_ip_route_mask_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") DEFSH (0, no_ip_ospf_dead_interval_cmd_vtysh, "no ip ospf dead-interval", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") DEFSH (0, no_ospf_area_stub_no_summary_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) stub no-summary", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n" "Do not inject inter-area routes into area\n") DEFSH (0, show_ip_bgp_ipv4_route_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") DEFSH (0, ip_mroute_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFSH (0, show_ipv6_mbgp_prefix_list_cmd_vtysh, "show ipv6 mbgp prefix-list WORD", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") DEFSH (0, no_debug_ospf6_lsa_hex_detail_cmd_vtysh, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFSH (0, no_ospf_area_vlink_authtype_authkey_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(authentication-key|)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, no_bgp_multiple_instance_cmd_vtysh, "no bgp multiple-instance", "Negate a command or set its defaults\n" "BGP information\n" "BGP multiple instance\n") DEFSH (0, show_isis_topology_l2_cmd_vtysh, "show isis topology level-2", "Show running system information\n" "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-2 routers in the domain\n") DEFSH (0|0|0|0, clear_ip_prefix_list_name_prefix_cmd_vtysh, "clear ip prefix-list WORD A.B.C.D/M", "Reset functions\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, clear_ip_pim_interfaces_cmd_vtysh, "clear ip pim interfaces", "Reset functions\n" "IP information\n" "PIM clear commands\n" "Reset PIM interfaces\n") DEFSH (0, test_pim_receive_join_cmd_vtysh, "test pim receive join INTERFACE <0-65535> A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM join reception from neighbor\n" "Interface\n" "Neighbor holdtime\n" "Upstream neighbor unicast destination address\n" "Downstream neighbor unicast source address\n" "Multicast group address\n" "Unicast source address\n") DEFSH (0, debug_ospf6_zebra_cmd_vtysh, "debug ospf6 zebra", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug connection between zebra\n" ) DEFSH (0, show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh, "show ipv6 ospf6 interface IFNAME prefix X:X::X:X/M (match|detail)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Interface name(e.g. ep0)\n" "Display connected prefixes to advertise\n" "Display the route\n" "Display the route matches the prefix\n" "Display details of the prefixes\n" ) DEFSH (0, debug_zebra_packet_direct_cmd_vtysh, "debug zebra packet (recv|send)", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") DEFSH (0|0, no_set_ipv6_nexthop_local_cmd_vtysh, "no set ipv6 next-hop local", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 local address\n") DEFSH (0, no_ipv6_nd_router_preference_cmd_vtysh, "no ipv6 nd router-preference", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n") DEFSH (0, access_list_extended_any_any_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip any any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "Any destination host\n") DEFSH (0, no_ip_ospf_retransmit_interval_cmd_vtysh, "no ip ospf retransmit-interval", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n") DEFSH (0, show_ipv6_ospf6_database_type_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_ip_route_mask_flags2_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, clear_bgp_all_soft_in_cmd_vtysh, "clear bgp * soft in", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0|0|0|0, no_ip_prefix_list_le_ge_cmd_vtysh, "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, debug_ospf_nsm_cmd_vtysh, "debug ospf nsm", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Neighbor State Machine\n") DEFSH (0, no_debug_isis_upd_cmd_vtysh, "no debug isis update-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Update related packets\n") DEFSH (0, no_ipv6_nd_ra_lifetime_cmd_vtysh, "no ipv6 nd ra-lifetime", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n") DEFSH (0, no_set_metric_val_cmd_vtysh, "no set metric (<0-4294967295>|<+/-metric>)", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Metric value for destination routing protocol\n" "Metric value\n" "Add or subtract metric\n") DEFSH (0, vty_ipv6_access_class_cmd_vtysh, "ipv6 access-class WORD", "IPv6 information\n" "Filter connections based on an IP access list\n" "IPv6 access list\n") DEFSH (0, set_vpnv4_nexthop_cmd_vtysh, "set vpnv4 next-hop A.B.C.D", "Set values in destination routing protocol\n" "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") DEFSH (0|0|0|0, no_ip_prefix_list_cmd_vtysh, "no ip prefix-list WORD", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0|0, ospf6_routemap_no_set_metric_type_cmd_vtysh, "no set metric-type (type-1|type-2)", "Negate a command or set its defaults\n" "Set value\n" "Type of metric\n" "OSPF6 external type 1 metric\n" "OSPF6 external type 2 metric\n") DEFSH (0, no_ip_forwarding_cmd_vtysh, "no ip forwarding", "Negate a command or set its defaults\n" "IP information\n" "Turn off IP forwarding") DEFSH (0, debug_rip_packet_direct_cmd_vtysh, "debug rip packet (recv|send)", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP packet\n" "RIP receive packet\n" "RIP send packet\n") DEFSH (0, bgp_always_compare_med_cmd_vtysh, "bgp always-compare-med", "BGP specific commands\n" "Allow comparing MED from different neighbors\n") DEFSH (0, aggregate_address_mask_summary_only_cmd_vtysh, "aggregate-address A.B.C.D A.B.C.D summary-only", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n") DEFSH (0, show_ip_bgp_paths_cmd_vtysh, "show ip bgp paths", "Show running system information\n" "IP information\n" "BGP information\n" "Path information\n") DEFSH (0, interface_no_ip_igmp_query_max_response_time_cmd_vtysh, "no" " " "ip igmp query-max-response-time", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (seconds)\n") DEFSH (0, clear_bgp_all_in_prefix_filter_cmd_vtysh, "clear bgp * in prefix-filter", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, ipv6_route_flags_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, aggregate_address_mask_summary_as_set_cmd_vtysh, "aggregate-address A.B.C.D A.B.C.D summary-only as-set", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, debug_zebra_kernel_cmd_vtysh, "debug zebra kernel", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra between kernel interface\n") DEFSH (0|0|0|0, match_ip_address_cmd_vtysh, "match ip address (<1-199>|<1300-2699>|WORD)", "Match values from routing table\n" "IP information\n" "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFSH (0, show_ip_community_list_cmd_vtysh, "show ip community-list", "Show running system information\n" "IP information\n" "List community-list\n") DEFSH (0, clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " vpnv4 unicast soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, ip_ospf_mtu_ignore_cmd_vtysh, "ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFSH (0, show_ip_bgp_flap_filter_list_cmd_vtysh, "show ip bgp flap-statistics filter-list WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, neighbor_set_peer_group_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "peer-group WORD", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Member of the peer-group\n" "peer-group name\n") DEFSH (0, clear_bgp_ipv6_all_soft_in_cmd_vtysh, "clear bgp ipv6 * soft in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_access_list_extended_any_host_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "A single destination host\n" "Destination address\n") DEFSH (0, no_ipv6_nd_ra_interval_val_cmd_vtysh, "no ipv6 nd ra-interval <1-1800>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") DEFSH (0, debug_isis_csum_cmd_vtysh, "debug isis checksum-errors", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS LSP checksum errors\n") DEFSH (0, show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh, "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Shortest Path First caculation\n" "Show SPF tree\n" "Specify root's router-id to calculate another router's SPF tree\n") DEFSH (0|0|0|0, no_ip_prefix_list_ge_le_cmd_vtysh, "no ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, debug_pim_packetdump_recv_cmd_vtysh, "debug pim packet-dump receive", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump received packets\n") DEFSH (0, ospf_router_id_cmd_vtysh, "ospf router-id A.B.C.D", "OSPF specific commands\n" "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") DEFSH (0, no_debug_zebra_fpm_cmd_vtysh, "no debug zebra fpm", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra FPM events\n") DEFSH (0, ospf_area_shortcut_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure the area's shortcutting mode\n" "Set default shortcutting behavior\n" "Enable shortcutting through the area\n" "Disable shortcutting through the area\n") DEFSH (0, lsp_refresh_interval_l2_cmd_vtysh, "lsp-refresh-interval level-2 <1-65235>", "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, no_bgp_router_id_val_cmd_vtysh, "no bgp router-id A.B.C.D", "Negate a command or set its defaults\n" "BGP information\n" "Override configured router identifier\n" "Manually configured router identifier\n") DEFSH (0, show_ipv6_bgp_community2_exact_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, clear_bgp_external_soft_cmd_vtysh, "clear bgp external soft", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n") DEFSH (0, no_ipv6_nd_homeagent_preference_val_cmd_vtysh, "no ipv6 nd home-agent-preference <0-65535>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFSH (0, show_bgp_view_neighbor_flap_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_detail_cmd_vtysh, "show ipv6 prefix-list detail", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Detail of prefix lists\n") DEFSH (0, neighbor_local_as_no_prepend_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") DEFSH (0, debug_ospf_lsa_sub_cmd_vtysh, "debug ospf lsa (generate|flooding|install|refresh)", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Link State Advertisement\n" "LSA Generation\n" "LSA Flooding\n" "LSA Install/Delete\n" "LSA Refresh\n") DEFSH (0, no_neighbor_local_as_val2_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") DEFSH (0|0|0|0, show_ip_prefix_list_name_seq_cmd_vtysh, "show ip prefix-list WORD seq <1-4294967295>", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n") DEFSH (0, area_range_cmd_vtysh, "area A.B.C.D range X:X::X:X/M", "OSPF area parameters\n" "Area ID (as an IPv4 notation)\n" "Configured address range\n" "Specify IPv6 prefix\n" ) DEFSH (0, no_debug_zebra_packet_cmd_vtysh, "no debug zebra packet", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra packet\n") DEFSH (0, no_ospf_priority_cmd_vtysh, "no ospf priority", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Router priority\n") DEFSH (0, neighbor_attr_unchanged10_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") DEFSH (0, no_isis_hello_interval_l2_cmd_vtysh, "no isis hello-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, ospf_passive_interface_default_cmd_vtysh, "passive-interface default", "Suppress routing updates on an interface\n" "Suppress routing updates on interfaces by default\n") DEFSH (0, clear_ip_bgp_as_ipv4_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_scan_cmd_vtysh, "show ip bgp scan", "Show running system information\n" "IP information\n" "BGP information\n" "BGP scan status\n") DEFSH (0|0|0|0, ipv6_prefix_list_seq_cmd_vtysh, "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) (X:X::X:X/M|any)", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Any prefix match. Same as \"::0/0 le 128\"\n") DEFSH (0, show_bgp_ipv6_neighbor_routes_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, show_ip_igmp_parameters_cmd_vtysh, "show ip igmp parameters", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP parameters information\n") DEFSH (0|0|0|0, show_ip_prefix_list_prefix_longer_cmd_vtysh, "show ip prefix-list WORD A.B.C.D/M longer", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Lookup longer prefix\n") DEFSH (0, neighbor_interface_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "interface WORD", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Interface\n" "Interface name\n") DEFSH (0, show_ipv6_bgp_community4_exact_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_neighbor_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) ", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n") DEFSH (0, debug_igmp_cmd_vtysh, "debug igmp", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n") DEFSH (0, show_ip_bgp_flap_statistics_cmd_vtysh, "show ip bgp flap-statistics", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n") DEFSH (0, no_router_ripng_cmd_vtysh, "no router ripng", "Negate a command or set its defaults\n" "Enable a routing process\n" "Make RIPng instance command\n") DEFSH (0, no_debug_ripng_zebra_cmd_vtysh, "no debug ripng zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng and zebra communication\n") DEFSH (0|0|0|0, ipv6_prefix_list_seq_ge_le_cmd_vtysh, "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, show_bgp_ipv6_regexp_cmd_vtysh, "show bgp ipv6 regexp .LINE", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_detail_name_cmd_vtysh, "show ipv6 prefix-list detail WORD", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Detail of prefix lists\n" "Name of a prefix list\n") DEFSH (0, clear_ip_bgp_all_ipv4_out_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0|0|0|0, no_ip_prefix_list_sequence_number_cmd_vtysh, "no ip prefix-list sequence-number", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Include/exclude sequence numbers in NVGEN\n") DEFSH (0, no_debug_ospf_ism_cmd_vtysh, "no debug ospf ism", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Interface State Machine") DEFSH (0, rip_passive_interface_cmd_vtysh, "passive-interface (IFNAME|default)", "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") DEFSH (0, no_bandwidth_if_val_cmd_vtysh, "no bandwidth <1-10000000>", "Negate a command or set its defaults\n" "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") DEFSH (0, no_debug_isis_spfstats_cmd_vtysh, "no debug isis spf-statistics", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") DEFSH (0, show_ip_bgp_ipv4_community_list_exact_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, no_neighbor_attr_unchanged4_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med (as-path|next-hop)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") DEFSH (0, no_debug_ospf_nsm_sub_cmd_vtysh, "no debug ospf nsm (status|events|timers)", "Negate a command or set its defaults\n" "Debugging functions\n" "OSPF information\n" "OSPF Interface State Machine\n" "NSM Status Information\n" "NSM Event Information\n" "NSM Timer Information\n") DEFSH (0, debug_ripng_zebra_cmd_vtysh, "debug ripng zebra", "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng and zebra communication\n") DEFSH (0, show_ipv6_ospf6_route_type_cmd_vtysh, "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" ) DEFSH (0, no_ip_ospf_authentication_key_cmd_vtysh, "no ip ospf authentication-key", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n") DEFSH (0, no_ip_rip_receive_version_num_cmd_vtysh, "no ip rip receive version (1|2)", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "Version 1\n" "Version 2\n") DEFSH (0, rip_neighbor_cmd_vtysh, "neighbor A.B.C.D", "Specify a neighbor router\n" "Neighbor address\n") DEFSH (0, no_ospf_area_vlink_authkey_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication-key|)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, no_debug_zebra_events_cmd_vtysh, "no debug zebra events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra events\n") DEFSH (0, dynamic_hostname_cmd_vtysh, "hostname dynamic", "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") DEFSH (0, ip_ospf_retransmit_interval_cmd_vtysh, "ip ospf retransmit-interval <3-65535>", "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n") DEFSH (0, no_debug_bgp_all_cmd_vtysh, "no debug all bgp", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Enable all debugging\n" "BGP information\n") DEFSH (0, no_debug_bgp_events_cmd_vtysh, "no debug bgp events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP events\n") DEFSH (0, isis_hello_multiplier_l2_cmd_vtysh, "isis hello-multiplier <2-100> level-2", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, show_bgp_community_list_cmd_vtysh, "show bgp community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") DEFSH (0, show_ip_pim_assert_winner_metric_cmd_vtysh, "show ip pim assert-winner-metric", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert winner metric\n") DEFSH (0, show_ip_igmp_groups_retransmissions_cmd_vtysh, "show ip igmp groups retransmissions", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP groups information\n" "IGMP group retransmissions\n") DEFSH (0, show_ipv6_ospf6_linkstate_network_cmd_vtysh, "show ipv6 ospf6 linkstate network A.B.C.D A.B.C.D", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display linkstate routing table\n" "Display Network Entry\n" "Specify Router ID as IPv4 address notation\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, show_ipv6_ospf6_database_type_router_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_bgp_graceful_restart_stalepath_time_cmd_vtysh, "no bgp graceful-restart stalepath-time", "Negate a command or set its defaults\n" "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_le_cmd_vtysh, "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, undebug_bgp_normal_cmd_vtysh, "undebug bgp", "Disable debugging functions (see also 'debug')\n" "BGP information\n") DEFSH (0, no_ip_ospf_priority_addr_cmd_vtysh, "no ip ospf priority A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Address of interface") DEFSH (0, show_ip_bgp_ipv4_community2_exact_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, show_ip_bgp_community_list_cmd_vtysh, "show ip bgp community-list (<1-500>|WORD)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") DEFSH (0, show_ipv6_bgp_community3_exact_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_isis_hello_multiplier_arg_cmd_vtysh, "no isis hello-multiplier <2-100>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, no_neighbor_allowas_in_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "allow local ASN appears in aspath attribute\n") DEFSH (0, no_neighbor_attr_unchanged5_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, lsp_gen_interval_l2_cmd_vtysh, "lsp-gen-interval level-2 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") DEFSH (0, no_debug_ospf_nssa_cmd_vtysh, "no debug ospf nssa", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF nssa information\n") DEFSH (0, no_bgp_default_local_preference_val_cmd_vtysh, "no bgp default local-preference <0-4294967295>", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") DEFSH (0, show_bgp_view_afi_safi_community2_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, clear_ip_bgp_peer_group_in_cmd_vtysh, "clear ip bgp peer-group WORD in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFSH (0, clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh, "clear ip bgp * vpnv4 unicast soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_ip_rip_authentication_mode_cmd_vtysh, "no ip rip authentication mode", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n") DEFSH (0, neighbor_attr_unchanged6_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Med attribute\n" "Nexthop attribute\n") DEFSH (0, no_debug_rip_packet_cmd_vtysh, "no debug rip packet", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP packet\n") DEFSH (0, no_bgp_distance_source_access_list_cmd_vtysh, "no distance <1-255> A.B.C.D/M WORD", "Negate a command or set its defaults\n" "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") DEFSH (0, ipv6_ospf6_retransmitinterval_cmd_vtysh, "ipv6 ospf6 retransmit-interval <1-65535>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Time between retransmitting lost link state advertisements\n" "<1-65535> Seconds\n" ) DEFSH (0|0|0|0|0|0, rmap_onmatch_goto_cmd_vtysh, "on-match goto <1-65535>", "Exit policy on matches\n" "Goto Clause number\n" "Number\n") DEFSH (0, no_bandwidth_if_cmd_vtysh, "no bandwidth", "Negate a command or set its defaults\n" "Set bandwidth informational parameter\n") DEFSH (0, show_ip_bgp_ipv4_community3_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, ipv6_nd_prefix_prefix_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFSH (0, neighbor_filter_list_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Establish BGP filters\n" "AS path access-list name\n" "Filter incoming routes\n" "Filter outgoing routes\n") DEFSH (0, no_debug_ospf6_neighbor_cmd_vtysh, "no debug ospf6 neighbor", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Neighbor\n" ) DEFSH (0, no_ip_multicast_routing_cmd_vtysh, "no" " " "ip multicast-routing", "Negate a command or set its defaults\n" "IP information\n" "Global IP configuration subcommands\n" "Enable IP multicast forwarding\n") DEFSH (0, show_ip_rib_cmd_vtysh, "show ip rib A.B.C.D", "Show running system information\n" "IP information\n" "IP unicast routing table\n" "Unicast address\n") DEFSH (0, clear_bgp_ipv6_all_cmd_vtysh, "clear bgp ipv6 *", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n") DEFSH (0, ospf_area_stub_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) stub", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") DEFSH (0|0|0|0|0|0, rmap_call_cmd_vtysh, "call WORD", "Jump to another Route-Map after match+set\n" "Target route-map name\n") DEFSH (0, old_no_ipv6_aggregate_address_summary_only_cmd_vtysh, "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", "Negate a command or set its defaults\n" "IPv6 information\n" "BGP information\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, no_ospf_area_default_cost_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") DEFSH (0, show_ipv6_ospf6_route_match_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M match", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Specify IPv6 prefix\n" "Display routes which match the specified route\n" ) DEFSH (0, ospf_rfc1583_flag_cmd_vtysh, "ospf rfc1583compatibility", "OSPF specific commands\n" "Enable the RFC1583Compatibility flag\n") DEFSH (0, no_set_vpnv4_nexthop_val_cmd_vtysh, "no set vpnv4 next-hop A.B.C.D", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") DEFSH (0, bgp_damp_set3_cmd_vtysh, "bgp dampening", "BGP Specific commands\n" "Enable route-flap dampening\n") DEFSH (0, debug_ospf6_route_cmd_vtysh, "debug ospf6 route (table|intra-area|inter-area|memory)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug route table calculation\n" "Debug detail\n" "Debug intra-area route calculation\n" "Debug inter-area route calculation\n" "Debug route memory use\n" ) DEFSH (0, show_mpls_te_link_cmd_vtysh, "show mpls-te interface [INTERFACE]", "Show running system information\n" "MPLS-TE information\n" "Interface information\n" "Interface name\n") DEFSH (0, show_ip_bgp_community3_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, ip_ospf_retransmit_interval_addr_cmd_vtysh, "ip ospf retransmit-interval <3-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n" "Address of interface") DEFSH (0|0|0|0|0|0, rmap_onmatch_next_cmd_vtysh, "on-match next", "Exit policy on matches\n" "Next clause\n") DEFSH (0, bandwidth_if_cmd_vtysh, "bandwidth <1-10000000>", "Set bandwidth informational parameter\n" "Bandwidth in kilobits\n") DEFSH (0, neighbor_local_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n") DEFSH (0, ip_ospf_dead_interval_minimal_addr_cmd_vtysh, "ip ospf dead-interval minimal hello-multiplier <1-10> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n" "Address of interface\n") DEFSH (0, no_set_src_cmd_vtysh, "no set src", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Source address for route\n") DEFSH (0, capability_opaque_cmd_vtysh, "capability opaque", "Enable specific OSPF feature\n" "Opaque LSA\n") DEFSH (0, no_access_list_extended_mask_host_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "A single destination host\n" "Destination address\n") DEFSH (0, show_bgp_statistics_view_vpnv4_cmd_vtysh, "show bgp view WORD (ipv4) (vpnv4) statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, no_isis_hello_interval_l1_cmd_vtysh, "no isis hello-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, no_set_weight_val_cmd_vtysh, "no set weight <0-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP weight for routing table\n" "Weight value\n") DEFSH (0, bgp_config_type_cmd_vtysh, "bgp config-type (cisco|zebra)", "BGP information\n" "Configuration type\n" "cisco\n" "zebra\n") DEFSH (0, match_ip_route_source_prefix_list_cmd_vtysh, "match ip route-source prefix-list WORD", "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, show_bgp_ipv6_neighbor_received_routes_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, no_ripng_redistribute_ripng_cmd_vtysh, "no redistribute ripng", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "RIPng route\n") DEFSH (0, clear_bgp_peer_in_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) in", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") DEFSH (0, show_ip_bgp_neighbors_cmd_vtysh, "show ip bgp neighbors", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, clear_bgp_all_rsclient_cmd_vtysh, "clear bgp * rsclient", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, debug_isis_packet_dump_cmd_vtysh, "debug isis packet-dump", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS packet dump\n") DEFSH (0, neighbor_allowas_in_arg_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in <1-10>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Accept as-path with my AS present in it\n" "Number of occurances of AS number\n") DEFSH (0, show_ip_bgp_ipv4_neighbors_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, no_ospf_log_adjacency_changes_cmd_vtysh, "no log-adjacency-changes", "Negate a command or set its defaults\n" "Log changes in adjacency state\n") DEFSH (0, ospf6_redistribute_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|isis|bgp|babel)", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" ) DEFSH (0, no_access_list_extended_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, no_neighbor_attr_unchanged_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n") DEFSH (0, show_bgp_instance_ipv4_safi_summary_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, no_set_ecommunity_rt_val_cmd_vtysh, "no set extcommunity rt .ASN:nn_or_IP-address:nn", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Route Target extended community\n" "VPN extended community\n") DEFSH (0, no_router_isis_cmd_vtysh, "no router isis WORD", "no\n" "Enable a routing process\n" "ISO IS-IS\n" "ISO Routing area tag") DEFSH (0, no_ospf_area_filter_list_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Filter networks between OSPF areas\n" "Filter prefixes between OSPF areas\n" "Name of an IP prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") DEFSH (0, isis_priority_cmd_vtysh, "isis priority <0-127>", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFSH (0, no_ospf_passive_interface_cmd_vtysh, "no passive-interface IFNAME", "Negate a command or set its defaults\n" "Allow routing updates on an interface\n" "Interface's name\n") DEFSH (0, no_csnp_interval_cmd_vtysh, "no isis csnp-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n") DEFSH (0, no_access_list_extended_host_mask_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, show_ipv6_bgp_prefix_longer_cmd_vtysh, "show ipv6 bgp X:X::X:X/M longer-prefixes", "Show running system information\n" "IPv6 information\n" "BGP information\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") DEFSH (0, show_ipv6_mbgp_community_all_cmd_vtysh, "show ipv6 mbgp community", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n") DEFSH (0, show_ip_bgp_view_cmd_vtysh, "show ip bgp view WORD", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n") DEFSH (0, clear_ip_mroute_cmd_vtysh, "clear ip mroute", "Reset functions\n" "IP information\n" "Reset multicast routes\n") DEFSH (0, clear_ip_bgp_peer_vpnv4_in_cmd_vtysh, "clear ip bgp A.B.C.D vpnv4 unicast in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFSH (0, ip_ospf_priority_addr_cmd_vtysh, "ip ospf priority <0-255> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n" "Address of interface") DEFSH (0, show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, metric_style_cmd_vtysh, "metric-style (narrow|transition|wide)", "Use old-style (ISO 10589) or new-style packet formats\n" "Use old style of TLVs with narrow metric\n" "Send and accept both styles of TLVs during transition\n" "Use new style of TLVs to carry wider metric\n") DEFSH (0, no_debug_ospf6_lsa_hex_cmd_vtysh, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFSH (0, show_bgp_neighbor_received_prefix_filter_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, neighbor_allowas_in_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "allowas-in", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Accept as-path with my AS present in it\n") DEFSH (0, ipv6_bgp_network_cmd_vtysh, "network X:X::X:X/M", "Specify a network to announce via BGP\n" "IPv6 prefix /\n") DEFSH (0, no_ospf_area_import_list_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) import-list NAME", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") DEFSH (0, show_bgp_view_afi_safi_community3_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, show_ipv6_ospf6_database_id_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, show_bgp_ipv6_safi_rsclient_route_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, send_lifetime_infinite_month_day_cmd_vtysh, "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", "Set send lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Never expires") DEFSH (0, show_ip_access_list_name_cmd_vtysh, "show ip access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD)", "Show running system information\n" "IP information\n" "List IP access lists\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n") DEFSH (0|0, no_match_tag_val_cmd_vtysh, "no match tag <0-65535>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match tag of route\n" "Metric value\n") DEFSH (0, neighbor_ebgp_multihop_ttl_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Allow EBGP neighbors not on directly connected networks\n" "maximum hop count\n") DEFSH (0, clear_bgp_all_soft_cmd_vtysh, "clear bgp * soft", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n") DEFSH (0, clear_bgp_peer_group_soft_out_cmd_vtysh, "clear bgp peer-group WORD soft out", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_ipv6_ospf6_redistribute_cmd_vtysh, "show ipv6 ospf6 redistribute", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "redistributing External information\n" ) DEFSH (0, clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, spf_interval_l1_cmd_vtysh, "spf-interval level-1 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, no_ip_ospf_hello_interval_addr_cmd_vtysh, "no ip ospf hello-interval A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Address of interface") DEFSH (0, no_ipv6_nd_managed_config_flag_cmd_vtysh, "no ipv6 nd managed-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") DEFSH (0, ospf_neighbor_priority_poll_interval_cmd_vtysh, "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", "Specify neighbor router\n" "Neighbor IP address\n" "Neighbor Priority\n" "Priority\n" "Dead Neighbor Polling interval\n" "Seconds\n") DEFSH (0, ip_forwarding_cmd_vtysh, "ip forwarding", "IP information\n" "Turn on IP forwarding") DEFSH (0, ospf_timers_throttle_spf_cmd_vtysh, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") DEFSH (0, ip_community_list_standard2_cmd_vtysh, "ip community-list <1-99> (deny|permit)", "IP information\n" "Add a community list entry\n" "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n") DEFSH (0, ipv6_nd_ra_interval_cmd_vtysh, "ipv6 nd ra-interval <1-1800>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in seconds\n") DEFSH (0, no_synchronization_cmd_vtysh, "no synchronization", "Negate a command or set its defaults\n" "Perform IGP synchronization\n") DEFSH (0, no_debug_isis_events_cmd_vtysh, "no debug isis events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Events\n") DEFSH (0, show_ipv6_ospf6_database_type_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" ) DEFSH (0, neighbor_soft_reconfiguration_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") DEFSH (0, no_debug_ospf6_interface_cmd_vtysh, "no debug ospf6 interface", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Interface\n" ) DEFSH (0, debug_isis_spftrigg_cmd_vtysh, "debug isis spf-triggers", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS SPF triggering events\n") DEFSH (0, aggregate_address_summary_only_cmd_vtysh, "aggregate-address A.B.C.D/M summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, ip_route_mask_flags2_cmd_vtysh, "ip route A.B.C.D A.B.C.D (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ipv6_mbgp_community4_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_ipv6_router_isis_cmd_vtysh, "no ipv6 router isis WORD", "Negate a command or set its defaults\n" "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") DEFSH (0, clear_ip_bgp_all_soft_in_cmd_vtysh, "clear ip bgp * soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_ospf_default_metric_cmd_vtysh, "no default-metric", "Negate a command or set its defaults\n" "Set metric of redistributed routes\n") DEFSH (0, clear_ip_pim_oil_cmd_vtysh, "clear ip pim oil", "Reset functions\n" "IP information\n" "PIM clear commands\n" "Rescan PIM OIL (output interface list)\n") DEFSH (0, ip_ospf_authentication_key_addr_cmd_vtysh, "ip ospf authentication-key AUTH_KEY A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)\n" "Address of interface") DEFSH (0, show_bgp_ipv6_community_list_cmd_vtysh, "show bgp ipv6 community-list (<1-500>|WORD)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") DEFSH (0, show_ip_bgp_dampened_paths_cmd_vtysh, "show ip bgp dampened-paths", "Show running system information\n" "IP information\n" "BGP information\n" "Display paths suppressed due to dampening\n") DEFSH (0|0|0|0, show_ip_prefix_list_detail_name_cmd_vtysh, "show ip prefix-list detail WORD", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Detail of prefix lists\n" "Name of a prefix list\n") DEFSH (0, show_bgp_ipv6_community3_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_seq_ge_cmd_vtysh, "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, rip_timers_cmd_vtysh, "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", "Adjust routing timers\n" "Basic routing protocol update timers\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") DEFSH (0, show_debugging_bgp_cmd_vtysh, "show debugging bgp", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "BGP information\n") DEFSH (0, show_database_arg_cmd_vtysh, "show isis database WORD", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n") DEFSH (0, ospf6_router_id_cmd_vtysh, "router-id A.B.C.D", "Configure OSPF Router-ID\n" "specify by IPv4 address notation(e.g. 0.0.0.0)\n") DEFSH (0, show_ip_route_cmd_vtysh, "show ip route", "Show running system information\n" "IP information\n" "IP routing table\n") DEFSH (0, no_ip_ospf_authentication_key_addr_cmd_vtysh, "no ip ospf authentication-key A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "Address of interface") DEFSH (0, show_zebra_client_cmd_vtysh, "show zebra client", "Show running system information\n" "Zebra information" "Client information") DEFSH (0, ripng_passive_interface_cmd_vtysh, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface name\n") DEFSH (0, no_ip_rip_authentication_mode_type_authlen_cmd_vtysh, "no ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFSH (0, show_ipv6_ospf6_database_id_detail_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_neighbor_unsuppress_map_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Route-map to selectively unsuppress suppressed routes\n" "Name of route map\n") DEFSH (0, no_ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh, "no ipv6 ripng split-horizon poisoned-reverse", "Negate a command or set its defaults\n" "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, clear_ip_bgp_peer_ipv4_soft_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, neighbor_dont_capability_negotiate_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "dont-capability-negotiate", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Do not perform capability negotiation\n") DEFSH (0|0|0|0, no_ip_prefix_list_seq_le_ge_cmd_vtysh, "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, debug_ospf_zebra_sub_cmd_vtysh, "debug ospf zebra (interface|redistribute)", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Zebra information\n" "Zebra interface\n" "Zebra redistribute\n") DEFSH (0, no_ip_ospf_hello_interval_cmd_vtysh, "no ip ospf hello-interval", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n") DEFSH (0, no_bgp_redistribute_ipv6_rmap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_debug_ospf_lsa_cmd_vtysh, "no debug ospf lsa", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Link State Advertisement\n") DEFSH (0, no_match_ip_route_source_val_cmd_vtysh, "no match ip route-source (<1-199>|<1300-2699>|WORD)", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP standard access-list name\n") DEFSH (0, show_bgp_view_ipv6_neighbor_received_routes_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, clear_bgp_ipv6_peer_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X)", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n") DEFSH (0, test_pim_receive_upcall_cmd_vtysh, "test pim receive upcall (nocache|wrongvif|wholepkt) <0-65535> A.B.C.D A.B.C.D", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test reception of kernel upcall\n" "NOCACHE kernel upcall\n" "WRONGVIF kernel upcall\n" "WHOLEPKT kernel upcall\n" "Input interface vif index\n" "Multicast group address\n" "Multicast source address\n") DEFSH (0, ipv6_access_list_exact_cmd_vtysh, "ipv6 access-list WORD (deny|permit) X:X::X:X/M exact-match", "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 3ffe:506::/32\n" "Exact match of the prefixes\n") DEFSH (0, ip_ssmpingd_cmd_vtysh, "ip ssmpingd [A.B.C.D]", "IP information\n" "Enable ssmpingd operation\n" "Source address\n") DEFSH (0, no_ospf_area_authentication_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) authentication", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n") DEFSH (0, show_ipv6_ospf6_route_type_detail_cmd_vtysh, "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2) detail", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" "Detailed information\n" ) DEFSH (0, key_string_cmd_vtysh, "key-string LINE", "Set key string\n" "The key\n") DEFSH (0, ospf_area_default_cost_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") DEFSH (0, bgp_graceful_restart_cmd_vtysh, "bgp graceful-restart", "BGP specific commands\n" "Graceful restart capability parameters\n") DEFSH (0, neighbor_port_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Neighbor's BGP port\n" "TCP port number\n") DEFSH (0, bgp_network_mask_natural_cmd_vtysh, "network A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n") DEFSH (0, no_ipv6_nd_reachable_time_val_cmd_vtysh, "no ipv6 nd reachable-time <1-3600000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFSH (0, no_debug_ospf6_spf_process_cmd_vtysh, "no debug ospf6 spf process", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Quit Debugging SPF Calculation\n" "Quit Debugging Detailed SPF Process\n" ) DEFSH (0, lsp_refresh_interval_l1_cmd_vtysh, "lsp-refresh-interval level-1 <1-65235>", "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, aggregate_address_mask_as_set_cmd_vtysh, "aggregate-address A.B.C.D A.B.C.D as-set", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n") DEFSH (0, neighbor_route_server_client_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-server-client", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure a neighbor as Route Server client\n") DEFSH (0, debug_isis_upd_cmd_vtysh, "debug isis update-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Update related packets\n") DEFSH (0, no_neighbor_attr_unchanged10_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med as-path next-hop", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") DEFSH (0, config_table_cmd_vtysh, "table TABLENO", "Configure target kernel routing table\n" "TABLE integer\n") DEFSH (0, show_bgp_ipv6_cmd_vtysh, "show bgp ipv6", "Show running system information\n" "BGP information\n" "Address family\n") DEFSH (0, undebug_pim_events_cmd_vtysh, "undebug pim events", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, show_bgp_community_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, lsp_gen_interval_cmd_vtysh, "lsp-gen-interval <1-120>", "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFSH (0, no_psnp_interval_l1_cmd_vtysh, "no isis psnp-interval level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, no_ripng_redistribute_type_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n") DEFSH (0, clear_ip_bgp_external_cmd_vtysh, "clear ip bgp external", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n") DEFSH (0, debug_ripng_events_cmd_vtysh, "debug ripng events", "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng events\n") DEFSH (0, area_import_list_cmd_vtysh, "area A.B.C.D import-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Set the filter for networks from other areas announced to the specified one\n" "Name of the acess-list\n") DEFSH (0, show_bgp_ipv6_safi_route_cmd_vtysh, "show bgp ipv6 (unicast|multicast) X:X::X:X", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") DEFSH (0, no_auto_cost_reference_bandwidth_cmd_vtysh, "no auto-cost reference-bandwidth", "Negate a command or set its defaults\n" "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n") DEFSH (0, no_debug_zebra_rib_cmd_vtysh, "no debug zebra rib", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra RIB\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, dump_bgp_all_cmd_vtysh, "dump bgp all PATH", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n") DEFSH (0, no_rip_timers_cmd_vtysh, "no timers basic", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Basic routing protocol update timers\n") DEFSH (0, debug_bgp_fsm_cmd_vtysh, "debug bgp fsm", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Finite State Machine\n") DEFSH (0, rip_network_cmd_vtysh, "network (A.B.C.D/M|WORD)", "Enable routing on an IP network\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Interface name\n") DEFSH (0, no_debug_ospf_event_cmd_vtysh, "no debug ospf event", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF event information\n") DEFSH (0, bgp_redistribute_ipv6_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n") DEFSH (0, undebug_igmp_packets_cmd_vtysh, "undebug igmp packets", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0, debug_isis_adj_cmd_vtysh, "debug isis adj-packets", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Adjacency related packets\n") DEFSH (0, undebug_pim_trace_cmd_vtysh, "undebug pim trace", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, ripng_default_information_originate_cmd_vtysh, "default-information originate", "Default route information\n" "Distribute default route\n") DEFSH (0, no_neighbor_default_originate_rmap_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate route-map WORD", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Originate default route to this neighbor\n" "Route-map to specify criteria to originate default\n" "route-map name\n") DEFSH (0, clear_ip_bgp_instance_all_soft_in_cmd_vtysh, "clear ip bgp view WORD * soft in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_debug_pim_packets_filter_cmd_vtysh, "no debug pim packets (hello|joins)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol packets\n" "PIM Hello protocol packets\n" "PIM Join/Prune protocol packets\n") DEFSH (0, ip_ospf_message_digest_key_addr_cmd_vtysh, "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" "Address of interface") DEFSH (0, no_ipv6_route_ifname_flags_cmd_vtysh, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_description_cmd_vtysh, "no ipv6 prefix-list WORD description", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n") DEFSH (0, no_neighbor_description_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description .LINE", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Neighbor specific description\n" "Up to 80 characters describing this neighbor\n") DEFSH (0, show_ip_pim_join_cmd_vtysh, "show ip pim join", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface join information\n") DEFSH (0, no_bgp_bestpath_aspath_multipath_relax_cmd_vtysh, "no bgp bestpath as-path multipath-relax", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") DEFSH (0, clear_bgp_ipv6_external_soft_cmd_vtysh, "clear bgp ipv6 external soft", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig\n") DEFSH (0, no_isis_metric_l1_cmd_vtysh, "no isis metric level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-1 routing\n") DEFSH (0, neighbor_password_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "password LINE", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set a password\n" "The password\n") DEFSH (0, ip_rip_authentication_mode_authlen_cmd_vtysh, "ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFSH (0, no_neighbor_enforce_multihop_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Enforce EBGP neighbors perform multihop\n") DEFSH (0, no_debug_ospf_packet_send_recv_cmd_vtysh, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", "Negate a command or set its defaults\n" "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") DEFSH (0, no_debug_bgp_normal_cmd_vtysh, "no debug bgp", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n") DEFSH (0, area_passwd_md5_snpauth_cmd_vtysh, "area-password md5 WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, no_set_metric_type_cmd_vtysh, "no set metric-type", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Type of metric for destination routing protocol\n") DEFSH (0|0|0|0, no_match_ip_address_prefix_list_val_cmd_vtysh, "no match ip address prefix-list WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, ipv6_bgp_neighbor_received_routes_cmd_vtysh, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, no_ip_community_list_name_expanded_cmd_vtysh, "no ip community-list expanded WORD (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Specify an expanded community-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, no_bgp_bestpath_aspath_confed_cmd_vtysh, "no bgp bestpath as-path confed", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") DEFSH (0, show_debugging_zebra_cmd_vtysh, "show debugging zebra", "Show running system information\n" "Debugging information\n" "Zebra configuration\n") DEFSH (0, access_list_standard_cmd_vtysh, "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n" "Wildcard bits\n") DEFSH (0, show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh, "show ip bgp vpnv4 all neighbors", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0|0|0|0, no_match_ip_next_hop_cmd_vtysh, "no match ip next-hop", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n") DEFSH (0, no_ipv6_access_list_cmd_vtysh, "no ipv6 access-list WORD (deny|permit) X:X::X:X/M", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 3ffe:506::/32\n") DEFSH (0, ospf_opaque_capable_cmd_vtysh, "ospf opaque-lsa", "OSPF specific commands\n" "Enable the Opaque-LSA capability (rfc2370)\n") DEFSH (0, no_bgp_always_compare_med_cmd_vtysh, "no bgp always-compare-med", "Negate a command or set its defaults\n" "BGP specific commands\n" "Allow comparing MED from different neighbors\n") DEFSH (0, rip_redistribute_rip_cmd_vtysh, "redistribute rip", "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") DEFSH (0, show_bgp_view_neighbor_routes_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, show_bgp_view_neighbor_advertised_route_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, linkdetect_cmd_vtysh, "link-detect", "Enable link detection on interface\n") DEFSH (0, show_bgp_ipv6_community4_exact_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ip_bgp_vpnv4_rd_summary_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Summary of BGP neighbor status\n") DEFSH (0, no_match_ecommunity_cmd_vtysh, "no match extcommunity", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP/VPN extended community list\n") DEFSH (0, ipv6_nd_prefix_noval_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Set Router Address flag\n") DEFSH (0, set_aspath_prepend_lastas_cmd_vtysh, "set as-path prepend (last-as) <1-10>", "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" "Number of times to insert") DEFSH (0, bgp_network_cmd_vtysh, "network A.B.C.D/M", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, show_ipv6_ospf6_route_detail_cmd_vtysh, "show ipv6 ospf6 route (X:X::X:X|X:X::X:X/M|detail|summary)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Specify IPv6 address\n" "Specify IPv6 prefix\n" "Detailed information\n" "Summary of route table\n" ) DEFSH (0|0|0|0, show_ipv6_prefix_list_prefix_first_match_cmd_vtysh, "show ipv6 prefix-list WORD X:X::X:X/M first-match", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "First matched prefix\n") DEFSH (0, no_neighbor_route_map_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out|import|export)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") DEFSH (0, no_ospf6_interface_area_cmd_vtysh, "no interface IFNAME area A.B.C.D", "Negate a command or set its defaults\n" "Disable routing on an IPv6 interface\n" "Interface name(e.g. ep0)\n" "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) DEFSH (0, show_babel_neighbour_cmd_vtysh, "show babel neighbour [INTERFACE]", "Show running system information\n" "IP information\n" "Babel information\n" "Print neighbours\n" "Interface name\n") DEFSH (0, neighbor_enforce_multihop_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "enforce-multihop", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Enforce EBGP neighbors perform multihop\n") DEFSH (0, if_rmap_cmd_vtysh, "route-map RMAP_NAME (in|out) IFNAME", "Route map set\n" "Route map name\n" "Route map set for input filtering\n" "Route map set for output filtering\n" "Route map interface name\n") DEFSH (0, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFSH (0, no_ripng_redistribute_type_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " metric <0-16>", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n") DEFSH (0, ip_extcommunity_list_expanded_cmd_vtysh, "ip extcommunity-list <100-500> (deny|permit) .LINE", "IP information\n" "Add a extended community list entry\n" "Extended Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, show_ipv6_mbgp_community2_exact_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, clear_bgp_external_out_cmd_vtysh, "clear bgp external out", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_route_addr_cmd_vtysh, "show ip route A.B.C.D", "Show running system information\n" "IP information\n" "IP routing table\n" "Network in the IP routing table to display\n") DEFSH (0, no_debug_isis_spfevents_cmd_vtysh, "no debug isis spf-events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Shortest Path First Events\n") DEFSH (0, show_ipv6_route_prefix_longer_cmd_vtysh, "show ipv6 route X:X::X:X/M longer-prefixes", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 prefix\n" "Show route matching the specified Network/Mask pair only\n") DEFSH (0, mpls_te_on_cmd_vtysh, "mpls-te on", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") DEFSH (0, spf_interval_cmd_vtysh, "spf-interval <1-120>", "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0|0|0|0, ip_prefix_list_seq_le_ge_cmd_vtysh, "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_ipv6_nd_mtu_cmd_vtysh, "no ipv6 nd mtu", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n") DEFSH (0, bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, clear_bgp_peer_rsclient_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, no_neighbor_local_as_val3_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>" " no-prepend replace-as", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") DEFSH (0, show_ip_route_summary_cmd_vtysh, "show ip route summary", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n") DEFSH (0, undebug_bgp_events_cmd_vtysh, "undebug bgp events", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP events\n") DEFSH (0, show_bgp_community2_exact_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0|0|0|0, no_ip_prefix_list_prefix_cmd_vtysh, "no ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") DEFSH (0, no_ip_community_list_name_standard_all_cmd_vtysh, "no ip community-list standard WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Add a standard community-list entry\n" "Community list name\n") DEFSH (0, no_bgp_bestpath_med_cmd_vtysh, "no bgp bestpath med (confed|missing-as-worst)", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") DEFSH (0, dump_bgp_updates_cmd_vtysh, "dump bgp updates PATH", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n") DEFSH (0, ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh, "ipv6 ripng split-horizon poisoned-reverse", "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFSH (0, show_ipv6_mbgp_cmd_vtysh, "show ipv6 mbgp", "Show running system information\n" "IP information\n" "MBGP information\n") DEFSH (0, ip_irdp_debug_misc_cmd_vtysh, "ip irdp debug misc", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, set_aspath_exclude_cmd_vtysh, "set as-path exclude ." "<1-4294967295>", "Set values in destination routing protocol\n" "Transform BGP AS-path attribute\n" "Exclude from the as-path\n" "AS number\n") DEFSH (0, no_ip_as_path_all_cmd_vtysh, "no ip as-path access-list WORD", "Negate a command or set its defaults\n" "IP information\n" "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n") DEFSH (0, show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, no_ripng_passive_interface_cmd_vtysh, "no passive-interface IFNAME", "Negate a command or set its defaults\n" "Suppress routing updates on an interface\n" "Interface name\n") DEFSH (0, show_isis_summary_cmd_vtysh, "show isis summary", "Show running system information\n" "IS-IS information\n" "IS-IS summary\n") DEFSH (0, access_list_exact_cmd_vtysh, "access-list WORD (deny|permit) A.B.C.D/M exact-match", "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n" "Exact match of the prefixes\n") DEFSH (0, clear_ip_bgp_all_vpnv4_soft_cmd_vtysh, "clear ip bgp * vpnv4 unicast soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, no_access_list_cmd_vtysh, "no access-list WORD (deny|permit) A.B.C.D/M", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP zebra access-list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 10.0.0.0/8\n") DEFSH (0, clear_ip_bgp_as_vpnv4_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " vpnv4 unicast soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, no_shutdown_if_cmd_vtysh, "no shutdown", "Negate a command or set its defaults\n" "Shutdown the selected interface\n") DEFSH (0, show_ipv6_ospf6_database_id_router_detail_cmd_vtysh, "show ipv6 ospf6 database * A.B.C.D A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_area_filter_list_cmd_vtysh, "no area A.B.C.D filter-list prefix WORD (in|out)", "Negate a command or set its defaults\n" "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Filter networks between OSPFv6 areas\n" "Filter prefixes between OSPFv6 areas\n" "Name of an IPv6 prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") DEFSH (0, no_redistribute_ospf6_cmd_vtysh, "no redistribute ospf6", "Negate a command or set its defaults\n" "Redistribute control\n" "OSPF6 route\n") DEFSH (0, ospf6_routemap_no_set_forwarding_cmd_vtysh, "no set forwarding-address X:X::X:X", "Negate a command or set its defaults\n" "Set value\n" "Forwarding Address\n" "IPv6 Address\n") DEFSH (0, show_ipv6_bgp_community3_cmd_vtysh, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, show_bgp_view_route_cmd_vtysh, "show bgp view WORD X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_bgp_route_cmd_vtysh, "show ip bgp A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Network in the BGP routing table to display\n") DEFSH (0, ip_ospf_network_cmd_vtysh, "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "IP Information\n" "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") DEFSH (0, ip_ospf_cost_u32_inet4_cmd_vtysh, "ip ospf cost <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, ospf_neighbor_priority_cmd_vtysh, "neighbor A.B.C.D priority <0-255>", "Specify neighbor router\n" "Neighbor IP address\n" "Neighbor Priority\n" "Seconds\n") DEFSH (0, debug_ospf6_brouter_area_cmd_vtysh, "debug ospf6 border-routers area-id A.B.C.D", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug border routers in specific Area\n" "Specify Area-ID\n" ) DEFSH (0|0|0|0, ipv6_prefix_list_ge_cmd_vtysh, "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, ripng_timers_cmd_vtysh, "timers basic <0-65535> <0-65535> <0-65535>", "RIPng timers setup\n" "Basic timer\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") DEFSH (0|0|0|0, ip_prefix_list_seq_cmd_vtysh, "ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") DEFSH (0, send_lifetime_duration_month_day_cmd_vtysh, "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> duration <1-2147483646>", "Set send lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Duration of the key\n" "Duration seconds\n") DEFSH (0, clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh, "show ip bgp vpnv4 all neighbors A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") DEFSH (0, show_bgp_prefix_cmd_vtysh, "show bgp X:X::X:X/M", "Show running system information\n" "BGP information\n" "IPv6 prefix /\n") DEFSH (0, no_aggregate_address_mask_summary_only_cmd_vtysh, "no aggregate-address A.B.C.D A.B.C.D summary-only", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n") DEFSH (0, area_passwd_clear_snpauth_cmd_vtysh, "area-password clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, no_ipv6_forwarding_cmd_vtysh, "no ipv6 forwarding", "Negate a command or set its defaults\n" "IPv6 information\n" "Turn off IPv6 forwarding") DEFSH (0, no_bgp_cluster_id_cmd_vtysh, "no bgp cluster-id", "Negate a command or set its defaults\n" "BGP information\n" "Configure Route-Reflector Cluster-id\n") DEFSH (0, ip_ospf_hello_interval_cmd_vtysh, "ip ospf hello-interval <1-65535>", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFSH (0, isis_metric_l2_cmd_vtysh, "isis metric <0-16777215> level-2", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") DEFSH (0, show_ip_igmp_sources_retransmissions_cmd_vtysh, "show ip igmp sources retransmissions", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP sources information\n" "IGMP source retransmissions\n") DEFSH (0, no_router_id_cmd_vtysh, "no router-id", "Negate a command or set its defaults\n" "Remove the manually configured router-id\n") DEFSH (0, no_neighbor_attr_unchanged9_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged med next-hop as-path", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "Nexthop attribute\n" "As-path attribute\n") DEFSH (0, match_aspath_cmd_vtysh, "match as-path WORD", "Match values from routing table\n" "Match BGP AS path list\n" "AS path access-list name\n") DEFSH (0, undebug_bgp_keepalive_cmd_vtysh, "undebug bgp keepalives", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP keepalives\n") DEFSH (0, no_rip_distance_cmd_vtysh, "no distance <1-255>", "Negate a command or set its defaults\n" "Administrative distance\n" "Distance value\n") DEFSH (0, no_rip_distance_source_cmd_vtysh, "no distance <1-255> A.B.C.D/M", "Negate a command or set its defaults\n" "Administrative distance\n" "Distance value\n" "IP source prefix\n") DEFSH (0, clear_bgp_as_in_cmd_vtysh, "clear bgp " "<1-4294967295>" " in", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFSH (0, debug_igmp_trace_cmd_vtysh, "debug igmp trace", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0, show_bgp_ipv6_safi_summary_cmd_vtysh, "show bgp ipv6 (unicast|multicast) summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, no_debug_ripng_events_cmd_vtysh, "no debug ripng events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng events\n") DEFSH (0|0, set_ip_nexthop_cmd_vtysh, "set ip next-hop A.B.C.D", "Set values in destination routing protocol\n" "IP information\n" "Next hop address\n" "IP address of next hop\n") DEFSH (0, show_bgp_view_ipv6_neighbor_damp_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFSH (0|0|0|0, match_ip_next_hop_prefix_list_cmd_vtysh, "match ip next-hop prefix-list WORD", "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, no_ipv6_route_pref_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Distance value for this prefix\n") DEFSH (0, old_ipv6_bgp_network_cmd_vtysh, "ipv6 bgp network X:X::X:X/M", "IPv6 information\n" "BGP information\n" "Specify a network to announce via BGP\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, no_ipv6_nd_adv_interval_config_option_cmd_vtysh, "no ipv6 nd adv-interval-option", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") DEFSH (0, no_debug_ospf6_spf_time_cmd_vtysh, "no debug ospf6 spf time", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Quit Debugging SPF Calculation\n" "Quit Measuring time taken by SPF Calculation\n" ) DEFSH (0, debug_igmp_packets_cmd_vtysh, "debug igmp packets", "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0|0|0|0|0|0, rmap_description_cmd_vtysh, "description .LINE", "Route-map comment\n" "Comment describing this route-map rule\n") DEFSH (0, clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, ipv6_aggregate_address_summary_only_cmd_vtysh, "aggregate-address X:X::X:X/M summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, ipv6_ospf6_advertise_prefix_list_cmd_vtysh, "ipv6 ospf6 advertise prefix-list WORD", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Advertising options\n" "Filter prefix using prefix-list\n" "Prefix list name\n" ) DEFSH (0, mpls_te_link_max_rsv_bw_cmd_vtysh, "mpls-te link max-rsv-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that may be reserved\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, rip_route_cmd_vtysh, "route A.B.C.D/M", "RIP static route configuration\n" "IP prefix /\n") DEFSH (0, no_debug_isis_spftrigg_cmd_vtysh, "no debug isis spf-triggers", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS SPF triggering events\n") DEFSH (0, no_rip_redistribute_type_metric_routemap_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " metric <0-16> route-map WORD", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_bgp_ipv6_community3_exact_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, ripng_network_cmd_vtysh, "network IF_OR_ADDR", "RIPng enable on specified interface or network.\n" "Interface or address") DEFSH (0, show_ip_bgp_view_rsclient_prefix_cmd_vtysh, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, multicast_cmd_vtysh, "multicast", "Set multicast flag to interface\n") DEFSH (0, no_debug_pim_zebra_cmd_vtysh, "no debug pim zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0, bgp_client_to_client_reflection_cmd_vtysh, "bgp client-to-client reflection", "BGP specific commands\n" "Configure client to client route reflection\n" "reflection of routes allowed\n") DEFSH (0, no_lsp_gen_interval_arg_cmd_vtysh, "no lsp-gen-interval <1-120>", "Negate a command or set its defaults\n" "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFSH (0, ipv6_nd_prefix_val_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Set Router Address flag\n") DEFSH (0, no_psnp_interval_cmd_vtysh, "no isis psnp-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n") DEFSH (0, show_ip_bgp_prefix_cmd_vtysh, "show ip bgp A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, babel_set_resend_delay_cmd_vtysh, "babel resend-delay <20-655340>", "Babel commands\n" "Time before resending a message\n" "Milliseconds\n") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" ) DEFSH (0|0, no_set_tag_val_cmd_vtysh, "no set tag <0-65535>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Tag value for routing protocol\n" "Tag value\n") DEFSH (0, debug_ospf_event_cmd_vtysh, "debug ospf event", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF event information\n") DEFSH (0, ospf_area_export_list_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) export-list NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the filter for networks announced to other areas\n" "Name of the access-list\n") DEFSH (0, clear_bgp_ipv6_all_soft_cmd_vtysh, "clear bgp ipv6 * soft", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig\n") DEFSH (0, no_ip_extcommunity_list_name_standard_all_cmd_vtysh, "no ip extcommunity-list standard WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Specify standard extcommunity-list\n" "Extended Community list name\n") DEFSH (0, no_ip_mroute_cmd_vtysh, "no ip mroute A.B.C.D/M (A.B.C.D|INTERFACE)", "Negate a command or set its defaults\n" "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n") DEFSH (0, no_lsp_refresh_interval_l2_arg_cmd_vtysh, "no lsp-refresh-interval level-2 <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") DEFSH (0, show_ipv6_mbgp_community_exact_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0|0|0|0, ip_prefix_list_seq_le_cmd_vtysh, "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M le <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, show_ipv6_route_cmd_vtysh, "show ipv6 route", "Show running system information\n" "IP information\n" "IPv6 routing table\n") DEFSH (0|0|0|0, no_ip_prefix_list_description_cmd_vtysh, "no ip prefix-list WORD description", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n") DEFSH (0|0|0|0|0, set_metric_cmd_vtysh, "set metric <0-4294967295>", "Set value\n" "Metric value for destination routing protocol\n" "Metric value\n") DEFSH (0, clear_ip_bgp_all_ipv4_in_cmd_vtysh, "clear ip bgp * ipv4 (unicast|multicast) in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, no_set_local_pref_val_cmd_vtysh, "no set local-preference <0-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP local preference path attribute\n" "Preference value\n") DEFSH (0, ripng_redistribute_type_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n") DEFSH (0, show_ip_bgp_rsclient_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, show_ip_pim_secondary_cmd_vtysh, "show ip pim secondary", "Show running system information\n" "IP information\n" "PIM information\n" "PIM neighbor addresses\n") DEFSH (0, show_bgp_neighbors_cmd_vtysh, "show bgp neighbors", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, no_spf_interval_l2_cmd_vtysh, "no spf-interval level-2", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n") DEFSH (0, interface_no_ip_igmp_query_max_response_time_dsec_cmd_vtysh, "no" " " "ip igmp query-max-response-time-dsec", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (deciseconds)\n") DEFSH (0, debug_zebra_rib_cmd_vtysh, "debug zebra rib", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug RIB events\n") DEFSH (0, no_neighbor_description_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "description", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Neighbor specific description\n") DEFSH (0, show_ip_bgp_neighbor_received_routes_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, show_bgp_neighbor_advertised_route_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, no_bgp_bestpath_med3_cmd_vtysh, "no bgp bestpath med missing-as-worst confed", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") DEFSH (0, no_ip_rip_authentication_key_chain_cmd_vtysh, "no ip rip authentication key-chain", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n") DEFSH (0, no_ipv6_nd_router_preference_val_cmd_vtysh, "no ipv6 nd router-preference (high|medium|low)", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFSH (0, no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh, "no ipv6 ospf6 advertise prefix-list", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Advertising options\n" "Filter prefix using prefix-list\n" ) DEFSH (0|0|0|0, ipv6_prefix_list_seq_ge_cmd_vtysh, "ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_neighbor_override_capability_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Override capability negotiation result\n") DEFSH (0, show_ipv6_ospf6_database_type_id_router_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, no_access_list_remark_cmd_vtysh, "no access-list (<1-99>|<100-199>|<1300-1999>|<2000-2699>|WORD) remark", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP extended access list\n" "IP standard access list (expanded range)\n" "IP extended access list (expanded range)\n" "IP zebra access-list\n" "Access list entry comment\n") DEFSH (0, show_bgp_instance_ipv6_summary_cmd_vtysh, "show bgp view WORD ipv6 summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Summary of BGP neighbor status\n") DEFSH (0, ripng_redistribute_ripng_cmd_vtysh, "redistribute ripng", "Redistribute information from another routing protocol\n" "RIPng route\n") DEFSH (0, show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh, "show bgp ipv6 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, ipv6_access_list_cmd_vtysh, "ipv6 access-list WORD (deny|permit) X:X::X:X/M", "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Prefix to match. e.g. 3ffe:506::/32\n") DEFSH (0, show_bgp_prefix_list_cmd_vtysh, "show bgp prefix-list WORD", "Show running system information\n" "BGP information\n" "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") DEFSH (0, show_ip_bgp_community4_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_key_string_cmd_vtysh, "no key-string [LINE]", "Negate a command or set its defaults\n" "Unset key string\n" "The key\n") DEFSH (0|0|0|0, no_ip_prefix_list_le_cmd_vtysh, "no ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_csnp_interval_l1_arg_cmd_vtysh, "no isis csnp-interval <1-600> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, clear_bgp_peer_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X)", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n") DEFSH (0, clear_ip_bgp_peer_soft_out_cmd_vtysh, "clear ip bgp A.B.C.D soft out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0|0|0|0|0|0, rmap_continue_cmd_vtysh, "continue", "Continue on a different entry within the route-map\n") DEFSH (0, show_bgp_ipv6_prefix_list_cmd_vtysh, "show bgp ipv6 prefix-list WORD", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") DEFSH (0, clear_ip_bgp_peer_soft_cmd_vtysh, "clear ip bgp A.B.C.D soft", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig\n") DEFSH (0, show_ipv6_bgp_prefix_cmd_vtysh, "show ipv6 bgp X:X::X:X/M", "Show running system information\n" "IP information\n" "BGP information\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, debug_bgp_zebra_cmd_vtysh, "debug bgp zebra", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, show_bgp_view_rsclient_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, show_ipv6_ospf6_database_self_originated_detail_cmd_vtysh, "show ipv6 ospf6 database self-originated " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Self-originated LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_ospf6_log_adjacency_changes_detail_cmd_vtysh, "no log-adjacency-changes detail", "Negate a command or set its defaults\n" "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, ipv6_nd_reachable_time_cmd_vtysh, "ipv6 nd reachable-time <1-3600000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFSH (0, clear_isis_neighbor_arg_cmd_vtysh, "clear isis neighbor WORD", "Reset functions\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") DEFSH (0, neighbor_attr_unchanged5_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path next-hop med", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, set_aspath_prepend_cmd_vtysh, "set as-path prepend ." "<1-4294967295>", "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFSH (0, match_ip_route_source_cmd_vtysh, "match ip route-source (<1-199>|<1300-2699>|WORD)", "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP standard access-list name\n") DEFSH (0, no_isis_metric_l2_cmd_vtysh, "no isis metric level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-2 routing\n") DEFSH (0, debug_ospf6_neighbor_detail_cmd_vtysh, "debug ospf6 neighbor (state|event)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) DEFSH (0, no_debug_ospf_packet_all_cmd_vtysh, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n") DEFSH (0, no_set_aspath_exclude_cmd_vtysh, "no set as-path exclude", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n") DEFSH (0, undebug_bgp_all_cmd_vtysh, "undebug all bgp", "Disable debugging functions (see also 'debug')\n" "Enable all debugging\n" "BGP information\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, show_ip_bgp_community_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_router_babel_cmd_vtysh, "no router babel", "Negate a command or set its defaults\n" "Disable a routing process\n" "Remove Babel instance command\n" "No attributes\n") DEFSH (0, domain_passwd_clear_snpauth_cmd_vtysh, "domain-password clear WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n") DEFSH (0, no_ip_router_isis_cmd_vtysh, "no ip router isis WORD", "Negate a command or set its defaults\n" "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") DEFSH (0, no_bgp_maxpaths_ibgp_arg_cmd_vtysh, "no maximum-paths ibgp <1-255>", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address family modifier\n" "Address family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the advertised routes to neighbor\n" "Display the received routes from neighbor\n") DEFSH (0, vty_login_cmd_vtysh, "login", "Enable password checking\n") DEFSH (0, no_set_aspath_prepend_cmd_vtysh, "no set as-path prepend", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n") DEFSH (0, set_overload_bit_cmd_vtysh, "set-overload-bit", "Set overload bit to avoid any transit traffic\n" "Set overload bit\n") DEFSH (0, no_neighbor_attr_unchanged8_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") DEFSH (0, no_bgp_redistribute_ipv4_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, no_spf_interval_l1_arg_cmd_vtysh, "no spf-interval level-1 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, ipv6_nd_prefix_val_noauto_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration") DEFSH (0, clear_ip_bgp_instance_peer_rsclient_cmd_vtysh, "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, isis_hello_interval_l2_cmd_vtysh, "isis hello-interval <1-600> level-2", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, neighbor_prefix_list_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "prefix-list WORD (in|out)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Filter updates to/from this neighbor\n" "Name of a prefix list\n" "Filter incoming updates\n" "Filter outgoing updates\n") DEFSH (0, isis_hello_interval_l1_cmd_vtysh, "isis hello-interval <1-600> level-1", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, ospf6_stub_router_admin_cmd_vtysh, "stub-router administrative", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Administratively applied, for an indefinite period\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_seq_ge_le_cmd_vtysh, "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, bgp_maxpaths_ibgp_cmd_vtysh, "maximum-paths ibgp <1-255>", "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, no_isis_priority_l1_cmd_vtysh, "no isis priority level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-1 routing\n") DEFSH (0, no_ip_rip_authentication_string2_cmd_vtysh, "no ip rip authentication string LINE", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n" "Authentication string\n") DEFSH (0, no_rip_default_information_originate_cmd_vtysh, "no default-information originate", "Negate a command or set its defaults\n" "Control distribution of default route\n" "Distribute a default route\n") DEFSH (0, show_ip_bgp_vpnv4_all_cmd_vtysh, "show ip bgp vpnv4 all", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n") DEFSH (0, clear_ip_bgp_all_soft_cmd_vtysh, "clear ip bgp * soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n") DEFSH (0, no_ospf_transmit_delay_cmd_vtysh, "no ospf transmit-delay", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Link state transmit delay\n") DEFSH (0, no_ospf_area_export_list_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) export-list NAME", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") DEFSH (0, neighbor_maximum_prefix_restart_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> restart <1-65535>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") DEFSH (0, ip_irdp_holdtime_cmd_vtysh, "ip irdp holdtime <0-9000>", "IP information\n" "ICMP Router discovery on this interface\n" "Set holdtime value\n" "Holdtime value in seconds. Default is 1800 seconds\n") DEFSH (0, ipv6_nd_prefix_val_nortaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, clear_bgp_as_in_prefix_filter_cmd_vtysh, "clear bgp " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_service_advanced_vty_cmd_vtysh, "no service advanced-vty", "Negate a command or set its defaults\n" "Set up miscellaneous service\n" "Enable advanced mode vty interface\n") DEFSH (0, clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh, "clear ip bgp view WORD * in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, show_bgp_regexp_cmd_vtysh, "show bgp regexp .LINE", "Show running system information\n" "BGP information\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, show_bgp_view_ipv6_neighbor_flap_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") DEFSH (0|0|0|0, no_ip_prefix_list_seq_ge_cmd_vtysh, "no ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_ipv6_route_flags_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ip_bgp_instance_neighbors_peer_cmd_vtysh, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, no_ipv6_ospf6_network_cmd_vtysh, "no ipv6 ospf6 network", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Network Type\n" "Default to whatever interface type system specifies" ) DEFSH (0, show_ip_ospf_neighbor_all_cmd_vtysh, "show ip ospf neighbor all", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "include down status neighbor\n") DEFSH (0, babel_redistribute_type_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|pim)", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (OSPFv2)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_le_ge_cmd_vtysh, "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, ipv6_route_ifname_pref_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Distance value for this prefix\n") DEFSH (0, no_max_lsp_lifetime_arg_cmd_vtysh, "no max-lsp-lifetime <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFSH (0|0|0|0|0|0, no_rmap_onmatch_goto_cmd_vtysh, "no on-match goto", "Negate a command or set its defaults\n" "Exit policy on matches\n" "Goto Clause number\n") DEFSH (0, no_match_community_cmd_vtysh, "no match community", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match BGP community list\n") DEFSH (0, clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh, "clear ip bgp A.B.C.D vpnv4 unicast soft", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, no_debug_isis_rtevents_cmd_vtysh, "no debug isis route-events", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Route related events\n") DEFSH (0, ipv6_nd_prefix_val_rev_rtaddr_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n" "Set Router Address flag\n") DEFSH (0, redistribute_ospf6_cmd_vtysh, "redistribute ospf6", "Redistribute control\n" "OSPF6 route\n") DEFSH (0, match_probability_cmd_vtysh, "match probability <0-100>", "Match values from routing table\n" "Match portion of routes defined by percentage value\n" "Percentage of routes\n") DEFSH (0, no_set_ipv6_nexthop_peer_cmd_vtysh, "no set ipv6 next-hop peer-address", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" ) DEFSH (0, no_bgp_bestpath_med2_cmd_vtysh, "no bgp bestpath med confed missing-as-worst", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") DEFSH (0, ospf_area_vlink_param3_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, accept_lifetime_month_day_month_day_cmd_vtysh, "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", "Set accept lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Time to expire\n" "Month of the year to expire\n" "Day of th month to expire\n" "Year to expire\n") DEFSH (0, access_list_extended_mask_host_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "A single destination host\n" "Destination address\n") DEFSH (0, clear_bgp_instance_peer_rsclient_cmd_vtysh, "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0|0|0|0, ipv6_prefix_list_description_cmd_vtysh, "ipv6 prefix-list WORD description .LINE", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n" "Up to 80 characters describing this prefix-list\n") DEFSH (0, no_dynamic_hostname_cmd_vtysh, "no hostname dynamic", "Negate a command or set its defaults\n" "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") DEFSH (0, show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_ip_extcommunity_list_standard_all_cmd_vtysh, "no ip extcommunity-list <1-99>", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Extended Community list number (standard)\n") DEFSH (0, no_ip_route_mask_flags_cmd_vtysh, "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, no_neighbor_attr_unchanged2_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, show_ip_ospf_border_routers_cmd_vtysh, "show ip ospf border-routers", "Show running system information\n" "IP information\n" "show all the ABR's and ASBR's\n" "for this area\n") DEFSH (0, interface_no_ip_igmp_join_cmd_vtysh, "no ip igmp join A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "IP information\n" "Enable IGMP operation\n" "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") DEFSH (0, no_isis_metric_l1_arg_cmd_vtysh, "no isis metric <0-16777215> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFSH (0, bgp_redistribute_ipv4_rmap_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, bgp_redistribute_ipv4_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, show_bgp_ipv6_prefix_longer_cmd_vtysh, "show bgp ipv6 X:X::X:X/M longer-prefixes", "Show running system information\n" "BGP information\n" "Address family\n" "IPv6 prefix /\n" "Display route and more specific routes\n") DEFSH (0, bgp_damp_unset_cmd_vtysh, "no bgp dampening", "Negate a command or set its defaults\n" "BGP Specific commands\n" "Enable route-flap dampening\n") DEFSH (0, no_aggregate_address_summary_only_cmd_vtysh, "no aggregate-address A.B.C.D/M summary-only", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, no_debug_rip_packet_direct_cmd_vtysh, "no debug rip packet (recv|send)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP packet\n" "RIP option set for receive packet\n" "RIP option set for send packet\n") DEFSH (0, no_debug_ospf_packet_send_recv_detail_cmd_vtysh, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", "Negate a command or set its defaults\n" "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") DEFSH (0, rip_default_information_originate_cmd_vtysh, "default-information originate", "Control distribution of default route\n" "Distribute a default route\n") DEFSH (0, bgp_timers_cmd_vtysh, "timers bgp <0-65535> <0-65535>", "Adjust routing timers\n" "BGP timers\n" "Keepalive interval\n" "Holdtime\n") DEFSH (0|0|0|0, ip_prefix_list_description_cmd_vtysh, "ip prefix-list WORD description .LINE", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n" "Up to 80 characters describing this prefix-list\n") DEFSH (0, no_max_lsp_lifetime_cmd_vtysh, "no max-lsp-lifetime", "Negate a command or set its defaults\n" "LSP lifetime in seconds\n") DEFSH (0, undebug_bgp_fsm_cmd_vtysh, "undebug bgp fsm", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "Finite State Machine\n") DEFSH (0, interface_ip_igmp_query_max_response_time_dsec_cmd_vtysh, "ip igmp query-max-response-time-dsec" " <10-250>", "IP information\n" "Enable IGMP operation\n" "IGMP max query response value (deciseconds)\n" "Query response value in deciseconds\n") DEFSH (0, no_bgp_confederation_identifier_arg_cmd_vtysh, "no bgp confederation identifier " "<1-4294967295>", "Negate a command or set its defaults\n" "BGP specific commands\n" "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") DEFSH (0, show_bgp_rsclient_summary_cmd_vtysh, "show bgp rsclient summary", "Show running system information\n" "BGP information\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, no_neighbor_port_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "port", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Neighbor's BGP port\n") DEFSH (0, no_neighbor_soft_reconfiguration_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "soft-reconfiguration inbound", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") DEFSH (0, ip_community_list_standard_cmd_vtysh, "ip community-list <1-99> (deny|permit) .AA:NN", "IP information\n" "Add a community list entry\n" "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n") DEFSH (0, ospf_log_adjacency_changes_detail_cmd_vtysh, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0, mpls_te_cmd_vtysh, "mpls-te", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") DEFSH (0, no_debug_ospf6_message_sendrecv_cmd_vtysh, "no debug ospf6 message " "(unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) DEFSH (0, neighbor_route_reflector_client_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure a neighbor as Route Reflector client\n") DEFSH (0|0, no_set_ip_nexthop_cmd_vtysh, "no set ip next-hop", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IP information\n" "Next hop address\n") DEFSH (0, no_neighbor_ttl_security_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ttl-security hops <1-254>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify the maximum number of hops to the BGP peer\n") DEFSH (0, show_ipv6_ospf6_interface_prefix_match_cmd_vtysh, "show ipv6 ospf6 interface prefix X:X::X:X/M (match|detail)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Display connected prefixes to advertise\n" "Display the route\n" "Display the route matches the prefix\n" "Display details of the prefixes\n" ) DEFSH (0, ipv6_route_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n") DEFSH (0, clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, show_ip_ospf_route_cmd_vtysh, "show ip ospf route", "Show running system information\n" "IP information\n" "OSPF information\n" "OSPF routing table\n") DEFSH (0, clear_ip_bgp_as_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_ipv4_community2_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_ospf_max_metric_router_lsa_admin_cmd_vtysh, "no max-metric router-lsa administrative", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") DEFSH (0, clear_ip_bgp_dampening_prefix_cmd_vtysh, "clear ip bgp dampening A.B.C.D/M", "Reset functions\n" "IP information\n" "BGP information\n" "Clear route flap dampening information\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, bgp_default_local_preference_cmd_vtysh, "bgp default local-preference <0-4294967295>", "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") DEFSH (0, clear_ip_igmp_interfaces_cmd_vtysh, "clear ip igmp interfaces", "Reset functions\n" "IP information\n" "IGMP clear commands\n" "Reset IGMP interfaces\n") DEFSH (0, no_linkdetect_cmd_vtysh, "no link-detect", "Negate a command or set its defaults\n" "Disable link detection on interface\n") DEFSH (0, clear_bgp_peer_group_in_prefix_filter_cmd_vtysh, "clear bgp peer-group WORD in prefix-filter", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0, no_neighbor_route_reflector_client_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "route-reflector-client", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure a neighbor as Route Reflector client\n") DEFSH (0, no_aggregate_address_summary_as_set_cmd_vtysh, "no aggregate-address A.B.C.D/M summary-only as-set", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFSH (0, no_isis_hello_interval_l1_arg_cmd_vtysh, "no isis hello-interval <1-600> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFSH (0, no_bgp_confederation_identifier_cmd_vtysh, "no bgp confederation identifier", "Negate a command or set its defaults\n" "BGP specific commands\n" "AS confederation parameters\n" "AS number\n") DEFSH (0, no_ip_community_list_expanded_all_cmd_vtysh, "no ip community-list <100-500>", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Community list number (expanded)\n") DEFSH (0, debug_ripng_packet_direct_cmd_vtysh, "debug ripng packet (recv|send)", "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") DEFSH (0, set_community_none_cmd_vtysh, "set community none", "Set values in destination routing protocol\n" "BGP community attribute\n" "No community attribute\n") DEFSH (0, no_ipv6_aggregate_address_summary_only_cmd_vtysh, "no aggregate-address X:X::X:X/M summary-only", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") DEFSH (0, no_aggregate_address_as_set_summary_cmd_vtysh, "no aggregate-address A.B.C.D/M as-set summary-only", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") DEFSH (0, no_ip_irdp_shutdown_cmd_vtysh, "no ip irdp shutdown", "Negate a command or set its defaults\n" "IP information\n" "ICMP Router discovery no shutdown on this interface\n") DEFSH (0, no_set_originator_id_cmd_vtysh, "no set originator-id", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP originator ID attribute\n") DEFSH (0, show_ipv6_mbgp_community2_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, ipv6_nd_adv_interval_config_option_cmd_vtysh, "ipv6 nd adv-interval-option", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") DEFSH (0, no_spf_interval_cmd_vtysh, "no spf-interval", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n") DEFSH (0, clear_isis_neighbor_cmd_vtysh, "clear isis neighbor", "Reset functions\n" "Reset ISIS network information\n" "Reset ISIS neighbor adjacencies\n") DEFSH (0, no_neighbor_password_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "password", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set a password\n") DEFSH (0, ip_irdp_broadcast_cmd_vtysh, "ip irdp broadcast", "IP information\n" "ICMP Router discovery on this interface using broadcast\n") DEFSH (0, debug_ospf_packet_all_cmd_vtysh, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n") DEFSH (0, debug_ospf_packet_send_recv_detail_cmd_vtysh, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") DEFSH (0, access_list_extended_any_host_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip any host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "A single destination host\n" "Destination address\n") DEFSH (0, show_bgp_statistics_vpnv4_cmd_vtysh, "show bgp (ipv4) (vpnv4) statistics", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, clear_ip_bgp_as_ipv4_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") DEFSH (0, isis_hello_multiplier_l1_cmd_vtysh, "isis hello-multiplier <2-100> level-1", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, set_ecommunity_rt_cmd_vtysh, "set extcommunity rt .ASN:nn_or_IP-address:nn", "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Route Target extended community\n" "VPN extended community\n") DEFSH (0, show_bgp_ipv6_community_list_exact_cmd_vtysh, "show bgp ipv6 community-list (<1-500>|WORD) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, no_neighbor_timers_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "timers", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP per neighbor timers\n") DEFSH (0, no_debug_isis_csum_cmd_vtysh, "no debug isis checksum-errors", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS LSP checksum errors\n") DEFSH (0, mpls_te_link_metric_cmd_vtysh, "mpls-te link metric <0-4294967295>", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Link metric for MPLS-TE purpose\n" "Metric\n") DEFSH (0, aggregate_address_as_set_summary_cmd_vtysh, "aggregate-address A.B.C.D/M as-set summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_prefix_counts_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") DEFSH (0, ip_ospf_authentication_key_cmd_vtysh, "ip ospf authentication-key AUTH_KEY", "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, no_rip_redistribute_type_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " metric <0-16>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n") DEFSH (0, ip_protocol_cmd_vtysh, "ip protocol PROTO route-map ROUTE-MAP", "Negate a command or set its defaults\n" "Apply route map to PROTO\n" "Protocol name\n" "Route map name\n") DEFSH (0, no_debug_igmp_events_cmd_vtysh, "no debug igmp events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0, ip_multicast_mode_cmd_vtysh, "ip multicast rpf-lookup-mode (urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix)", "IP information\n" "Multicast options\n" "RPF lookup behavior\n" "Lookup in unicast RIB only\n" "Lookup in multicast RIB only\n" "Try multicast RIB first, fall back to unicast RIB\n" "Lookup both, use entry with lower distance\n" "Lookup both, use entry with longer prefix\n") DEFSH (0, neighbor_override_capability_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "override-capability", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Override capability negotiation result\n") DEFSH (0, show_bgp_community3_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, show_ip_bgp_vpnv4_all_route_cmd_vtysh, "show ip bgp vpnv4 all A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Network in the BGP routing table to display\n") DEFSH (0, ipv6_nd_prefix_noval_noauto_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n") DEFSH (0, access_list_extended_host_any_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "Any destination host\n") DEFSH (0, ip_community_list_name_standard2_cmd_vtysh, "ip community-list standard WORD (deny|permit)", "IP information\n" "Add a community list entry\n" "Add a standard community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n") DEFSH (0, no_debug_ospf6_asbr_cmd_vtysh, "no debug ospf6 asbr", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 ASBR function\n" ) DEFSH (0, rip_offset_list_ifname_cmd_vtysh, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, show_ip_bgp_attr_info_cmd_vtysh, "show ip bgp attribute-info", "Show running system information\n" "IP information\n" "BGP information\n" "List all bgp attribute information\n") DEFSH (0, show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "adv-router A.B.C.D linkstate-id A.B.C.D " "(dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_debug_isis_err_cmd_vtysh, "no debug isis protocol-errors", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS LSP protocol errors\n") DEFSH (0, show_bgp_ipv6_community_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, ospf_network_cmd_vtysh, "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") DEFSH (0, debug_mroute_cmd_vtysh, "debug mroute", "Debugging functions (see also 'undebug')\n" "PIM interaction with kernel MFC cache\n") DEFSH (0, debug_ospf_packet_send_recv_cmd_vtysh, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail information\n") DEFSH (0, no_neighbor_filter_list_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "filter-list WORD (in|out)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Establish BGP filters\n" "AS path access-list name\n" "Filter incoming routes\n" "Filter outgoing routes\n") DEFSH (0, isis_metric_cmd_vtysh, "isis metric <0-16777215>", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFSH (0, old_no_ipv6_aggregate_address_cmd_vtysh, "no ipv6 bgp aggregate-address X:X::X:X/M", "Negate a command or set its defaults\n" "IPv6 information\n" "BGP information\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, show_bgp_neighbor_damp_cmd_vtysh, "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFSH (0, no_aggregate_address_cmd_vtysh, "no aggregate-address A.B.C.D/M", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, clear_bgp_external_in_cmd_vtysh, "clear bgp external in", "Reset functions\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig inbound update\n") DEFSH (0, show_zebra_cmd_vtysh, "show zebra", "Show running system information\n" "Zebra information\n") DEFSH (0, dump_bgp_updates_interval_cmd_vtysh, "dump bgp updates PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n" "Interval of output\n") DEFSH (0, show_ip_ospf_neighbor_detail_cmd_vtysh, "show ip ospf neighbor detail", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "detail of all neighbors\n") DEFSH (0, ipv6_ospf6_mtu_ignore_cmd_vtysh, "ipv6 ospf6 mtu-ignore", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Ignore MTU mismatch on this interface\n" ) DEFSH (0, clear_bgp_peer_group_in_cmd_vtysh, "clear bgp peer-group WORD in", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFSH (0, no_neighbor_port_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "port <0-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Neighbor's BGP port\n" "TCP port number\n") DEFSH (0, neighbor_attr_unchanged_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n") DEFSH (0, show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0, ip_route_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") DEFSH (0, ospf6_log_adjacency_changes_detail_cmd_vtysh, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") DEFSH (0|0|0|0, ip_prefix_list_cmd_vtysh, "ip prefix-list WORD (deny|permit) (A.B.C.D/M|any)", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") DEFSH (0, no_ip_extcommunity_list_name_expanded_cmd_vtysh, "no ip extcommunity-list expanded WORD (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Specify expanded extcommunity-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, show_ip_ospf_database_type_id_self_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") A.B.C.D (self-originate|)", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n" "Self-originated link states\n" "\n") DEFSH (0, show_ip_bgp_ipv4_community4_exact_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, clear_ip_bgp_all_soft_out_cmd_vtysh, "clear ip bgp * soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, clear_bgp_ipv6_peer_in_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") DEFSH (0, ospf_distance_ospf_cmd_vtysh, "distance ospf " "{intra-area <1-255>|inter-area <1-255>|external <1-255>}", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") DEFSH (0, spf_interval_l2_cmd_vtysh, "spf-interval level-2 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, no_debug_ospf6_brouter_cmd_vtysh, "no debug ospf6 border-routers", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" ) DEFSH (0, clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh, "clear ip bgp A.B.C.D vpnv4 unicast soft in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_neighbor_local_as_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as " "<1-4294967295>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n" "AS number used as local AS\n") DEFSH (0, ospf_refresh_timer_cmd_vtysh, "refresh timer <10-1800>", "Adjust refresh parameters\n" "Set refresh timer\n" "Timer value in seconds\n") DEFSH (0, no_access_list_standard_host_cmd_vtysh, "no access-list (<1-99>|<1300-1999>) (deny|permit) host A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "A single host address\n" "Address to match\n") DEFSH (0, no_vpnv4_network_cmd_vtysh, "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") DEFSH (0, show_ip_bgp_community_all_cmd_vtysh, "show ip bgp community", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n") DEFSH (0, undebug_igmp_events_cmd_vtysh, "undebug igmp events", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP protocol events\n") DEFSH (0|0, set_metric_addsub_cmd_vtysh, "set metric <+/-metric>", "Set values in destination routing protocol\n" "Metric value for destination routing protocol\n" "Add or subtract metric\n") DEFSH (0, show_ipv6_mbgp_prefix_cmd_vtysh, "show ipv6 mbgp X:X::X:X/M", "Show running system information\n" "IP information\n" "MBGP information\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, no_bgp_fast_external_failover_cmd_vtysh, "no bgp fast-external-failover", "Negate a command or set its defaults\n" "BGP information\n" "Immediately reset session if a link to a directly connected external peer goes down\n") DEFSH (0, ospf_area_vlink_md5_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(message-digest-key|) <1-255> md5 KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, no_bgp_confederation_peers_cmd_vtysh, "no bgp confederation peers ." "<1-4294967295>", "Negate a command or set its defaults\n" "BGP specific commands\n" "AS confederation parameters\n" "Peer ASs in BGP confederation\n" "AS number\n") DEFSH (0, csnp_interval_l2_cmd_vtysh, "isis csnp-interval <1-600> level-2", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, ip_ospf_hello_interval_addr_cmd_vtysh, "ip ospf hello-interval <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n" "Address of interface") DEFSH (0, access_list_extended_host_mask_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, area_range_advertise_cmd_vtysh, "area A.B.C.D range X:X::X:X/M (advertise|not-advertise)", "OSPF area parameters\n" "Area ID (as an IPv4 notation)\n" "Configured address range\n" "Specify IPv6 prefix\n" ) DEFSH (0, show_ipv6_ospf6_neighbor_cmd_vtysh, "show ipv6 ospf6 neighbor", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Neighbor list\n" ) DEFSH (0, show_ip_bgp_view_rsclient_cmd_vtysh, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, show_ip_igmp_querier_cmd_vtysh, "show ip igmp querier", "Show running system information\n" "IP information\n" "IGMP information\n" "IGMP querier information\n") DEFSH (0, ipv6_bgp_neighbor_routes_cmd_vtysh, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, ip_community_list_expanded_cmd_vtysh, "ip community-list <100-500> (deny|permit) .LINE", "IP information\n" "Add a community list entry\n" "Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, ospf_area_stub_no_summary_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) stub no-summary", "OSPF stub parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n" "Do not inject inter-area routes into stub\n") DEFSH (0, show_bgp_instance_summary_cmd_vtysh, "show bgp view WORD summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") DEFSH (0|0|0|0, no_set_metric_cmd_vtysh, "no set metric", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Metric value for destination routing protocol\n") DEFSH (0, no_ip_multicast_mode_noarg_cmd_vtysh, "no ip multicast rpf-lookup-mode", "Negate a command or set its defaults\n" "IP information\n" "Multicast options\n" "RPF lookup behavior\n") DEFSH (0, show_ipv6_ospf6_border_routers_cmd_vtysh, "show ipv6 ospf6 border-routers", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display routing table for ABR and ASBR\n" ) DEFSH (0, no_debug_ospf_nsm_cmd_vtysh, "no debug ospf nsm", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Neighbor State Machine") DEFSH (0, show_ipv6_mbgp_prefix_longer_cmd_vtysh, "show ipv6 mbgp X:X::X:X/M longer-prefixes", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") DEFSH (0, ospf_authentication_key_cmd_vtysh, "ospf authentication-key AUTH_KEY", "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, bgp_bestpath_aspath_confed_cmd_vtysh, "bgp bestpath as-path confed", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") DEFSH (0, no_max_lsp_lifetime_l1_arg_cmd_vtysh, "no max-lsp-lifetime level-1 <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFSH (0, no_ip_as_path_cmd_vtysh, "no ip as-path access-list WORD (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, bgp_bestpath_med2_cmd_vtysh, "bgp bestpath med confed missing-as-worst", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") DEFSH (0, ipv6_nd_homeagent_preference_cmd_vtysh, "ipv6 nd home-agent-preference <0-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFSH (0, clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, clear_bgp_ipv6_as_in_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFSH (0, set_atomic_aggregate_cmd_vtysh, "set atomic-aggregate", "Set values in destination routing protocol\n" "BGP atomic aggregate attribute\n" ) DEFSH (0, show_bgp_ipv6_safi_cmd_vtysh, "show bgp ipv6 (unicast|multicast)", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, ipv6_route_ifname_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n") DEFSH (0, clear_bgp_peer_group_soft_in_cmd_vtysh, "clear bgp peer-group WORD soft in", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, no_debug_pim_packetdump_send_cmd_vtysh, "no debug pim packet-dump send", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM packet dump\n" "Dump sent packets\n") DEFSH (0, no_ipv6_nd_other_config_flag_cmd_vtysh, "no ipv6 nd other-config-flag", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, rip_version_cmd_vtysh, "version <1-2>", "Set routing protocol version\n" "version\n") DEFSH (0, no_ip_route_flags_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, show_ipv6_route_addr_cmd_vtysh, "show ipv6 route X:X::X:X", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "IPv6 Address\n") DEFSH (0, no_ospf_area_range_cost_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFSH (0, no_ospf_authentication_key_cmd_vtysh, "no ospf authentication-key", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Authentication password (key)\n") DEFSH (0, show_ipv6_forwarding_cmd_vtysh, "show ipv6 forwarding", "Show running system information\n" "IPv6 information\n" "Forwarding status\n") DEFSH (0|0, ospf6_routemap_match_address_prefixlist_cmd_vtysh, "match ipv6 address prefix-list WORD", "Match values\n" "IPv6 information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") DEFSH (0, clear_ip_bgp_as_soft_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n") DEFSH (0|0, no_set_ipv6_nexthop_local_val_cmd_vtysh, "no set ipv6 next-hop local X:X::X:X", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") DEFSH (0, show_ipv6_bgp_community_all_cmd_vtysh, "show ipv6 bgp community", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the communities\n") DEFSH (0, no_ospf_max_metric_router_lsa_shutdown_cmd_vtysh, "no max-metric router-lsa on-shutdown", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n") DEFSH (0, no_neighbor_send_community_type_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") DEFSH (0, show_ip_bgp_ipv4_prefix_longer_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFSH (0, show_ip_pim_rpf_cmd_vtysh, "show ip pim rpf", "Show running system information\n" "IP information\n" "PIM information\n" "PIM cached source rpf information\n") DEFSH (0, show_ipv6_ospf6_route_match_detail_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M match detail", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Specify IPv6 prefix\n" "Display routes which match the specified route\n" "Detailed information\n" ) DEFSH (0, no_neighbor_strict_capability_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Strict capability negotiation match\n") DEFSH (0, debug_zebra_rib_q_cmd_vtysh, "debug zebra rib queue", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug RIB events\n" "Debug RIB queueing\n") DEFSH (0, no_debug_ospf_zebra_cmd_vtysh, "no debug ospf zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Zebra information\n") DEFSH (0, ospf_neighbor_cmd_vtysh, "neighbor A.B.C.D", "Specify neighbor router\n" "Neighbor IP address\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_description_arg_cmd_vtysh, "no ipv6 prefix-list WORD description .LINE", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n" "Up to 80 characters describing this prefix-list\n") DEFSH (0, debug_isis_spfstats_cmd_vtysh, "debug isis spf-statistics ", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") DEFSH (0, ip_irdp_preference_cmd_vtysh, "ip irdp preference <0-2147483647>", "IP information\n" "ICMP Router discovery on this interface\n" "Set default preference level for this interface\n" "Preference level\n") DEFSH (0, bgp_bestpath_compare_router_id_cmd_vtysh, "bgp bestpath compare-routerid", "BGP specific commands\n" "Change the default bestpath selection\n" "Compare router-id for identical EBGP paths\n") DEFSH (0, ip_ospf_priority_cmd_vtysh, "ip ospf priority <0-255>", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n") DEFSH (0, debug_rip_zebra_cmd_vtysh, "debug rip zebra", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP and ZEBRA communication\n") DEFSH (0, interface_ip_igmp_cmd_vtysh, "ip igmp", "IP information\n" "Enable IGMP operation\n") DEFSH (0, show_ip_bgp_flap_route_map_cmd_vtysh, "show ip bgp flap-statistics route-map WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0|0|0|0, show_ip_prefix_list_cmd_vtysh, "show ip prefix-list", "Show running system information\n" "IP information\n" "Build a prefix list\n") DEFSH (0, no_ip_route_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") DEFSH (0, set_originator_id_cmd_vtysh, "set originator-id A.B.C.D", "Set values in destination routing protocol\n" "BGP originator ID attribute\n" "IP address of originator\n") DEFSH (0, debug_rip_events_cmd_vtysh, "debug rip events", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP events\n") DEFSH (0, no_ospf_area_vlink_param4_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, no_set_local_pref_cmd_vtysh, "no set local-preference", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP local preference path attribute\n") DEFSH (0, clear_bgp_ipv6_external_out_cmd_vtysh, "clear bgp ipv6 external WORD out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig outbound update\n") DEFSH (0, debug_ospf_ism_cmd_vtysh, "debug ospf ism", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Interface State Machine\n") DEFSH (0, no_bgp_enforce_first_as_cmd_vtysh, "no bgp enforce-first-as", "Negate a command or set its defaults\n" "BGP information\n" "Enforce the first AS for EBGP routes\n") DEFSH (0|0|0|0, ip_prefix_list_ge_cmd_vtysh, "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFSH (0, no_match_peer_local_cmd_vtysh, "no match peer local", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n" "Static or Redistributed routes\n") DEFSH (0, match_ipv6_address_cmd_vtysh, "match ipv6 address WORD", "Match values from routing table\n" "IPv6 information\n" "Match IPv6 address of route\n" "IPv6 access-list name\n") DEFSH (0, clear_bgp_ipv6_as_soft_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n") DEFSH (0, no_bgp_bestpath_compare_router_id_cmd_vtysh, "no bgp bestpath compare-routerid", "Negate a command or set its defaults\n" "BGP specific commands\n" "Change the default bestpath selection\n" "Compare router-id for identical EBGP paths\n") DEFSH (0, show_ip_bgp_neighbor_damp_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFSH (0, bgp_graceful_restart_stalepath_time_cmd_vtysh, "bgp graceful-restart stalepath-time <1-3600>", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") DEFSH (0, ospf_area_vlink_authtype_args_authkey_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null) " "(authentication-key|) AUTH_KEY", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Use null authentication\n" "Use message-digest authentication\n" "Authentication password (key)\n" "The OSPF password (key)") DEFSH (0, no_debug_igmp_packets_cmd_vtysh, "no debug igmp packets", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP protocol packets\n") DEFSH (0, no_match_ipv6_next_hop_cmd_vtysh, "no match ipv6 next-hop X:X::X:X", "Negate a command or set its defaults\n" "Match values from routing table\n" "IPv6 information\n" "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") DEFSH (0, aggregate_address_mask_as_set_summary_cmd_vtysh, "aggregate-address A.B.C.D A.B.C.D as-set summary-only", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") DEFSH (0, ipv6_route_ifname_flags_pref_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0|0|0|0, ip_prefix_list_seq_ge_cmd_vtysh, "ip prefix-list WORD seq <1-4294967295> (deny|permit) A.B.C.D/M ge <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_ip_ospf_priority_cmd_vtysh, "no ip ospf priority", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Router priority\n") DEFSH (0, no_ip_ssmpingd_cmd_vtysh, "no ip ssmpingd [A.B.C.D]", "Negate a command or set its defaults\n" "IP information\n" "Enable ssmpingd operation\n" "Source address\n") DEFSH (0, no_ripng_default_metric_val_cmd_vtysh, "no default-metric <1-16>", "Negate a command or set its defaults\n" "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, no_psnp_interval_l2_cmd_vtysh, "no isis psnp-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, ipv6_route_ifname_flags_cmd_vtysh, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0, ripng_redistribute_type_routemap_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf6|isis|bgp|babel)" " route-map WORD", "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_bgp_ipv6_community2_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, show_ip_bgp_view_rsclient_route_cmd_vtysh, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, ip_ospf_authentication_addr_cmd_vtysh, "ip ospf authentication A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Address of interface") DEFSH (0, show_ip_pim_upstream_cmd_vtysh, "show ip pim upstream", "Show running system information\n" "IP information\n" "PIM information\n" "PIM upstream information\n") DEFSH (0, no_area_export_list_cmd_vtysh, "no area A.B.C.D export-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") DEFSH (0, ospf_max_metric_router_lsa_shutdown_cmd_vtysh, "max-metric router-lsa on-shutdown <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") DEFSH (0, no_log_adj_changes_cmd_vtysh, "no log-adjacency-changes", "Stop logging changes in adjacency state\n") DEFSH (0, show_ip_bgp_view_neighbor_received_routes_cmd_vtysh, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, no_debug_pim_events_cmd_vtysh, "no debug pim events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, ip_ospf_dead_interval_cmd_vtysh, "ip ospf dead-interval <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, no_bgp_maxpaths_cmd_vtysh, "no maximum-paths", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0, clear_bgp_instance_all_cmd_vtysh, "clear bgp view WORD *", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n") DEFSH (0, no_ipv6_nd_ra_interval_cmd_vtysh, "no ipv6 nd ra-interval", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") DEFSH (0, ospf_passive_interface_addr_cmd_vtysh, "passive-interface IFNAME A.B.C.D", "Suppress routing updates on an interface\n" "Interface's name\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_cmd_vtysh, "no ipv6 prefix-list WORD", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0, no_lsp_refresh_interval_arg_cmd_vtysh, "no lsp-refresh-interval <1-65235>", "Negate a command or set its defaults\n" "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFSH (0, show_ip_bgp_ipv4_community_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, debug_bgp_as4_segment_cmd_vtysh, "debug bgp as4 segment", "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, show_bgp_view_neighbor_received_routes_cmd_vtysh, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFSH (0, no_psnp_interval_arg_cmd_vtysh, "no isis psnp-interval <1-120>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFSH (0, dump_bgp_all_interval_cmd_vtysh, "dump bgp all PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n" "Interval of output\n") DEFSH (0, show_ip_bgp_rsclient_prefix_cmd_vtysh, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "IP information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, ospf6_log_adjacency_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, no_set_community_cmd_vtysh, "no set community", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP community attribute\n") DEFSH (0, no_isis_priority_cmd_vtysh, "no isis priority", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n") DEFSH (0, no_set_aggregator_as_cmd_vtysh, "no set aggregator as", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP aggregator attribute\n" "AS number of aggregator\n") DEFSH (0, no_set_aspath_prepend_val_cmd_vtysh, "no set as-path prepend ." "<1-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFSH (0, no_babel_redistribute_type_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ripng|ospf|ospf6|isis|bgp|pim)", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (OSPFv2)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n") DEFSH (0, ipv6_nd_prefix_noval_offlink_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n") DEFSH (0, show_ip_ospf_cmd_vtysh, "show ip ospf", "Show running system information\n" "IP information\n" "OSPF information\n") DEFSH (0, no_bgp_network_mask_natural_route_map_cmd_vtysh, "no network A.B.C.D route-map WORD", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, show_ipv6_ospf6_linkstate_cmd_vtysh, "show ipv6 ospf6 linkstate", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display linkstate routing table\n" ) DEFSH (0, ip_router_isis_cmd_vtysh, "ip router isis WORD", "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") DEFSH (0, clear_ip_bgp_as_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFSH (0|0|0|0, show_ip_prefix_list_summary_name_cmd_vtysh, "show ip prefix-list summary WORD", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Summary of prefix lists\n" "Name of a prefix list\n") DEFSH (0, no_ip_community_list_expanded_cmd_vtysh, "no ip community-list <100-500> (deny|permit) .LINE", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, show_ipv6_ospf6_database_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, ipv6_ospf6_hellointerval_cmd_vtysh, "ipv6 ospf6 hello-interval <1-65535>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interval time of Hello packets\n" "<1-65535> Seconds\n" ) DEFSH (0, router_id_cmd_vtysh, "router-id A.B.C.D", "Manually set the router-id\n" "IP address to use for router-id\n") DEFSH (0, show_ipv6_bgp_summary_cmd_vtysh, "show ipv6 bgp summary", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Summary of BGP neighbor status\n") DEFSH (0, show_bgp_community2_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, ospf_area_range_substitute_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") DEFSH (0, show_ip_route_prefix_longer_cmd_vtysh, "show ip route A.B.C.D/M longer-prefixes", "Show running system information\n" "IP information\n" "IP routing table\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Show route matching the specified Network/Mask pair only\n") DEFSH (0, bgp_network_mask_route_map_cmd_vtysh, "network A.B.C.D mask A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 3ffe::/16\n") DEFSH (0, no_match_peer_val_cmd_vtysh, "no match peer (A.B.C.D|X:X::X:X)", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match peer address\n" "IPv6 address of peer\n" "IP address of peer\n") DEFSH (0, ospf_abr_type_cmd_vtysh, "ospf abr-type (cisco|ibm|shortcut|standard)", "OSPF specific commands\n" "Set OSPF ABR type\n" "Alternative ABR, cisco implementation\n" "Alternative ABR, IBM implementation\n" "Shortcut ABR\n" "Standard behavior (RFC2328)\n") DEFSH (0, no_key_chain_cmd_vtysh, "no key chain WORD", "Negate a command or set its defaults\n" "Authentication key management\n" "Key-chain management\n" "Key-chain name\n") DEFSH (0, show_ip_rip_status_cmd_vtysh, "show ip rip status", "Show running system information\n" "IP information\n" "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") DEFSH (0|0|0|0, clear_ip_prefix_list_cmd_vtysh, "clear ip prefix-list", "Reset functions\n" "IP information\n" "Build a prefix list\n") DEFSH (0, no_ip_protocol_cmd_vtysh, "no ip protocol PROTO", "Negate a command or set its defaults\n" "Remove route map from PROTO\n" "Protocol name\n") DEFSH (0, clear_bgp_ipv6_peer_out_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") DEFSH (0, bgp_damp_set2_cmd_vtysh, "bgp dampening <1-45>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n") DEFSH (0, clear_bgp_ipv6_as_soft_in_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>" " soft in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_debug_ospf6_route_cmd_vtysh, "no debug ospf6 route (table|intra-area|inter-area|memory)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug route table calculation\n" "Debug intra-area route calculation\n" "Debug route memory use\n") DEFSH (0, no_set_aspath_exclude_val_cmd_vtysh, "no set as-path exclude ." "<1-4294967295>", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n" "AS number\n") DEFSH (0, no_ospf_area_nssa_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) nssa", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n") DEFSH (0, clear_ip_bgp_external_ipv4_soft_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") DEFSH (0, ipv6_mbgp_neighbor_routes_cmd_vtysh, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, set_aggregator_as_cmd_vtysh, "set aggregator as " "<1-4294967295>" " A.B.C.D", "Set values in destination routing protocol\n" "BGP aggregator attribute\n" "AS number of aggregator\n" "AS number\n" "IP address of aggregator\n") DEFSH (0, clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, access_list_extended_any_mask_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip any A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Any source host\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, undebug_ssmpingd_cmd_vtysh, "undebug ssmpingd", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, debug_isis_events_cmd_vtysh, "debug isis events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Events\n") DEFSH (0, clear_ip_bgp_all_cmd_vtysh, "clear ip bgp *", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n") DEFSH (0|0|0|0, show_ip_prefix_list_detail_cmd_vtysh, "show ip prefix-list detail", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Detail of prefix lists\n") DEFSH (0, no_ipv6_ospf6_mtu_ignore_cmd_vtysh, "no ipv6 ospf6 mtu-ignore", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Ignore MTU mismatch on this interface\n" ) DEFSH (0, clear_bgp_as_soft_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n") DEFSH (0, show_ip_ospf_neighbor_int_cmd_vtysh, "show ip ospf neighbor IFNAME", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "Interface name\n") DEFSH (0, show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, bgp_cluster_id_cmd_vtysh, "bgp cluster-id A.B.C.D", "BGP information\n" "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id in IP address format\n") DEFSH (0, clear_ip_bgp_instance_all_soft_cmd_vtysh, "clear ip bgp view WORD * soft", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") DEFSH (0, ipv6_nd_prefix_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n" "Set Router Address flag\n") DEFSH (0, ip_rip_send_version_1_cmd_vtysh, "ip rip send version 1 2", "IP information\n" "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") DEFSH (0, show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") DEFSH (0, ip_multicast_routing_cmd_vtysh, "ip multicast-routing", "IP information\n" "Enable IP multicast forwarding\n") DEFSH (0, interface_no_ip_pim_ssm_cmd_vtysh, "no ip pim ssm", "Negate a command or set its defaults\n" "IP information\n" "PIM information\n" "Enable PIM SSM operation\n") DEFSH (0, test_pim_receive_hello_cmd_vtysh, "test pim receive hello INTERFACE A.B.C.D <0-65535> <0-65535> <0-65535> <0-32767> <0-65535> <0-1>[LINE]", "Test\n" "Test PIM protocol\n" "Test PIM message reception\n" "Test PIM hello reception from neighbor\n" "Interface\n" "Neighbor address\n" "Neighbor holdtime\n" "Neighbor DR priority\n" "Neighbor generation ID\n" "Neighbor propagation delay (msec)\n" "Neighbor override interval (msec)\n" "Neighbor LAN prune delay T-bit\n" "Neighbor secondary addresses\n") DEFSH (0, no_neighbor_ebgp_multihop_ttl_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop <1-255>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Allow EBGP neighbors not on directly connected networks\n" "maximum hop count\n") DEFSH (0, ip_route_mask_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0)", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Null interface\n") DEFSH (0, ripng_aggregate_address_cmd_vtysh, "aggregate-address X:X::X:X/M", "Set aggregate RIPng route announcement\n" "Aggregate network\n") DEFSH (0, ip_address_label_cmd_vtysh, "ip address A.B.C.D/M label LINE", "Interface Internet Protocol config commands\n" "Set the IP address of an interface\n" "IP address (e.g. 10.0.0.1/8)\n" "Label of this address\n" "Label\n") DEFSH (0, clear_ip_bgp_instance_all_rsclient_cmd_vtysh, "clear ip bgp view WORD * rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_bgp_view_afi_safi_community_all_cmd_vtysh, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") DEFSH (0|0|0|0, show_ip_prefix_list_name_cmd_vtysh, "show ip prefix-list WORD", "Show running system information\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0, ip_community_list_name_expanded_cmd_vtysh, "ip community-list expanded WORD (deny|permit) .LINE", "IP information\n" "Add a community list entry\n" "Add an expanded community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") DEFSH (0, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, no_isis_network_cmd_vtysh, "no isis network point-to-point", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set network type for circuit\n" "point-to-point network type\n") DEFSH (0, neighbor_shutdown_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "shutdown", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Administratively shut down this neighbor\n") DEFSH (0, show_babel_database_cmd_vtysh, "show babel database", "Show running system information\n" "IP information\n" "Babel information\n" "Database information\n" "No attributes\n") DEFSH (0, clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh, "clear ip bgp * vpnv4 unicast soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_flap_prefix_longer_cmd_vtysh, "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFSH (0|0|0, no_match_metric_val_cmd_vtysh, "no match metric <0-4294967295>", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match metric of route\n" "Metric value\n") DEFSH (0, no_debug_isis_adj_cmd_vtysh, "no debug isis adj-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS Adjacency related packets\n") DEFSH (0, ospf_transmit_delay_cmd_vtysh, "ospf transmit-delay <1-65535>", "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n") DEFSH (0, no_rip_route_cmd_vtysh, "no route A.B.C.D/M", "Negate a command or set its defaults\n" "RIP static route configuration\n" "IP prefix /\n") DEFSH (0, no_vty_ipv6_access_class_cmd_vtysh, "no ipv6 access-class [WORD]", "Negate a command or set its defaults\n" "IPv6 information\n" "Filter connections based on an IP access list\n" "IPv6 access list\n") DEFSH (0, no_ip_ospf_cost_cmd_vtysh, "no ip ospf cost", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n") DEFSH (0|0, match_tag_cmd_vtysh, "match tag <0-65535>", "Match values from routing table\n" "Match tag of route\n" "Metric value\n") DEFSH (0, debug_zebra_packet_cmd_vtysh, "debug zebra packet", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra packet\n") DEFSH (0, undebug_igmp_cmd_vtysh, "undebug igmp", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n") DEFSH (0, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, no_aggregate_address_mask_cmd_vtysh, "no aggregate-address A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n") DEFSH (0, no_spf_interval_l2_arg_cmd_vtysh, "no spf-interval level-2 <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, debug_ospf6_spf_database_cmd_vtysh, "debug ospf6 spf database", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug SPF Calculation\n" "Log number of LSAs at SPF Calculation time\n" ) DEFSH (0, neighbor_route_map_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "route-map WORD (in|out|import|export)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") DEFSH (0, ipv6_address_cmd_vtysh, "ipv6 address X:X::X:X/M", "Interface IPv6 config commands\n" "Set the IP address of an interface\n" "IPv6 address (e.g. 3ffe:506::1/48)\n") DEFSH (0, show_ip_ospf_neighbor_detail_all_cmd_vtysh, "show ip ospf neighbor detail all", "Show running system information\n" "IP information\n" "OSPF information\n" "Neighbor list\n" "detail of all neighbors\n" "include down status neighbor\n") DEFSH (0, no_rip_offset_list_cmd_vtysh, "no offset-list WORD (in|out) <0-16>", "Negate a command or set its defaults\n" "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0|0|0|0, show_ipv6_prefix_list_name_cmd_vtysh, "show ipv6 prefix-list WORD", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0, no_rip_timers_val_cmd_vtysh, "no timers basic <0-65535> <0-65535> <0-65535>", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Basic routing protocol update timers\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") DEFSH (0, show_debugging_rip_cmd_vtysh, "show debugging rip", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "RIP information\n") DEFSH (0, no_match_origin_cmd_vtysh, "no match origin", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP origin code\n") DEFSH (0, set_community_cmd_vtysh, "set community .AA:NN", "Set values in destination routing protocol\n" "BGP community attribute\n" "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") DEFSH (0, ospf_priority_cmd_vtysh, "ospf priority <0-255>", "OSPF interface commands\n" "Router priority\n" "Priority\n") DEFSH (0, clear_bgp_peer_in_prefix_filter_cmd_vtysh, "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", "Reset functions\n" "BGP information\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFSH (0, clear_ip_bgp_peer_group_soft_cmd_vtysh, "clear ip bgp peer-group WORD soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") DEFSH (0, isis_metric_l1_cmd_vtysh, "isis metric <0-16777215> level-1", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFSH (0, neighbor_remote_as_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "remote-as " "<1-4294967295>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a BGP neighbor\n" "AS number\n") DEFSH (0, no_match_ip_route_source_prefix_list_val_cmd_vtysh, "no match ip route-source prefix-list WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match advertising source address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, no_multicast_cmd_vtysh, "no multicast", "Negate a command or set its defaults\n" "Unset multicast flag to interface\n") DEFSH (0, clear_ip_bgp_dampening_address_mask_cmd_vtysh, "clear ip bgp dampening A.B.C.D A.B.C.D", "Reset functions\n" "IP information\n" "BGP information\n" "Clear route flap dampening information\n" "Network to clear damping information\n" "Network mask\n") DEFSH (0, no_debug_ospf6_brouter_router_cmd_vtysh, "no debug ospf6 border-routers router-id", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug specific border router\n" ) DEFSH (0, no_ipv6_nd_reachable_time_cmd_vtysh, "no ipv6 nd reachable-time", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n") DEFSH (0, no_ospf_default_metric_val_cmd_vtysh, "no default-metric <0-16777214>", "Negate a command or set its defaults\n" "Set metric of redistributed routes\n" "Default metric\n") DEFSH (0, no_debug_bgp_filter_cmd_vtysh, "no debug bgp filters", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP filters\n") DEFSH (0, ip_rip_send_version_cmd_vtysh, "ip rip send version (1|2)", "IP information\n" "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") DEFSH (0, no_neighbor_weight_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set default weight for routes from this neighbor\n") DEFSH (0, show_bgp_ipv4_safi_rsclient_route_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, clear_ip_bgp_as_in_prefix_filter_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " in prefix-filter", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFSH (0|0|0|0, no_ip_prefix_list_description_arg_cmd_vtysh, "no ip prefix-list WORD description .LINE", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Prefix-list specific description\n" "Up to 80 characters describing this prefix-list\n") DEFSH (0, rip_distance_source_cmd_vtysh, "distance <1-255> A.B.C.D/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") DEFSH (0, debug_ssmpingd_cmd_vtysh, "debug ssmpingd", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "adv-router A.B.C.D linkstate-id A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) DEFSH (0, show_bgp_views_cmd_vtysh, "show bgp views", "Show running system information\n" "BGP information\n" "Show the defined BGP views\n") DEFSH (0, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh, "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, show_ip_route_summary_prefix_cmd_vtysh, "show ip route summary prefix", "Show running system information\n" "IP information\n" "IP routing table\n" "Summary of all routes\n" "Prefix routes\n") DEFSH (0, no_debug_ripng_packet_direct_cmd_vtysh, "no debug ripng packet (recv|send)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n" "Debug option set for ripng packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") DEFSH (0, no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> warning-only", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Only give warning message when limit is exceeded\n") DEFSH (0, clear_ip_bgp_peer_soft_in_cmd_vtysh, "clear ip bgp A.B.C.D soft in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, clear_ip_bgp_external_soft_cmd_vtysh, "clear ip bgp external soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Soft reconfig\n") DEFSH (0, no_bgp_timers_cmd_vtysh, "no timers bgp", "Negate a command or set its defaults\n" "Adjust routing timers\n" "BGP timers\n") DEFSH (0, no_debug_rip_events_cmd_vtysh, "no debug rip events", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP events\n") DEFSH (0, bgp_damp_set_cmd_vtysh, "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") DEFSH (0, debug_ospf6_flooding_cmd_vtysh, "debug ospf6 flooding", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 flooding function\n" ) DEFSH (0, bgp_redistribute_ipv4_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, no_ipv6_nd_homeagent_preference_cmd_vtysh, "no ipv6 nd home-agent-preference", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n") DEFSH (0, show_database_arg_detail_cmd_vtysh, "show isis database WORD detail", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n" "Detailed information\n") DEFSH (0, no_ospf6_timers_throttle_spf_cmd_vtysh, "no timers throttle spf", "Negate a command or set its defaults\n" "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n") DEFSH (0, accept_lifetime_day_month_day_month_cmd_vtysh, "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", "Set accept lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Time to expire\n" "Day of th month to expire\n" "Month of the year to expire\n" "Year to expire\n") DEFSH (0, no_csnp_interval_l2_arg_cmd_vtysh, "no isis csnp-interval <1-600> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh, "show bgp view WORD ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_ip_bgp_prefix_longer_cmd_vtysh, "show ip bgp A.B.C.D/M longer-prefixes", "Show running system information\n" "IP information\n" "BGP information\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") DEFSH (0, ip_as_path_cmd_vtysh, "ip as-path access-list WORD (deny|permit) .LINE", "IP information\n" "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0|0, ospf6_routemap_no_match_address_prefixlist_cmd_vtysh, "no match ipv6 address prefix-list WORD", "Negate a command or set its defaults\n" "Match values\n" "IPv6 information\n" "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") DEFSH (0, clear_bgp_ipv6_instance_peer_rsclient_cmd_vtysh, "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, clear_bgp_ipv6_peer_soft_in_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, area_filter_list_cmd_vtysh, "area A.B.C.D filter-list prefix WORD (in|out)", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Filter networks between OSPFv6 areas\n" "Filter prefixes between OSPFv6 areas\n" "Name of an IPv6 prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") DEFSH (0, no_aggregate_address_mask_as_set_cmd_vtysh, "no aggregate-address A.B.C.D A.B.C.D as-set", "Negate a command or set its defaults\n" "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n") DEFSH (0, ip_ospf_message_digest_key_cmd_vtysh, "ip ospf message-digest-key <1-255> md5 KEY", "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, no_access_list_standard_cmd_vtysh, "no access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D A.B.C.D", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n" "Wildcard bits\n") DEFSH (0, bgp_network_backdoor_cmd_vtysh, "network A.B.C.D/M backdoor", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") DEFSH (0, show_ip_bgp_vpnv4_rd_route_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Network in the BGP routing table to display\n") DEFSH (0, no_ip_ospf_cost_inet4_cmd_vtysh, "no ip ospf cost A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Address of interface") DEFSH (0, debug_ospf6_message_cmd_vtysh, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) DEFSH (0, no_set_aggregator_as_val_cmd_vtysh, "no set aggregator as " "<1-4294967295>" " A.B.C.D", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP aggregator attribute\n" "AS number of aggregator\n" "AS number\n" "IP address of aggregator\n") DEFSH (0|0|0|0, match_ip_next_hop_cmd_vtysh, "match ip next-hop (<1-199>|<1300-2699>|WORD)", "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFSH (0, no_ospf_area_vlink_authtype_md5_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(message-digest-key|)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Enable authentication on this virtual link\n" "dummy string \n" "Message digest authentication password (key)\n" "dummy string \n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, no_if_rmap_cmd_vtysh, "no route-map ROUTEMAP_NAME (in|out) IFNAME", "Negate a command or set its defaults\n" "Route map unset\n" "Route map name\n" "Route map for input filtering\n" "Route map for output filtering\n" "Route map interface name\n") DEFSH (0, match_ecommunity_cmd_vtysh, "match extcommunity (<1-99>|<100-500>|WORD)", "Match values from routing table\n" "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") DEFSH (0, no_neighbor_peer_group_remote_as_cmd_vtysh, "no neighbor WORD remote-as " "<1-4294967295>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor tag\n" "Specify a BGP neighbor\n" "AS number\n") DEFSH (0, access_list_extended_mask_any_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "Any destination host\n") DEFSH (0, undebug_bgp_as4_cmd_vtysh, "undebug bgp as4", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, show_ip_bgp_ipv4_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast)", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, no_isis_hello_multiplier_l1_arg_cmd_vtysh, "no isis hello-multiplier <2-100> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, show_ip_ospf_database_type_id_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") A.B.C.D", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Link State ID (as an IP address)\n") DEFSH (0, ospf_area_range_advertise_cost_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFSH (0, no_ospf_area_vlink_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n") DEFSH (0, old_ipv6_aggregate_address_cmd_vtysh, "ipv6 bgp aggregate-address X:X::X:X/M", "IPv6 information\n" "BGP information\n" "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, clear_bgp_ipv6_external_in_cmd_vtysh, "clear bgp ipv6 external WORD in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n") DEFSH (0, no_neighbor_attr_unchanged1_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, ip_ospf_cost_u32_cmd_vtysh, "ip ospf cost <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") DEFSH (0, ip_route_mask_flags_distance_cmd_vtysh, "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, babel_network_cmd_vtysh, "network IF_OR_ADDR", "Enable Babel protocol on specified interface or network.\n" "Interface or address") DEFSH (0, no_ipv6_ospf6_ifmtu_cmd_vtysh, "no ipv6 ospf6 ifmtu", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface MTU\n" ) DEFSH (0, show_ip_bgp_flap_regexp_cmd_vtysh, "show ip bgp flap-statistics regexp .LINE", "Show running system information\n" "IP information\n" "BGP information\n" "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, clear_ip_bgp_dampening_cmd_vtysh, "clear ip bgp dampening", "Reset functions\n" "IP information\n" "BGP information\n" "Clear route flap dampening information\n") DEFSH (0, no_debug_isis_snp_cmd_vtysh, "no debug isis snp-packets", "Disable debugging functions (see also 'debug')\n" "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") DEFSH (0, send_lifetime_month_day_day_month_cmd_vtysh, "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS <1-31> MONTH <1993-2035>", "Set send lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Time to expire\n" "Day of th month to expire\n" "Month of the year to expire\n" "Year to expire\n") DEFSH (0, debug_ospf6_asbr_cmd_vtysh, "debug ospf6 asbr", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 ASBR function\n" ) DEFSH (0, clear_bgp_instance_all_soft_out_cmd_vtysh, "clear bgp view WORD * soft out", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, log_adj_changes_cmd_vtysh, "log-adjacency-changes", "Log changes in adjacency state\n") DEFSH (0, no_debug_ssmpingd_cmd_vtysh, "no debug ssmpingd", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "ssmpingd activity\n") DEFSH (0, clear_ip_bgp_peer_group_cmd_vtysh, "clear ip bgp peer-group WORD", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n") DEFSH (0, show_bgp_view_prefix_cmd_vtysh, "show bgp view WORD X:X::X:X/M", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "IPv6 prefix /\n") DEFSH (0, clear_ip_bgp_peer_cmd_vtysh, "clear ip bgp (A.B.C.D|X:X::X:X)", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n") DEFSH (0, show_bgp_community4_exact_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_ip_irdp_cmd_vtysh, "no ip irdp", "Negate a command or set its defaults\n" "IP information\n" "Disable ICMP Router discovery on this interface\n") DEFSH (0, show_ipv6_ospf6_database_type_router_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) * A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, clear_bgp_all_out_cmd_vtysh, "clear bgp * out", "Reset functions\n" "BGP information\n" "Clear all peers\n" "Soft reconfig outbound update\n") DEFSH (0, no_mpls_te_cmd_vtysh, "no mpls-te", "Negate a command or set its defaults\n" "Configure MPLS-TE parameters\n" "Disable the MPLS-TE functionality\n") DEFSH (0, show_ipv6_ospf6_database_router_cmd_vtysh, "show ipv6 ospf6 database * * A.B.C.D", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Any Link state Type\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" ) DEFSH (0, debug_ospf6_interface_cmd_vtysh, "debug ospf6 interface", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 Interface\n" ) DEFSH (0, ospf_retransmit_interval_cmd_vtysh, "ospf retransmit-interval <3-65535>", "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n") DEFSH (0, no_bgp_network_mask_backdoor_cmd_vtysh, "no network A.B.C.D mask A.B.C.D backdoor", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") DEFSH (0, no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " route-map WORD metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, neighbor_maximum_prefix_warning_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> warning-only", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Only give warning message when limit is exceeded\n") DEFSH (0, mpls_te_link_rsc_clsclr_cmd_vtysh, "mpls-te link rsc-clsclr BITPATTERN", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Administrative group membership\n" "32-bit Hexadecimal value (ex. 0xa1)\n") DEFSH (0, bgp_confederation_peers_cmd_vtysh, "bgp confederation peers ." "<1-4294967295>", "BGP specific commands\n" "AS confederation parameters\n" "Peer ASs in BGP confederation\n" "AS number\n") DEFSH (0, no_bgp_deterministic_med_cmd_vtysh, "no bgp deterministic-med", "Negate a command or set its defaults\n" "BGP specific commands\n" "Pick the best-MED path among paths advertised from the neighboring AS\n") DEFSH (0, no_max_lsp_lifetime_l2_arg_cmd_vtysh, "no max-lsp-lifetime level-2 <350-65535>", "Negate a command or set its defaults\n" "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0, no_debug_pim_trace_cmd_vtysh, "no debug pim trace", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM internal daemon activity\n") DEFSH (0, exec_timeout_sec_cmd_vtysh, "exec-timeout <0-35791> <0-2147483>", "Set the EXEC timeout\n" "Timeout in minutes\n" "Timeout in seconds\n") DEFSH (0, no_bgp_scan_time_cmd_vtysh, "no bgp scan-time", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure background scanner interval\n") DEFSH (0, show_ip_extcommunity_list_cmd_vtysh, "show ip extcommunity-list", "Show running system information\n" "IP information\n" "List extended-community list\n") DEFSH (0, clear_ip_bgp_as_vpnv4_in_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " vpnv4 unicast in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, clear_bgp_instance_all_rsclient_cmd_vtysh, "clear bgp view WORD * rsclient", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, debug_bgp_normal_cmd_vtysh, "debug bgp", "Debugging functions (see also 'undebug')\n" "BGP information\n") DEFSH (0, no_ospf_router_id_cmd_vtysh, "no ospf router-id", "Negate a command or set its defaults\n" "OSPF specific commands\n" "router-id for the OSPF process\n") DEFSH (0, vty_no_restricted_mode_cmd_vtysh, "no anonymous restricted", "Negate a command or set its defaults\n" "Enable password checking\n") DEFSH (0, lsp_gen_interval_l1_cmd_vtysh, "lsp-gen-interval level-1 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFSH (0, show_bgp_instance_neighbors_cmd_vtysh, "show bgp view WORD neighbors", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, no_ip_rip_send_version_cmd_vtysh, "no ip rip send version", "Negate a command or set its defaults\n" "IP information\n" "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n") DEFSH (0, neighbor_send_community_type_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community (both|extended|standard)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") DEFSH (0, isis_priority_l2_cmd_vtysh, "isis priority <0-127> level-2", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") DEFSH (0, undebug_bgp_filter_cmd_vtysh, "undebug bgp filters", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP filters\n") DEFSH (0, no_neighbor_ebgp_multihop_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Allow EBGP neighbors not on directly connected networks\n") DEFSH (0, ipv6_route_flags_pref_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this prefix\n") DEFSH (0, ipv6_mbgp_neighbor_advertised_route_cmd_vtysh, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, no_bgp_default_local_preference_cmd_vtysh, "no bgp default local-preference", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n") DEFSH (0, show_ipv6_bgp_route_cmd_vtysh, "show ipv6 bgp X:X::X:X", "Show running system information\n" "IP information\n" "BGP information\n" "Network in the BGP routing table to display\n") DEFSH (0, neighbor_nexthop_self_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self {all}", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") DEFSH (0, no_ripng_network_cmd_vtysh, "no network IF_OR_ADDR", "Negate a command or set its defaults\n" "RIPng enable on specified interface or network.\n" "Interface or address") DEFSH (0, no_ipv6_access_list_remark_cmd_vtysh, "no ipv6 access-list WORD remark", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Access list entry comment\n") DEFSH (0, psnp_interval_l2_cmd_vtysh, "isis psnp-interval <1-120> level-2", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, show_ip_bgp_ipv4_regexp_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) regexp .LINE", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") DEFSH (0, no_set_atomic_aggregate_cmd_vtysh, "no set atomic-aggregate", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP atomic aggregate attribute\n" ) DEFSH (0, area_export_list_cmd_vtysh, "area A.B.C.D export-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Set the filter for networks announced to other areas\n" "Name of the acess-list\n") DEFSH (0, neighbor_attr_unchanged8_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged next-hop as-path med", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") DEFSH (0, clear_bgp_as_soft_in_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft in", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, neighbor_unsuppress_map_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "unsuppress-map WORD", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Route-map to selectively unsuppress suppressed routes\n" "Name of route map\n") DEFSH (0, show_ip_bgp_route_map_cmd_vtysh, "show ip bgp route-map WORD", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFSH (0|0|0|0, no_ipv6_prefix_list_ge_le_cmd_vtysh, "no ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_csnp_interval_l2_cmd_vtysh, "no isis csnp-interval level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-2 CSNPs\n") DEFSH (0, ospf_cost_u32_inet4_cmd_vtysh, "ospf cost <1-65535> A.B.C.D", "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, show_ipv6_ospf6_interface_prefix_cmd_vtysh, "show ipv6 ospf6 interface prefix", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interface infomation\n" "Display connected prefixes to advertise\n" ) DEFSH (0, ospf_hello_interval_cmd_vtysh, "ospf hello-interval <1-65535>", "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFSH (0, no_set_pathlimit_ttl_val_cmd_vtysh, "no set pathlimit ttl <1-255>", "Negate a command or set its defaults\n" "Match values from routing table\n" "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") DEFSH (0, send_lifetime_month_day_month_day_cmd_vtysh, "send-lifetime HH:MM:SS MONTH <1-31> <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", "Set send lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Time to expire\n" "Month of the year to expire\n" "Day of th month to expire\n" "Year to expire\n") DEFSH (0, bgp_bestpath_aspath_multipath_relax_cmd_vtysh, "bgp bestpath as-path multipath-relax", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") DEFSH (0|0, ospf6_routemap_set_metric_type_cmd_vtysh, "set metric-type (type-1|type-2)", "Set value\n" "Type of metric\n" "OSPF6 external type 1 metric\n" "OSPF6 external type 2 metric\n") DEFSH (0, ripng_route_cmd_vtysh, "route IPV6ADDR", "Static route setup\n" "Set static RIPng route announcement\n") DEFSH (0, no_bgp_maxpaths_arg_cmd_vtysh, "no maximum-paths <1-255>", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "Number of paths\n") DEFSH (0|0, set_ipv6_nexthop_local_cmd_vtysh, "set ipv6 next-hop local X:X::X:X", "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") DEFSH (0, show_ipv6_ospf6_route_longer_detail_cmd_vtysh, "show ipv6 ospf6 route X:X::X:X/M longer detail", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" "Detailed information\n" ) DEFSH (0, show_ip_bgp_ipv4_summary_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) summary", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, bgp_redistribute_ipv6_metric_rmap_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") DEFSH (0, show_ipv6_ospf6_database_type_id_self_originated_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Display Self-originated LSAs\n" ) DEFSH (0, show_ipv6_ospf6_database_type_adv_router_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D " "(detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_isis_hello_interval_arg_cmd_vtysh, "no isis hello-interval <1-600>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n") DEFSH (0|0|0|0, clear_ipv6_prefix_list_name_cmd_vtysh, "clear ipv6 prefix-list WORD", "Reset functions\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n") DEFSH (0, no_bgp_network_cmd_vtysh, "no network A.B.C.D/M", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0, no_set_weight_cmd_vtysh, "no set weight", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP weight for routing table\n") DEFSH (0, no_ospf_message_digest_key_cmd_vtysh, "no ospf message-digest-key <1-255>", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n") DEFSH (0, no_debug_ospf6_flooding_cmd_vtysh, "no debug ospf6 flooding", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 flooding function\n" ) DEFSH (0, show_ipv6_route_summary_cmd_vtysh, "show ipv6 route summary", "Show running system information\n" "IP information\n" "IPv6 routing table\n" "Summary of all IPv6 routes\n") DEFSH (0, clear_ip_bgp_as_vpnv4_out_cmd_vtysh, "clear ip bgp " "<1-4294967295>" " vpnv4 unicast out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, ipv6_nd_ra_interval_msec_cmd_vtysh, "ipv6 nd ra-interval msec <70-1800000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFSH (0, no_ipv6_nd_mtu_val_cmd_vtysh, "no ipv6 nd mtu <1-65535>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") DEFSH (0, isis_hello_interval_cmd_vtysh, "isis hello-interval <1-600>", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 seconds, interval depends on multiplier\n") DEFSH (0, show_bgp_instance_ipv6_neighbors_cmd_vtysh, "show bgp view WORD ipv6 neighbors", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFSH (0, debug_ospf_zebra_cmd_vtysh, "debug ospf zebra", "Debugging functions (see also 'undebug')\n" "OSPF information\n" "OSPF Zebra information\n") DEFSH (0, no_bgp_distance_source_cmd_vtysh, "no distance <1-255> A.B.C.D/M", "Negate a command or set its defaults\n" "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") DEFSH (0, neighbor_ttl_security_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "ttl-security hops <1-254>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify the maximum number of hops to the BGP peer\n") DEFSH (0, bgp_network_mask_natural_route_map_cmd_vtysh, "network A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") DEFSH (0, ospf_distance_cmd_vtysh, "distance <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n") DEFSH (0, ripng_default_metric_cmd_vtysh, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0|0|0|0, clear_ipv6_prefix_list_name_prefix_cmd_vtysh, "clear ipv6 prefix-list WORD X:X::X:X/M", "Reset functions\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, ospf_area_range_advertise_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "OSPF area range for route advertise (default)\n" "Area range prefix\n" "Advertise this range (default)\n") DEFSH (0, clear_bgp_ipv6_peer_group_cmd_vtysh, "clear bgp ipv6 peer-group WORD", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n") DEFSH (0, access_list_extended_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D A.B.C.D A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "Destination address\n" "Destination Wildcard bits\n") DEFSH (0, no_neighbor_nexthop_self_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "next-hop-self {all}", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") DEFSH (0, no_ip_irdp_address_preference_cmd_vtysh, "no ip irdp address A.B.C.D preference <0-2147483647>", "Negate a command or set its defaults\n" "IP information\n" "Alter ICMP Router discovery preference this interface\n" "Removes IRDP non-default preference\n" "Select IRDP address\n" "Old preference level\n") DEFSH (0, no_neighbor_local_as_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "local-as", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Specify a local-as number\n") DEFSH (0, neighbor_capability_orf_prefix_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Advertise capability to the peer\n" "Advertise ORF capability to the peer\n" "Advertise prefixlist ORF capability to this neighbor\n" "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") DEFSH (0, accept_lifetime_infinite_month_day_cmd_vtysh, "accept-lifetime HH:MM:SS MONTH <1-31> <1993-2035> infinite", "Set accept lifetime of the key\n" "Time to start\n" "Month of the year to start\n" "Day of th month to start\n" "Year to start\n" "Never expires") DEFSH (0, show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh, "show bgp ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, show_isis_neighbor_detail_cmd_vtysh, "show isis neighbor detail", "Show running system information\n" "ISIS network information\n" "ISIS neighbor adjacencies\n" "show detailed information\n") DEFSH (0, ipv6_ospf6_passive_cmd_vtysh, "ipv6 ospf6 passive", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "passive interface, No adjacency will be formed on this interface\n" ) DEFSH (0, no_set_origin_val_cmd_vtysh, "no set origin (egp|igp|incomplete)", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFSH (0, show_ip_pim_local_membership_cmd_vtysh, "show ip pim local-membership", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface local-membership\n") DEFSH (0, show_ip_bgp_community_exact_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, ospf_distribute_list_out_cmd_vtysh, "distribute-list WORD out " "(kernel|connected|static|rip|isis|bgp|pim|babel)", "Filter networks in routing updates\n" "Access-list name\n" "Filter outgoing routing updates\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0, show_debugging_cmd_vtysh, "show debugging", "Show running system information\n" "State of each debugging option\n") DEFSH (0, no_ip_ospf_mtu_ignore_addr_cmd_vtysh, "no ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") DEFSH (0, no_rip_default_metric_cmd_vtysh, "no default-metric", "Negate a command or set its defaults\n" "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, show_ip_bgp_community_info_cmd_vtysh, "show ip bgp community-info", "Show running system information\n" "IP information\n" "BGP information\n" "List all bgp community information\n") DEFSH (0|0|0, no_match_metric_cmd_vtysh, "no match metric", "Negate a command or set its defaults\n" "Match values from routing table\n" "Match metric of route\n") DEFSH (0, show_ipv6_ospf6_database_self_originated_cmd_vtysh, "show ipv6 ospf6 database self-originated", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Self-originated LSAs\n" ) DEFSH (0, clear_ip_bgp_all_vpnv4_in_cmd_vtysh, "clear ip bgp * vpnv4 unicast in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFSH (0|0|0|0, ip_prefix_list_ge_le_cmd_vtysh, "ip prefix-list WORD (deny|permit) A.B.C.D/M ge <0-32> le <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, bgp_redistribute_ipv4_cmd_vtysh, "redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n") DEFSH (0|0|0|0, ip_prefix_list_le_ge_cmd_vtysh, "ip prefix-list WORD (deny|permit) A.B.C.D/M le <0-32> ge <0-32>", "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, bgp_network_mask_natural_backdoor_cmd_vtysh, "network A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") DEFSH (0, show_ipv6_mbgp_community_cmd_vtysh, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IPv6 information\n" "MBGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, clear_bgp_ipv6_all_soft_out_cmd_vtysh, "clear bgp ipv6 * soft out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_spf_interval_arg_cmd_vtysh, "no spf-interval <1-120>", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFSH (0, no_isis_priority_l2_arg_cmd_vtysh, "no isis priority <0-127> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") DEFSH (0, clear_bgp_ipv6_peer_group_out_cmd_vtysh, "clear bgp ipv6 peer-group WORD out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFSH (0, clear_ip_bgp_peer_group_out_cmd_vtysh, "clear ip bgp peer-group WORD out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFSH (0, ospf6_routemap_set_forwarding_cmd_vtysh, "set forwarding-address X:X::X:X", "Set value\n" "Forwarding Address\n" "IPv6 Address\n") DEFSH (0, no_isis_passwd_cmd_vtysh, "no isis password", "Negate a command or set its defaults\n" "IS-IS commands\n" "Configure the authentication password for a circuit\n") DEFSH (0, no_ipv6_nd_ra_interval_msec_val_cmd_vtysh, "no ipv6 nd ra-interval msec <1-1800000>", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFSH (0, no_spf_interval_l1_cmd_vtysh, "no spf-interval level-1", "Negate a command or set its defaults\n" "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n") DEFSH (0, no_ospf_distance_ospf_cmd_vtysh, "no distance ospf {intra-area|inter-area|external}", "Negate a command or set its defaults\n" "Define an administrative distance\n" "OSPF Administrative distance\n" "OSPF Distance\n" "Intra-area routes\n" "Inter-area routes\n" "External routes\n") DEFSH (0, show_bgp_ipv6_neighbor_prefix_counts_cmd_vtysh, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", "Show running system information\n" "BGP information\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") DEFSH (0, no_ipv6_access_list_all_cmd_vtysh, "no ipv6 access-list WORD", "Negate a command or set its defaults\n" "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n") DEFSH (0, clear_bgp_as_cmd_vtysh, "clear bgp " "<1-4294967295>", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n") DEFSH (0, ipv6_nd_suppress_ra_cmd_vtysh, "ipv6 nd suppress-ra", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") DEFSH (0, mpls_te_link_maxbw_cmd_vtysh, "mpls-te link max-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that can be used\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, no_neighbor_peer_group_cmd_vtysh, "no neighbor WORD peer-group", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor tag\n" "Configure peer-group\n") DEFSH (0, show_ip_as_path_access_list_cmd_vtysh, "show ip as-path-access-list WORD", "Show running system information\n" "IP information\n" "List AS path access lists\n" "AS path access list name\n") DEFSH (0, no_ospf_network_area_cmd_vtysh, "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", "Negate a command or set its defaults\n" "Enable routing on an IP network\n" "OSPF network prefix\n" "Set the OSPF area ID\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") DEFSH (0, show_bgp_memory_cmd_vtysh, "show bgp memory", "Show running system information\n" "BGP information\n" "Global BGP memory statistics\n") DEFSH (0, no_ospf_cost_inet4_cmd_vtysh, "no ospf cost A.B.C.D", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Address of interface") DEFSH (0, show_bgp_view_ipv6_cmd_vtysh, "show bgp view WORD ipv6", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n") DEFSH (0, neighbor_nexthop_local_unchanged_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "nexthop-local unchanged", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Configure treatment of outgoing link-local nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") DEFSH (0, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") DEFSH (0, show_bgp_ipv6_community_exact_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd_vtysh, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "linkstate-id A.B.C.D (detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, no_ip_community_list_name_standard_cmd_vtysh, "no ip community-list standard WORD (deny|permit) .AA:NN", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Specify a standard community-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n") DEFSH (0, show_bgp_view_ipv6_neighbor_routes_cmd_vtysh, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, show_ip_ospf_database_type_self_cmd_vtysh, "show ip ospf database (" "asbr-summary|external|network|router|summary" "|nssa-external" "|opaque-link|opaque-area|opaque-as" ") (self-originate|)", "Show running system information\n" "IP information\n" "OSPF information\n" "Database summary\n" "ASBR summary link states\n" "External link states\n" "Network link states\n" "Router link states\n" "Network summary link states\n" "NSSA external link state\n" "Link local Opaque-LSA\n" "Link area Opaque-LSA\n" "Link AS Opaque-LSA\n" "Self-originated link states\n") DEFSH (0, no_neighbor_maximum_prefix_restart_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> restart <1-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") DEFSH (0, set_src_cmd_vtysh, "set src A.B.C.D", "Set values in destination routing protocol\n" "src address for route\n" "src address\n") DEFSH (0, clear_ip_bgp_peer_ipv4_in_cmd_vtysh, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFSH (0, ip_ospf_dead_interval_addr_cmd_vtysh, "ip ospf dead-interval <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Address of interface\n") DEFSH (0|0|0|0, ipv6_prefix_list_ge_le_cmd_vtysh, "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M ge <0-128> le <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n") DEFSH (0, no_neighbor_weight_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "weight <0-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Set default weight for routes from this neighbor\n" "default weight\n") DEFSH (0, no_ospf6_redistribute_cmd_vtysh, "no redistribute " "(kernel|connected|static|ripng|isis|bgp|babel)", "Negate a command or set its defaults\n" "Redistribute\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Babel routing protocol (Babel)\n" ) DEFSH (0|0|0|0, no_ipv6_prefix_list_seq_le_ge_cmd_vtysh, "no ipv6 prefix-list WORD seq <1-4294967295> (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", "Negate a command or set its defaults\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, ospf_auto_cost_reference_bandwidth_cmd_vtysh, "auto-cost reference-bandwidth <1-4294967>", "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") DEFSH (0, clear_bgp_as_soft_out_cmd_vtysh, "clear bgp " "<1-4294967295>" " soft out", "Reset functions\n" "BGP information\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0|0|0|0, no_ip_prefix_list_seq_cmd_vtysh, "no ip prefix-list WORD seq <1-4294967295> (deny|permit) (A.B.C.D/M|any)", "Negate a command or set its defaults\n" "IP information\n" "Build a prefix list\n" "Name of a prefix list\n" "sequence number of an entry\n" "Sequence number\n" "Specify packets to reject\n" "Specify packets to forward\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n") DEFSH (0, neighbor_passive_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "passive", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Don't send open messages to this neighbor\n") DEFSH (0, ip_route_flags2_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole)", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n") DEFSH (0|0|0|0, no_match_ip_address_prefix_list_cmd_vtysh, "no match ip address prefix-list", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match address of route\n" "Match entries of prefix-lists\n") DEFSH (0, neighbor_timers_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "timers <0-65535> <0-65535>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP per neighbor timers\n" "Keepalive interval\n" "Holdtime\n") DEFSH (0, show_ipv6_bgp_prefix_list_cmd_vtysh, "show ipv6 bgp prefix-list WORD", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") DEFSH (0, set_ipv6_nexthop_peer_cmd_vtysh, "set ipv6 next-hop peer-address", "Set values in destination routing protocol\n" "IPv6 information\n" "Next hop address\n" "Use peer address (for BGP only)\n") DEFSH (0|0|0|0, ipv6_prefix_list_le_ge_cmd_vtysh, "ipv6 prefix-list WORD (deny|permit) X:X::X:X/M le <0-128> ge <0-128>", "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "Specify packets to reject\n" "Specify packets to forward\n" "IPv6 prefix /, e.g., 3ffe::/16\n" "Maximum prefix length to be matched\n" "Maximum prefix length\n" "Minimum prefix length to be matched\n" "Minimum prefix length\n") DEFSH (0, no_debug_zebra_rib_q_cmd_vtysh, "no debug zebra rib queue", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug zebra RIB\n" "Debug RIB queueing\n") DEFSH (0, show_ipv6_bgp_filter_list_cmd_vtysh, "show ipv6 bgp filter-list WORD", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") DEFSH (0, undebug_bgp_as4_segment_cmd_vtysh, "undebug bgp as4 segment", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFSH (0, no_ip_route_flags_distance_cmd_vtysh, "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, babel_set_wireless_cmd_vtysh, "babel wireless", "Babel interface commands\n" "Disable wired optimiations (assume wireless)") DEFSH (0, no_neighbor_remove_private_as_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "remove-private-AS", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Remove private AS number from outbound updates\n") DEFSH (0, no_ripng_offset_list_cmd_vtysh, "no offset-list WORD (in|out) <0-16>", "Negate a command or set its defaults\n" "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") DEFSH (0, show_ipv6_access_list_cmd_vtysh, "show ipv6 access-list", "Show running system information\n" "IPv6 information\n" "List IPv6 access lists\n") DEFSH (0, no_ospf_max_metric_router_lsa_startup_cmd_vtysh, "no max-metric router-lsa on-startup", "Negate a command or set its defaults\n" "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n") DEFSH (0|0, no_set_tag_cmd_vtysh, "no set tag", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "Tag value for routing protocol\n") DEFSH (0, show_ipv6_mbgp_regexp_cmd_vtysh, "show ipv6 mbgp regexp .LINE", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the MBGP AS paths\n") DEFSH (0, debug_ospf6_zebra_sendrecv_cmd_vtysh, "debug ospf6 zebra (send|recv)", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) DEFSH (0, no_neighbor_capability_orf_prefix_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "capability orf prefix-list (both|send|receive)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Advertise capability to the peer\n" "Advertise ORF capability to the peer\n" "Advertise prefixlist ORF capability to this neighbor\n" "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") DEFSH (0, interface_ip_igmp_query_interval_cmd_vtysh, "ip igmp query-interval" " <1-1800>", "IP information\n" "Enable IGMP operation\n" "IGMP host query interval\n" "Query interval in seconds\n") DEFSH (0, neighbor_ebgp_multihop_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "ebgp-multihop", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Allow EBGP neighbors not on directly connected networks\n") DEFSH (0|0|0|0, ipv6_prefix_list_sequence_number_cmd_vtysh, "ipv6 prefix-list sequence-number", "IPv6 information\n" "Build a prefix list\n" "Include/exclude sequence numbers in NVGEN\n") DEFSH (0, no_bgp_client_to_client_reflection_cmd_vtysh, "no bgp client-to-client reflection", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure client to client route reflection\n" "reflection of routes allowed\n") DEFSH (0, no_bgp_maxpaths_ibgp_cmd_vtysh, "no maximum-paths ibgp", "Negate a command or set its defaults\n" "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") DEFSH (0, no_ipv6_bgp_network_cmd_vtysh, "no network X:X::X:X/M", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "IPv6 prefix /\n") DEFSH (0, no_dump_bgp_all_cmd_vtysh, "no dump bgp all [PATH] [INTERVAL]", "Negate a command or set its defaults\n" "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n") DEFSH (0|0|0|0|0|0, no_rmap_continue_cmd_vtysh, "no continue", "Negate a command or set its defaults\n" "Continue on a different entry within the route-map\n") DEFSH (0, clear_bgp_all_cmd_vtysh, "clear bgp *", "Reset functions\n" "BGP information\n" "Clear all peers\n") DEFSH (0, no_debug_igmp_trace_cmd_vtysh, "no debug igmp trace", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0|0|0|0|0|0, no_route_map_cmd_vtysh, "no route-map WORD (deny|permit) <1-65535>", "Negate a command or set its defaults\n" "Create route-map or enter route-map command mode\n" "Route map tag\n" "Route map denies set operations\n" "Route map permits set operations\n" "Sequence to insert to/delete from existing route-map entry\n") DEFSH (0, no_access_list_extended_host_any_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D any", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "Any destination host\n") DEFSH (0, show_bgp_community3_exact_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, neighbor_attr_unchanged2_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path (next-hop|med)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, no_isis_hello_interval_l2_arg_cmd_vtysh, "no isis hello-interval <1-600> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFSH (0, show_ipv6_ospf6_area_spf_tree_cmd_vtysh, "show ipv6 ospf6 area A.B.C.D spf tree", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Area information\n" "Area ID (as an IPv4 notation)\n" "Shortest Path First caculation\n" "Show SPF tree\n") DEFSH (0, debug_pim_cmd_vtysh, "debug pim", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n") DEFSH (0, ospf_area_filter_list_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Filter networks between OSPF areas\n" "Filter prefixes between OSPF areas\n" "Name of an IP prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") DEFSH (0, show_babel_interface_cmd_vtysh, "show babel interface [INTERFACE]", "Show running system information\n" "IP information\n" "Babel information\n" "Interface information\n" "Interface name\n") DEFSH (0, set_origin_cmd_vtysh, "set origin (egp|igp|incomplete)", "Set values in destination routing protocol\n" "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFSH (0, vpnv4_network_cmd_vtysh, "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") DEFSH (0, no_ipv6_nd_homeagent_lifetime_cmd_vtysh, "no ipv6 nd home-agent-lifetime", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n") DEFSH (0, ospf_area_nssa_translate_no_summary_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always) no-summary", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Configure NSSA-ABR for translate election (default)\n" "Configure NSSA-ABR to never translate\n" "Configure NSSA-ABR to always translate\n" "Do not inject inter-area routes into nssa\n") DEFSH (0, no_ospf_neighbor_cmd_vtysh, "no neighbor A.B.C.D", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor IP address\n") DEFSH (0, ipv6_access_list_any_cmd_vtysh, "ipv6 access-list WORD (deny|permit) any", "IPv6 information\n" "Add an access list entry\n" "IPv6 zebra access-list\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any prefixi to match\n") DEFSH (0, show_bgp_ipv6_community4_cmd_vtysh, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_ipv6_ospf6_passive_cmd_vtysh, "no ipv6 ospf6 passive", "Negate a command or set its defaults\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "passive interface: No Adjacency will be formed on this I/F\n" ) DEFSH (0, undebug_pim_zebra_cmd_vtysh, "undebug pim zebra", "Disable debugging functions (see also 'debug')\n" "PIM protocol activity\n" "ZEBRA protocol activity\n") DEFSH (0, clear_bgp_peer_group_soft_cmd_vtysh, "clear bgp peer-group WORD soft", "Reset functions\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") DEFSH (0, no_debug_ospf6_brouter_area_cmd_vtysh, "no debug ospf6 border-routers area-id", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" "Debug border routers in specific Area\n" ) DEFSH (0, clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) soft out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, no_router_ospf_id_cmd_vtysh, "no router-id", "Negate a command or set its defaults\n" "router-id for the OSPF process\n") DEFSH (0, clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") DEFSH (0, show_ipv6_bgp_community_list_cmd_vtysh, "show ipv6 bgp community-list WORD", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list name\n") DEFSH (0, bgp_enforce_first_as_cmd_vtysh, "bgp enforce-first-as", "BGP information\n" "Enforce the first AS for EBGP routes\n") DEFSH (0, show_ipv6_ospf6_route_cmd_vtysh, "show ipv6 ospf6 route", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Routing Table\n" ) DEFSH (0, show_ip_bgp_community2_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, neighbor_peer_group_cmd_vtysh, "neighbor WORD peer-group", "Specify neighbor router\n" "Neighbor tag\n" "Configure peer-group\n") DEFSH (0, no_debug_bgp_as4_cmd_vtysh, "no debug bgp as4", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP AS4 actions\n") DEFSH (0, bgp_distance_cmd_vtysh, "distance bgp <1-255> <1-255> <1-255>", "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") DEFSH (0, no_ospf_cost_u32_inet4_cmd_vtysh, "no ospf cost <1-65535> A.B.C.D", "Negate a command or set its defaults\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFSH (0, send_lifetime_day_month_month_day_cmd_vtysh, "send-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", "Set send lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Time to expire\n" "Month of the year to expire\n" "Day of th month to expire\n" "Year to expire\n") DEFSH (0, set_local_pref_cmd_vtysh, "set local-preference <0-4294967295>", "Set values in destination routing protocol\n" "BGP local preference path attribute\n" "Preference value\n") DEFSH (0, bgp_log_neighbor_changes_cmd_vtysh, "bgp log-neighbor-changes", "BGP specific commands\n" "Log neighbor up/down and reset reason\n") DEFSH (0, no_bgp_distance2_cmd_vtysh, "no distance bgp", "Negate a command or set its defaults\n" "Define an administrative distance\n" "BGP distance\n") DEFSH (0, clear_ip_bgp_all_out_cmd_vtysh, "clear ip bgp * out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig outbound update\n") DEFSH (0, aggregate_address_cmd_vtysh, "aggregate-address A.B.C.D/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") DEFSH (0, show_zebra_fpm_stats_cmd_vtysh, "show zebra fpm stats", "Show running system information\n" "Zebra information\n" "Forwarding Path Manager information\n" "Statistics\n") DEFSH (0, ospf_passive_interface_cmd_vtysh, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface's name\n") DEFSH (0, debug_rip_packet_cmd_vtysh, "debug rip packet", "Debugging functions (see also 'undebug')\n" "RIP information\n" "RIP packet\n") DEFSH (0, show_isis_interface_arg_cmd_vtysh, "show isis interface WORD", "Show running system information\n" "ISIS network information\n" "ISIS interface\n" "ISIS interface name\n") DEFSH (0, no_ipv6_route_cmd_vtysh, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n") DEFSH (0, ospf_area_vlink_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n") DEFSH (0, clear_bgp_ipv6_as_cmd_vtysh, "clear bgp ipv6 " "<1-4294967295>", "Reset functions\n" "BGP information\n" "Address family\n" "Clear peers with the AS number\n") DEFSH (0, clear_ip_bgp_peer_out_cmd_vtysh, "clear ip bgp A.B.C.D out", "Reset functions\n" "IP information\n" "BGP information\n" "BGP neighbor address to clear\n" "Soft reconfig outbound update\n") DEFSH (0, no_net_cmd_vtysh, "no net WORD", "Negate a command or set its defaults\n" "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") DEFSH (0, clear_ip_bgp_external_ipv4_out_cmd_vtysh, "clear ip bgp external ipv4 (unicast|multicast) out", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFSH (0, show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, isis_hello_padding_cmd_vtysh, "isis hello padding", "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") DEFSH (0, no_ip_community_list_name_expanded_all_cmd_vtysh, "no ip community-list expanded WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a community list entry\n" "Add an expanded community-list entry\n" "Community list name\n") DEFSH (0, neighbor_distribute_list_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Filter updates to/from this neighbor\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") DEFSH (0, no_debug_bgp_zebra_cmd_vtysh, "no debug bgp zebra", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, clear_bgp_ipv6_external_soft_in_cmd_vtysh, "clear bgp ipv6 external soft in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, show_ipv6_ospf6_neighbor_detail_cmd_vtysh, "show ipv6 ospf6 neighbor (detail|drchoice)", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Neighbor list\n" "Display details\n" "Display DR choices\n" ) DEFSH (0, no_isis_hello_multiplier_l2_cmd_vtysh, "no isis hello-multiplier level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-2 IIHs\n") DEFSH (0, no_neighbor_interface_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "interface WORD", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Interface\n" "Interface name\n") DEFSH (0, access_list_standard_any_cmd_vtysh, "access-list (<1-99>|<1300-1999>) (deny|permit) any", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any source host\n") DEFSH (0, ospf_max_metric_router_lsa_admin_cmd_vtysh, "max-metric router-lsa administrative", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") DEFSH (0, access_list_extended_host_host_cmd_vtysh, "access-list (<100-199>|<2000-2699>) (deny|permit) ip host A.B.C.D host A.B.C.D", "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "A single source host\n" "Source address\n" "A single destination host\n" "Destination address\n") DEFSH (0, psnp_interval_cmd_vtysh, "isis psnp-interval <1-120>", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFSH (0, ipv6_nd_prefix_val_cmd_vtysh, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n") DEFSH (0, babel_split_horizon_cmd_vtysh, "babel split-horizon", "Babel interface commands\n" "Enable split horizon processing") DEFSH (0, dump_bgp_routes_cmd_vtysh, "dump bgp routes-mrt PATH", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n") DEFSH (0, no_neighbor_activate_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "activate", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Enable the Address Family for this Neighbor\n") DEFSH (0, no_debug_ospf6_message_cmd_vtysh, "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) DEFSH (0|0|0|0, show_ipv6_prefix_list_prefix_cmd_vtysh, "show ipv6 prefix-list WORD X:X::X:X/M", "Show running system information\n" "IPv6 information\n" "Build a prefix list\n" "Name of a prefix list\n" "IPv6 prefix /, e.g., 3ffe::/16\n") DEFSH (0, show_ip_pim_assert_cmd_vtysh, "show ip pim assert", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface assert\n") DEFSH (0, ip_route_flags_distance2_cmd_vtysh, "ip route A.B.C.D/M (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, ip_rip_send_version_2_cmd_vtysh, "ip rip send version 2 1", "IP information\n" "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 2\n" "RIP version 1\n") DEFSH (0, access_list_standard_nomask_cmd_vtysh, "access-list (<1-99>|<1300-1999>) (deny|permit) A.B.C.D", "Add an access list entry\n" "IP standard access list\n" "IP standard access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Address to match\n") DEFSH (0, no_ospf_rfc1583_flag_cmd_vtysh, "no ospf rfc1583compatibility", "Negate a command or set its defaults\n" "OSPF specific commands\n" "Disable the RFC1583Compatibility flag\n") DEFSH (0, no_debug_ospf6_abr_cmd_vtysh, "no debug ospf6 abr", "Negate a command or set its defaults\n" "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug OSPFv3 ABR function\n" ) DEFSH (0, no_ospf_abr_type_cmd_vtysh, "no ospf abr-type (cisco|ibm|shortcut|standard)", "Negate a command or set its defaults\n" "OSPF specific commands\n" "Set OSPF ABR type\n" "Alternative ABR, cisco implementation\n" "Alternative ABR, IBM implementation\n" "Shortcut ABR\n") DEFSH (0, debug_isis_rtevents_cmd_vtysh, "debug isis route-events", "Debugging functions (see also 'undebug')\n" "IS-IS information\n" "IS-IS Route related events\n") DEFSH (0, ip_mroute_dist_cmd_vtysh, "ip mroute A.B.C.D/M (A.B.C.D|INTERFACE) <1-255>", "IP information\n" "Configure static unicast route into MRIB for multicast RPF lookup\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Nexthop address\n" "Nexthop interface name\n" "Distance\n") DEFSH (0, ip_extcommunity_list_name_standard2_cmd_vtysh, "ip extcommunity-list standard WORD (deny|permit)", "IP information\n" "Add a extended community list entry\n" "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n") DEFSH (0, no_set_vpnv4_nexthop_cmd_vtysh, "no set vpnv4 next-hop", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "VPNv4 information\n" "VPNv4 next-hop address\n") DEFSH (0, no_router_rip_cmd_vtysh, "no router rip", "Negate a command or set its defaults\n" "Enable a routing process\n" "Routing Information Protocol (RIP)\n") DEFSH (0, ipv6_ospf6_instance_cmd_vtysh, "ipv6 ospf6 instance-id <0-255>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Instance ID for this interface\n" "Instance ID value\n" ) DEFSH (0, accept_lifetime_day_month_month_day_cmd_vtysh, "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> HH:MM:SS MONTH <1-31> <1993-2035>", "Set accept lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Time to expire\n" "Month of the year to expire\n" "Day of th month to expire\n" "Year to expire\n") DEFSH (0, no_ipv6_nd_prefix_cmd_vtysh, "no ipv6 nd prefix IPV6PREFIX", "Negate a command or set its defaults\n" "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFSH (0, show_ip_bgp_ipv4_community_exact_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, rip_default_metric_cmd_vtysh, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") DEFSH (0, no_ospf_opaque_capable_cmd_vtysh, "no ospf opaque-lsa", "Negate a command or set its defaults\n" "OSPF specific commands\n" "Disable the Opaque-LSA capability (rfc2370)\n") DEFSH (0, no_max_lsp_lifetime_l2_cmd_vtysh, "no max-lsp-lifetime level-2", "Negate a command or set its defaults\n" "LSP lifetime for Level 2 only in seconds\n") DEFSH (0|0, no_set_ip_nexthop_val_cmd_vtysh, "no set ip next-hop A.B.C.D", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IP information\n" "Next hop address\n" "IP address of next hop\n") DEFSH (0, undebug_bgp_zebra_cmd_vtysh, "undebug bgp zebra", "Disable debugging functions (see also 'debug')\n" "BGP information\n" "BGP Zebra messages\n") DEFSH (0, show_interface_desc_cmd_vtysh, "show interface description", "Show running system information\n" "Interface status and configuration\n" "Interface description\n") DEFSH (0, show_ip_rip_cmd_vtysh, "show ip rip", "Show running system information\n" "IP information\n" "Show RIP routes\n") DEFSH (0, no_bgp_redistribute_ipv4_metric_cmd_vtysh, "no redistribute " "(kernel|connected|static|rip|ospf|isis|pim|babel)" " metric <0-4294967295>", "Negate a command or set its defaults\n" "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol (RIP)\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, show_bgp_view_ipv6_route_cmd_vtysh, "show bgp view WORD ipv6 X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Network in the BGP routing table to display\n") DEFSH (0|0|0|0, no_match_ip_address_cmd_vtysh, "no match ip address", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match address of route\n") DEFSH (0, ipv6_nd_homeagent_config_flag_cmd_vtysh, "ipv6 nd home-agent-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") DEFSH (0, show_bgp_ipv6_route_cmd_vtysh, "show bgp ipv6 X:X::X:X", "Show running system information\n" "BGP information\n" "Address family\n" "Network in the BGP routing table to display\n") DEFSH (0, clear_bgp_ipv6_external_soft_out_cmd_vtysh, "clear bgp ipv6 external soft out", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFSH (0, bgp_redistribute_ipv6_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ripng|ospf6|isis|babel)" " metric <0-4294967295>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Routing Information Protocol next-generation (IPv6) (RIPng)\n" "Open Shortest Path First (IPv6) (OSPFv3)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Babel routing protocol (Babel)\n" "Metric for redistributed routes\n" "Default metric\n") DEFSH (0, undebug_igmp_trace_cmd_vtysh, "undebug igmp trace", "Disable debugging functions (see also 'debug')\n" "IGMP protocol activity\n" "IGMP internal daemon activity\n") DEFSH (0, show_bgp_community4_cmd_vtysh, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", "Show running system information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFSH (0, no_bgp_graceful_restart_cmd_vtysh, "no bgp graceful-restart", "Negate a command or set its defaults\n" "BGP specific commands\n" "Graceful restart capability parameters\n") DEFSH (0, neighbor_attr_unchanged1_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged (as-path|next-hop|med)", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") DEFSH (0, show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh, "show ip bgp ipv4 (unicast|multicast) rsclient summary", "Show running system information\n" "IP information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFSH (0, babel_set_update_interval_cmd_vtysh, "babel update-interval <20-655340>", "Babel interface commands\n" "Time between scheduled updates\n" "Milliseconds\n") DEFSH (0, ip_irdp_debug_packet_cmd_vtysh, "ip irdp debug packet", "IP information\n" "ICMP Router discovery debug Averts. and Solicits (short)\n") DEFSH (0, ip_route_flags_distance_cmd_vtysh, "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "IP gateway address\n" "IP gateway interface name\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, show_bgp_ipv6_summary_cmd_vtysh, "show bgp ipv6 summary", "Show running system information\n" "BGP information\n" "Address family\n" "Summary of BGP neighbor status\n") DEFSH (0, no_rip_neighbor_cmd_vtysh, "no neighbor A.B.C.D", "Negate a command or set its defaults\n" "Specify a neighbor router\n" "Neighbor address\n") DEFSH (0, no_bgp_network_mask_natural_cmd_vtysh, "no network A.B.C.D", "Negate a command or set its defaults\n" "Specify a network to announce via BGP\n" "Network number\n") DEFSH (0, show_debugging_ripng_cmd_vtysh, "show debugging ripng", "Show running system information\n" "Debugging functions (see also 'undebug')\n" "RIPng configuration\n") DEFSH (0, no_psnp_interval_l2_arg_cmd_vtysh, "no isis psnp-interval <1-120> level-2", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") DEFSH (0, no_ip_ospf_retransmit_interval_addr_cmd_vtysh, "no ip ospf retransmit-interval A.B.C.D", "Negate a command or set its defaults\n" "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Address of interface") DEFSH (0, neighbor_maximum_prefix_threshold_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n") DEFSH (0, ipv6_route_pref_cmd_vtysh, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", "IP information\n" "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" "IPv6 gateway address\n" "IPv6 gateway interface name\n" "Distance value for this prefix\n") DEFSH (0, show_bgp_rsclient_cmd_vtysh, "show bgp rsclient (A.B.C.D|X:X::X:X)", "Show running system information\n" "BGP information\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n") DEFSH (0, mpls_te_link_unrsv_bw_cmd_vtysh, "mpls-te link unrsv-bw <0-7> BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Unreserved bandwidth at each priority level\n" "Priority\n" "Bytes/second (IEEE floating point format)\n") DEFSH (0, neighbor_strict_capability_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X) " "strict-capability-match", "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Strict capability negotiation match\n") DEFSH (0, match_community_cmd_vtysh, "match community (<1-99>|<100-500>|WORD)", "Match values from routing table\n" "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") DEFSH (0, show_mpls_te_router_cmd_vtysh, "show mpls-te router", "Show running system information\n" "MPLS-TE information\n" "Router information\n") DEFSH (0, no_ospf_area_range_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n") DEFSH (0, show_ipv6_bgp_community_list_exact_cmd_vtysh, "show ipv6 bgp community-list WORD exact-match", "Show running system information\n" "IPv6 information\n" "BGP information\n" "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") DEFSH (0, clear_ip_bgp_all_rsclient_cmd_vtysh, "clear ip bgp * rsclient", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, show_ip_bgp_neighbors_peer_cmd_vtysh, "show ip bgp neighbors (A.B.C.D|X:X::X:X)", "Show running system information\n" "IP information\n" "BGP information\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFSH (0|0|0|0|0, match_interface_cmd_vtysh, "match interface WORD", "Match values from routing table\n" "match first hop interface of route\n" "Interface name\n") DEFSH (0, shutdown_if_cmd_vtysh, "shutdown", "Shutdown the selected interface\n") DEFSH (0, show_bgp_ipv4_safi_prefix_cmd_vtysh, "show bgp ipv4 (unicast|multicast) A.B.C.D/M", "Show running system information\n" "BGP information\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFSH (0|0, no_neighbor_maximum_prefix_warning_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> warning-only", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Only give warning message when limit is exceeded\n") DEFSH (0, show_ipv6_ospf6_cmd_vtysh, "show ipv6 ospf6", "Show running system information\n" "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n") DEFSH (0, ospf_area_range_cost_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFSH (0, rip_distance_source_access_list_cmd_vtysh, "distance <1-255> A.B.C.D/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") DEFSH (0, no_metric_style_cmd_vtysh, "no metric-style", "Negate a command or set its defaults\n" "Use old-style (ISO 10589) or new-style packet formats\n") DEFSH (0, ipv6_ospf6_deadinterval_cmd_vtysh, "ipv6 ospf6 dead-interval <1-65535>", "IPv6 Information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Interval time after which a neighbor is declared down\n" "<1-65535> Seconds\n" ) DEFSH (0, no_set_community_val_cmd_vtysh, "no set community .AA:NN", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP community attribute\n" "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") DEFSH (0, accept_lifetime_infinite_day_month_cmd_vtysh, "accept-lifetime HH:MM:SS <1-31> MONTH <1993-2035> infinite", "Set accept lifetime of the key\n" "Time to start\n" "Day of th month to start\n" "Month of the year to start\n" "Year to start\n" "Never expires") DEFSH (0, ospf_area_vlink_param2_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure a virtual link\n" "Router ID of the remote ABR\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Time between HELLO packets\n" "Time between retransmitting lost link state advertisements\n" "Link state transmit delay\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFSH (0, no_vty_access_class_cmd_vtysh, "no access-class [WORD]", "Negate a command or set its defaults\n" "Filter connections based on an IP access list\n" "IP access list\n") DEFSH (0, no_neighbor_attr_unchanged6_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "attribute-unchanged as-path med next-hop", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Med attribute\n" "Nexthop attribute\n") DEFSH (0, no_set_ipv6_nexthop_global_cmd_vtysh, "no set ipv6 next-hop global", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "IPv6 information\n" "IPv6 next-hop address\n" "IPv6 global address\n") DEFSH (0, ospf_message_digest_key_cmd_vtysh, "ospf message-digest-key <1-255> md5 KEY", "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFSH (0, show_ip_bgp_instance_summary_cmd_vtysh, "show ip bgp view WORD summary", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") DEFSH (0, no_neighbor_distribute_list_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Filter updates to/from this neighbor\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") DEFSH (0, no_psnp_interval_l1_arg_cmd_vtysh, "no isis psnp-interval <1-120> level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFSH (0, no_ripng_offset_list_ifname_cmd_vtysh, "no offset-list WORD (in|out) <0-16> IFNAME", "Negate a command or set its defaults\n" "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") DEFSH (0, show_ip_bgp_cidr_only_cmd_vtysh, "show ip bgp cidr-only", "Show running system information\n" "IP information\n" "BGP information\n" "Display only routes with non-natural netmasks\n") DEFSH (0, no_neighbor_advertise_interval_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "advertisement-interval <0-600>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "Minimum interval between sending BGP routing updates\n" "time in seconds\n") DEFSH (0, no_ip_extcommunity_list_name_expanded_all_cmd_vtysh, "no ip extcommunity-list expanded WORD", "Negate a command or set its defaults\n" "IP information\n" "Add a extended community list entry\n" "Specify expanded extcommunity-list\n" "Extended Community list name\n") DEFSH (0, show_ipv6_ospf6_database_cmd_vtysh, "show ipv6 ospf6 database", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" ) DEFSH (0, interface_ip_igmp_join_cmd_vtysh, "ip igmp join A.B.C.D A.B.C.D", "IP information\n" "Enable IGMP operation\n" "IGMP join multicast group\n" "Multicast group address\n" "Source address\n") DEFSH (0, clear_bgp_ipv6_peer_rsclient_cmd_vtysh, "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", "Reset functions\n" "BGP information\n" "Address family\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFSH (0, no_router_bgp_view_cmd_vtysh, "no router bgp " "<1-4294967295>" " view WORD", "Negate a command or set its defaults\n" "Enable a routing process\n" "BGP information\n" "AS number\n" "BGP view\n" "view name\n") DEFSH (0, no_neighbor_update_source_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "update-source", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Source of routing updates\n") DEFSH (0, aggregate_address_mask_cmd_vtysh, "aggregate-address A.B.C.D A.B.C.D", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n") DEFSH (0, no_isis_hello_multiplier_l1_cmd_vtysh, "no isis hello-multiplier level-1", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-1 IIHs\n") DEFSH (0, if_ipv6_rmap_cmd_vtysh, "route-map RMAP_NAME (in|out) IFNAME", "Route map set\n" "Route map name\n" "Route map set for input filtering\n" "Route map set for output filtering\n" "Route map interface name\n") DEFSH (0, neighbor_send_community_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "send-community", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Send Community attribute to this neighbor\n") DEFSH (0, no_lsp_refresh_interval_l1_cmd_vtysh, "no lsp-refresh-interval level-1", "Negate a command or set its defaults\n" "LSP refresh interval for Level 1 only in seconds\n") DEFSH (0, no_neighbor_timers_connect_val_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X) " "timers connect <0-65535>", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nIPv6 address\n" "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") DEFSH (0, show_ipv6_ospf6_database_detail_cmd_vtysh, "show ipv6 ospf6 database (detail|dump|internal)", "Show running system information\n" "IPv6 information\n" "Open Shortest Path First (OSPF) for IPv6\n" "Display Link state database\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFSH (0, ip_ospf_dead_interval_minimal_cmd_vtysh, "ip ospf dead-interval minimal hello-multiplier <1-10>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n") DEFSH (0, bgp_bestpath_aspath_ignore_cmd_vtysh, "bgp bestpath as-path ignore", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Ignore as-path length in selecting a route\n") DEFSH (0, no_ip_route_flags_distance2_cmd_vtysh, "no ip route A.B.C.D/M (reject|blackhole) <1-255>", "Negate a command or set its defaults\n" "IP information\n" "Establish static routes\n" "IP destination prefix (e.g. 10.0.0.0/8)\n" "Emit an ICMP unreachable when matched\n" "Silently discard pkts when matched\n" "Distance value for this route\n") DEFSH (0, show_ip_pim_jp_override_interval_cmd_vtysh, "show ip pim jp-override-interval", "Show running system information\n" "IP information\n" "PIM information\n" "PIM interface J/P override interval\n") DEFSH (0, no_bgp_default_ipv4_unicast_cmd_vtysh, "no bgp default ipv4-unicast", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") DEFSH (0, show_ip_bgp_view_neighbor_advertised_route_cmd_vtysh, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFSH (0, neighbor_capability_dynamic_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "capability dynamic", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Advertise capability to the peer\n" "Advertise dynamic capability to this neighbor\n") DEFSH (0, isis_passwd_clear_cmd_vtysh, "isis password clear WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") DEFSH (0, lsp_refresh_interval_cmd_vtysh, "lsp-refresh-interval <1-65235>", "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFSH (0, ip_ospf_transmit_delay_cmd_vtysh, "ip ospf transmit-delay <1-65535>", "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n") DEFSH (0, no_bgp_log_neighbor_changes_cmd_vtysh, "no bgp log-neighbor-changes", "Negate a command or set its defaults\n" "BGP specific commands\n" "Log neighbor up/down and reset reason\n") DEFSH (0|0|0|0, no_match_ip_next_hop_prefix_list_val_cmd_vtysh, "no match ip next-hop prefix-list WORD", "Negate a command or set its defaults\n" "Match values from routing table\n" "IP information\n" "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFSH (0, ipv6_ripng_split_horizon_cmd_vtysh, "ipv6 ripng split-horizon", "IPv6 information\n" "Routing Information Protocol\n" "Perform split horizon\n") DEFSH (0, rip_redistribute_type_metric_cmd_vtysh, "redistribute " "(kernel|connected|static|ospf|isis|bgp|pim|babel)" " metric <0-16>", "Redistribute information from another routing protocol\n" "Kernel routes (not installed via the zebra RIB)\n" "Connected routes (directly attached subnet or host)\n" "Statically configured routes\n" "Open Shortest Path First (OSPFv2)\n" "Intermediate System to Intermediate System (IS-IS)\n" "Border Gateway Protocol (BGP)\n" "Protocol Independent Multicast (PIM)\n" "Babel routing protocol (Babel)\n" "Metric\n" "Metric value\n") DEFSH (0, no_isis_priority_arg_cmd_vtysh, "no isis priority <0-127>", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFSH (0, exec_timeout_min_cmd_vtysh, "exec-timeout <0-35791>", "Set timeout value\n" "Timeout value in minutes\n") DEFSH (0, no_bgp_scan_time_val_cmd_vtysh, "no bgp scan-time <5-60>", "Negate a command or set its defaults\n" "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") DEFSH (0, no_ospf_area_range_advertise_cmd_vtysh, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)", "Negate a command or set its defaults\n" "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "DoNotAdvertise this range\n") DEFSH (0, show_ip_bgp_community2_exact_cmd_vtysh, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", "Show running system information\n" "IP information\n" "BGP information\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFSH (0, no_access_list_extended_mask_any_cmd_vtysh, "no access-list (<100-199>|<2000-2699>) (deny|permit) ip A.B.C.D A.B.C.D any", "Negate a command or set its defaults\n" "Add an access list entry\n" "IP extended access list\n" "IP extended access list (expanded range)\n" "Specify packets to reject\n" "Specify packets to forward\n" "Any Internet Protocol\n" "Source address\n" "Source wildcard bits\n" "Any destination host\n") DEFSH (0, no_bgp_distance_cmd_vtysh, "no distance bgp <1-255> <1-255> <1-255>", "Negate a command or set its defaults\n" "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") DEFSH (0, ospf_area_authentication_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) authentication", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n") DEFSH (0, debug_ospf6_spf_process_cmd_vtysh, "debug ospf6 spf process", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug SPF Calculation\n" "Debug Detailed SPF Process\n" ) DEFSH (0, address_family_ipv6_safi_cmd_vtysh, "address-family ipv6 (unicast|multicast)", "Enter Address Family command mode\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFSH (0, csnp_interval_l1_cmd_vtysh, "isis csnp-interval <1-600> level-1", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFSH (0, debug_pim_events_cmd_vtysh, "debug pim events", "Debugging functions (see also 'undebug')\n" "PIM protocol activity\n" "PIM protocol events\n") DEFSH (0, no_set_ecommunity_soo_cmd_vtysh, "no set extcommunity soo", "Negate a command or set its defaults\n" "Set values in destination routing protocol\n" "BGP extended community attribute\n" "Site-of-Origin extended community\n") DEFSH (0, net_cmd_vtysh, "net WORD", "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") DEFSH (0, no_isis_hello_interval_cmd_vtysh, "no isis hello-interval", "Negate a command or set its defaults\n" "IS-IS commands\n" "Set Hello interval\n") DEFSH (0, ospf_area_nssa_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) nssa", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n") DEFSH (0, neighbor_maximum_prefix_threshold_restart_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") DEFSH (0, ospf_area_range_cmd_vtysh, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n") DEFSH (0, neighbor_default_originate_rmap_cmd_vtysh, "neighbor (A.B.C.D|X:X::X:X|WORD) " "default-originate route-map WORD", "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Originate default route to this neighbor\n" "Route-map to specify criteria to originate default\n" "route-map name\n") DEFSH (0|0|0|0|0|0, no_rmap_onmatch_next_cmd_vtysh, "no on-match next", "Negate a command or set its defaults\n" "Exit policy on matches\n" "Next clause\n") DEFSH (0, show_bgp_statistics_cmd_vtysh, "show bgp (ipv4|ipv6) (unicast|multicast) statistics", "Show running system information\n" "BGP information\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFSH (0, clear_ip_bgp_all_in_cmd_vtysh, "clear ip bgp * in", "Reset functions\n" "IP information\n" "BGP information\n" "Clear all peers\n" "Soft reconfig inbound update\n") DEFSH (0, no_neighbor_maximum_prefix_cmd_vtysh, "no neighbor (A.B.C.D|X:X::X:X|WORD) " "maximum-prefix", "Negate a command or set its defaults\n" "Specify neighbor router\n" "Neighbor address\nNeighbor IPv6 address\nNeighbor tag\n" "Maximum number of prefix accept from this peer\n") DEFSH (0, show_database_detail_cmd_vtysh, "show isis database detail", "Show running system information\n" "IS-IS information\n" "IS-IS link state database\n") DEFSH (0, clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh, "clear bgp ipv6 peer-group WORD soft in", "Reset functions\n" "BGP information\n" "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") DEFSH (0, rip_distance_cmd_vtysh, "distance <1-255>", "Administrative distance\n" "Distance value\n") DEFSH (0, show_ip_bgp_instance_ipv4_summary_cmd_vtysh, "show ip bgp view WORD ipv4 (unicast|multicast) summary", "Show running system information\n" "IP information\n" "BGP information\n" "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFSH (0, debug_ospf6_brouter_cmd_vtysh, "debug ospf6 border-routers", "Debugging functions (see also 'undebug')\n" "Open Shortest Path First (OSPF) for IPv6\n" "Debug border router\n" ) DEFSH (0, show_bgp_view_rsclient_route_cmd_vtysh, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", "Show running system information\n" "BGP information\n" "BGP view\n" "View name\n" "Information about Route Server Client\n" "Neighbor address\nIPv6 address\n" "Network in the BGP routing table to display\n") DEFSH (0, show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh, "show ip bgp vpnv4 all neighbors A.B.C.D routes", "Show running system information\n" "IP information\n" "BGP information\n" "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFSH (0, area_passwd_md5_cmd_vtysh, "area-password md5 WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") DEFSH (0, clear_bgp_instance_all_soft_cmd_vtysh, "clear bgp view WORD * soft", "Reset functions\n" "BGP information\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") DEFSH (0, debug_zebra_packet_detail_cmd_vtysh, "debug zebra packet (recv|send) detail", "Debugging functions (see also 'undebug')\n" "Zebra configuration\n" "Debug option set for zebra packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n" "Debug option set detailed information\n") DEFSH (0, match_peer_local_cmd_vtysh, "match peer local", "Match values from routing table\n" "Match peer address\n" "Static or Redistributed routes\n") void test_init_cmd () { install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_packet_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spftrigg_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_access_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_l1_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd_vtysh); install_element (ENABLE_NODE, &undebug_ssmpingd_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_rib_q_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_addr_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_network_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_filter_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd_vtysh); install_element (BGP_NODE, &bgp_scan_time_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_events_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_snp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd_vtysh); install_element (ENABLE_NODE, &show_babel_database_cmd_vtysh); install_element (BGP_NODE, &neighbor_description_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_rib_q_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_information_originate_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_host_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_area_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packetdump_recv_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_description_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_any_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_access_list_name_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_address_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_router_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_as_path_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_host_cmd_vtysh); install_element (VTY_NODE, &vty_ipv6_access_class_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd_vtysh); install_element (VIEW_NODE, &show_database_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_u32_cmd_vtysh); install_element (BABEL_NODE, &no_babel_network_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd_vtysh); install_element (RMAP_NODE, &set_origin_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_addr_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd_vtysh); install_element (CONFIG_NODE, &no_service_advanced_vty_cmd_vtysh); install_element (OSPF6_NODE, &area_range_advertise_cmd_vtysh); install_element (BGP_NODE, &no_bgp_router_id_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_offset_list_ifname_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_day_month_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_prune_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_packet_cmd_vtysh); install_element (ISIS_NODE, &no_set_overload_bit_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_mroute_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_secondary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd_vtysh); install_element (RMAP_NODE, &no_set_aggregator_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_dump_bgp_all_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_cmd_vtysh); install_element (ENABLE_NODE, &show_database_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_metric_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_client_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (OSPF6_NODE, &no_area_export_list_cmd_vtysh); install_element (ENABLE_NODE, &show_hostname_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_events_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_trace_cmd_vtysh); install_element (OSPF_NODE, &ospf_timers_throttle_spf_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_inet4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh); install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_events_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_password_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_cmd_vtysh); install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_kernel_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_rsclient_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh); install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_groups_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_shutdown_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_passive_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_md5_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd_vtysh); install_element (OSPF6_NODE, &no_area_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd_vtysh); install_element (CONFIG_NODE, &no_router_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_abr_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_cmd_vtysh); install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd_vtysh); install_element (BGP_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_port_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_cmd_vtysh); install_element (RMAP_NODE, &set_aggregator_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_priority_cmd_vtysh); install_element (ENABLE_NODE, &debug_babel_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_priority_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_ospf_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_authlen_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd_vtysh); install_element (RIP_NODE, &no_rip_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &key_string_cmd_vtysh); install_element (BGP_NODE, &neighbor_shutdown_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_NODE, &neighbor_strict_capability_cmd_vtysh); install_element (BGP_NODE, &neighbor_advertise_interval_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (RMAP_NODE, &match_ipv6_address_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param1_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_summary_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd_vtysh); install_element (RIP_NODE, &rip_default_information_originate_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_authentication_message_digest_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_zebra_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd_vtysh); install_element (VTY_NODE, &vty_restricted_mode_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_ip_multicast_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_multicast_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_shutdown_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_pref_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd_vtysh); install_element (VIEW_NODE, &show_database_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd_vtysh); install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd_vtysh); install_element (BGP_NODE, &bgp_router_id_cmd_vtysh); install_element (RIP_NODE, &if_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_jp_override_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd_vtysh); install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_multicast_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh); install_element (OSPF_NODE, &no_router_ospf_id_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_lupd_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_override_capability_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_cmd_vtysh); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_interval_cmd_vtysh); install_element (RMAP_NODE, &no_match_origin_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_mask_any_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_remark_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_metric_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_self_originated_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_normal_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_source_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd_vtysh); install_element (RMAP_NODE, &match_metric_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_prefix_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); install_element (ISIS_NODE, &no_net_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_l1_cmd_vtysh); install_element (CONFIG_NODE, &no_router_rip_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_topology_l1_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_ism_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd_vtysh); install_element (INTERFACE_NODE, &ip_address_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_onmatch_goto_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_interface_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community3_cmd_vtysh); install_element (RIPNG_NODE, &ripng_offset_list_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_router_isis_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_any_cmd_vtysh); install_element (INTERFACE_NODE, &babel_set_update_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_priority_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_trace_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_prefix_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_packets_cmd_vtysh); install_element (RMAP_NODE, &no_match_interface_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd_vtysh); install_element (RIP_NODE, &no_rip_version_val_cmd_vtysh); install_element (ISIS_NODE, &net_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_route_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_le_ge_cmd_vtysh); install_element (INTERFACE_NODE, &isis_passwd_clear_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ripng_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd_vtysh); install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rib_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd_vtysh); install_element (RIP_NODE, &rip_version_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_mask_cmd_vtysh); install_element (RMAP_NODE, &match_ecommunity_cmd_vtysh); install_element (ISIS_NODE, &no_area_passwd_cmd_vtysh); install_element (RIPNG_NODE, &if_ipv6_rmap_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd_vtysh); install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_lsa_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VTY_NODE, &vty_no_restricted_mode_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_host_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd_vtysh); install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_day_month_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packetdump_recv_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_events_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_cmd_vtysh); install_element (BGP_NODE, &neighbor_disable_connected_check_cmd_vtysh); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_detail_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_groups_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_cost_u32_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_zebra_cmd_vtysh); install_element (OSPF6_NODE, &area_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_shutdown_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_groups_retransmissions_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community4_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_filter_list_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_all_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_le_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_sequence_number_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_event_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_rib_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_kernel_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd_vtysh); install_element (INTERFACE_NODE, &linkdetect_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (INTERFACE_NODE, &ip_router_isis_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_route_cmd_vtysh); install_element (CONFIG_NODE, &bgp_config_type_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_misc_cmd_vtysh); install_element (RMAP_NODE, &rmap_description_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_routes_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_day_month_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_stub_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_routemap_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (RIP_NODE, &no_rip_default_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_cmd_vtysh); install_element (BGP_NODE, &no_bgp_router_id_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_addr_cmd_vtysh); install_element (ENABLE_NODE, &show_interface_desc_cmd_vtysh); install_element (CONFIG_NODE, &access_list_remark_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd_vtysh); install_element (RMAP_NODE, &no_set_local_pref_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param3_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_detail_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_onmatch_next_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh); install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_stub_router_admin_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd_vtysh); install_element (ENABLE_NODE, &show_version_ospf6_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_rib_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh); install_element (RIPNG_NODE, &ripng_passive_interface_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd_vtysh); install_element (CONFIG_NODE, &no_router_babel_cmd_vtysh); install_element (BGP_NODE, &bgp_confederation_identifier_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_upcall_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_prefix_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_val_cmd_vtysh); install_element (RMAP_NODE, &set_ecommunity_rt_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_host_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd_vtysh); install_element (BGP_NODE, &bgp_fast_external_failover_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_prepend_cmd_vtysh); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd_vtysh); install_element (RMAP_NODE, &no_set_local_pref_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_u32_inet4_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community4_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_packet_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_router_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_memory_cmd_vtysh); install_element (RMAP_NODE, &set_atomic_aggregate_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh); install_element (OSPF6_NODE, &auto_cost_reference_bandwidth_cmd_vtysh); install_element (RMAP_NODE, &set_community_none_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (BGP_NODE, &no_bgp_cluster_id_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_address_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_cmd_vtysh); install_element (BGP_NODE, &no_auto_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (CONFIG_NODE, &debug_mroute_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd_vtysh); install_element (INTERFACE_NODE, &no_linkdetect_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_packets_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_mpls_te_link_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_confed_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd_vtysh); install_element (BGP_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd_vtysh); install_element (VTY_NODE, &no_exec_timeout_cmd_vtysh); install_element (CONFIG_NODE, &no_route_map_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_ge_le_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_l1_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_fpm_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_events_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_mroute_count_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spfevents_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_not_advertise_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_arg_cmd_vtysh); install_element (ISIS_NODE, &metric_style_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_protocol_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_any_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_packet_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_lupd_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_inet4_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packetdump_recv_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_startup_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_out_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_network_cmd_vtysh); install_element (ISIS_NODE, &no_metric_style_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_stub_no_summary_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_self_originated_detail_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_clear_cmd_vtysh); install_element (VIEW_NODE, &show_zebra_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_views_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_detail_cmd_vtysh); install_element (BGP_NODE, &neighbor_password_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_priority_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd_vtysh); install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_snp_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_filter_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (RMAP_NODE, &no_match_ecommunity_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_snp_cmd_vtysh); install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_packets_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd_vtysh); install_element (BGP_NODE, &bgp_network_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_mask_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community3_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (CONFIG_NODE, &debug_igmp_trace_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_cost_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_local_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &no_key_chain_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_events_cmd_vtysh); install_element (VIEW_NODE, &clear_isis_neighbor_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_events_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_router_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_router_detail_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_rib_cmd_vtysh); install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd_vtysh); install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); install_element (CONFIG_NODE, &access_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance2_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_le_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_self_originated_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_ge_le_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_forwarding_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_address_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_access_list_cmd_vtysh); install_element (BGP_NODE, &no_bgp_scan_time_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_as4_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh); install_element (ENABLE_NODE, &show_table_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd_vtysh); install_element (CONFIG_NODE, &debug_babel_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_trace_cmd_vtysh); install_element (RIP_NODE, &no_rip_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_regexp_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spfevents_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_remark_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ripng_cmd_vtysh); install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_zebra_cmd_vtysh); install_element (BGP_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_hello_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_no_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (VIEW_NODE, &show_babel_parameters_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd_vtysh); install_element (ENABLE_NODE, &show_babel_parameters_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_name_seq_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_self_originated_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_snp_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_infinite_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_err_cmd_vtysh); install_element (VTY_NODE, &exec_timeout_sec_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd_vtysh); install_element (OSPF_NODE, &ospf_abr_type_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_upstream_rpf_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_events_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_expanded_all_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_standard2_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_hello_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_any_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_authlen_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_hello_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_interface_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh); install_element (RIP_NODE, &rip_neighbor_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_exclude_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_events_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_description_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param2_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_assert_winner_metric_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_protocol_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_rib_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_forwarding_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_sequence_number_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_rpf_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_igmp_interfaces_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_summary_cmd_vtysh); install_element (OSPF_NODE, &no_mpls_te_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_distance_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &debug_ssmpingd_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd_vtysh); install_element (VIEW_NODE, &show_ip_mroute_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_disable_cmd_vtysh); install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_topology_cmd_vtysh); install_element (CONFIG_NODE, &ip_multicast_routing_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_community_list_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags2_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_network_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_in_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_nomask_cmd_vtysh); install_element (VIEW_NODE, &show_table_cmd_vtysh); install_element (ENABLE_NODE, &show_database_arg_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_le_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_querier_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd_vtysh); install_element (BGP_NODE, &no_bgp_timers_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param2_cmd_vtysh); install_element (INTERFACE_NODE, &babel_set_wired_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_forwarding_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_le_cmd_vtysh); install_element (RMAP_NODE, &no_set_tag_val_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_month_day_month_day_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param4_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd_vtysh); install_element (ENABLE_NODE, &show_interface_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_hello_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community3_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_forwarding_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_cmd_vtysh); install_element (BGP_NODE, &neighbor_timers_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_paths_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_ripng_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_all_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_stub_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_day_month_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_interface_detail_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_messages_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_router_isis_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_detail_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_sources_retransmissions_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nsm_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_interval_cmd_vtysh); install_element (RMAP_NODE, &match_interface_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_cmd_vtysh); install_element (RIP_NODE, &rip_network_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_events_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_views_cmd_vtysh); install_element (OSPF_NODE, &router_ospf_id_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_linkstate_id_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_pim_interfaces_cmd_vtysh); install_element (RMAP_NODE, &rmap_call_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd_vtysh); install_element (RMAP_NODE, &no_set_originator_id_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_passwd_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_supernets_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_rpf_cmd_vtysh); install_element (ENABLE_NODE, &test_igmp_receive_report_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd_vtysh); install_element (VTY_NODE, &vty_login_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_sources_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_passive_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_events_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set2_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_exact_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_description_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_route_map_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd_vtysh); install_element (ZEBRA_NODE, &redistribute_ospf6_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_addr_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packets_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_authentication_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_month_day_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_assert_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (ISIS_NODE, &log_adj_changes_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_router_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_flags_pref_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_cost_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_dump_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_preference_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_protocol_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_access_list_name_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cost_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_linkstate_id_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_string_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community2_exact_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_cmd_vtysh); install_element (RMAP_NODE, &no_match_aspath_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbors_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_stub_no_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_internal_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_origin_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_disable_connected_check_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_unset2_cmd_vtysh); install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_any_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_ge_le_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_trace_cmd_vtysh); install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd_vtysh); install_element (BGP_NODE, &bgp_cluster_id_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_debug_packet_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_events_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_rtevents_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_shortcut_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_kernel_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ssmpingd_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_le_cmd_vtysh); install_element (INTERFACE_NODE, &isis_passwd_md5_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_adj_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_addr_cmd_vtysh); install_element (INTERFACE_NODE, &ip_address_label_cmd_vtysh); install_element (RMAP_NODE, &match_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_babel_interface_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (INTERFACE_NODE, &babel_split_horizon_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_address_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_shortcut_cmd_vtysh); install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_l2_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_update_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance2_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_groups_retransmissions_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_infinite_month_day_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_default_cmd_vtysh); install_element (RMAP_NODE, &no_match_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_export_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd_vtysh); install_element (RIP_NODE, &rip_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community2_cmd_vtysh); install_element (OSPF_NODE, &mpls_te_router_addr_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd_vtysh); install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (BGP_NODE, &neighbor_timers_connect_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (INTERFACE_NODE, &babel_set_hello_interval_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd_vtysh); install_element (ISIS_NODE, &no_domain_passwd_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_bgp_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_ripng_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_routemap_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd_vtysh); install_element (BABEL_NODE, &babel_network_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_duration_day_month_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spfstats_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_events_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_events_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_standard_host_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_mtu_ignore_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_addr_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_expanded_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_strict_capability_cmd_vtysh); install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_month_day_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_summary_name_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_authkey_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_winner_metric_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_zebra_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_name_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_rib_q_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd_vtysh); install_element (BGP_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_md5_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_update_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd_vtysh); install_element (BGP_NODE, &neighbor_update_source_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_trace_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh); install_element (RMAP_NODE, &no_match_aspath_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_adj_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_day_month_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community_list_cmd_vtysh); install_element (OSPF_NODE, &ospf_log_adjacency_changes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_events_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_trace_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_rib_q_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_update_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_offset_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd_vtysh); install_element (RMAP_NODE, &no_set_weight_val_cmd_vtysh); install_element (BGP_NODE, &neighbor_override_capability_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community_exact_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_local_membership_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (VIEW_NODE, &show_isis_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_detail_cmd_vtysh); install_element (RMAP_NODE, &match_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_babel_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd_vtysh); install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd_vtysh); install_element (OSPF_NODE, &ospf_opaque_capable_cmd_vtysh); install_element (OSPF6_NODE, &no_area_range_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_interface_area_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_lupd_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_rtevents_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_lsa_cmd_vtysh); install_element (VTY_NODE, &no_vty_login_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_route_map_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_sources_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_md5_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mroute_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd_vtysh); install_element (ENABLE_NODE, &show_babel_neighbour_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_ge_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_router_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_views_cmd_vtysh); install_element (CONFIG_NODE, &config_table_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_zebra_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_padding_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd_vtysh); install_element (BGP_NODE, &bgp_maxpaths_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd_vtysh); install_element (VIEW_NODE, &show_version_ospf6_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_err_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_memory_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (CONFIG_NODE, &ip_multicast_mode_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_updates_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_message_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd_vtysh); install_element (CONFIG_NODE, &access_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags2_cmd_vtysh); install_element (RIPNG_NODE, &ripng_route_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_authentication_key_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_spfevents_cmd_vtysh); install_element (RIP_NODE, &no_if_rmap_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_any_mask_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_supernets_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_abr_type_cmd_vtysh); install_element (CONFIG_NODE, &no_router_id_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_priority_poll_interval_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spftrigg_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_NODE, &no_bgp_deterministic_med_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_substitute_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd_vtysh); install_element (RIP_NODE, &rip_allow_ecmp_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_router_detail_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_advertise_cost_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (BABEL_NODE, &babel_redistribute_type_cmd_vtysh); install_element (BABEL_NODE, &no_babel_redistribute_type_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd_vtysh); install_element (KEYCHAIN_NODE, &no_key_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_rpf_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_csum_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_description_cmd_vtysh); install_element (CONFIG_NODE, &access_list_any_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_month_day_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_events_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_dsec_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_NODE, &bgp_network_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packets_cmd_vtysh); install_element (BGP_NODE, &bgp_deterministic_med_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd_vtysh); install_element (BGP_NODE, &neighbor_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_param3_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_err_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_packets_filter_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_duration_day_month_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd_vtysh); install_element (RMAP_NODE, &set_local_pref_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_area_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd_vtysh); install_element (CONFIG_NODE, &debug_ssmpingd_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd_vtysh); install_element (RIPNG_NODE, &ripng_timers_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_cost_u32_inet4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_interface_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd_vtysh); install_element (ISIS_NODE, &no_log_adj_changes_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_scan_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_detail_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ssmpingd_cmd_vtysh); install_element (ISIS_NODE, &dynamic_hostname_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_dsec_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd_vtysh); install_element (ISIS_NODE, &set_overload_bit_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags_distance_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_zebra_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ospf6_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_mpls_te_link_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_route_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_query_max_response_time_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_jp_override_interval_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_linkstate_id_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_message_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_range_advertise_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd_vtysh); install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_cmd_vtysh); install_element (BGP_NODE, &bgp_default_local_preference_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (OSPF_NODE, &ospf_neighbor_priority_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_distance_cmd_vtysh); install_element (VIEW_NODE, &show_debugging_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd_vtysh); install_element (RIP_NODE, &rip_distance_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community2_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_authkey_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packets_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_pim_oil_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_network_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_router_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd_vtysh); install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packets_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_router_id_cmd_vtysh); install_element (OSPF_NODE, &mpls_te_on_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_route_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_csum_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_interface_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_route_map_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_redistribute_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l1_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_sources_retransmissions_cmd_vtysh); install_element (RIPNG_NODE, &no_if_ipv6_rmap_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_brouter_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_events_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_babel_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (OSPF_NODE, &ospf_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); install_element (RMAP_NODE, &set_community_delete_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_interface_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_packets_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_assert_metric_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spfevents_cmd_vtysh); install_element (RMAP_NODE, &set_ip_nexthop_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mroute_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l2_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_metric_routemap_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_authkey_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_linkstate_id_detail_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param4_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_pim_ssm_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (RIP_NODE, &no_rip_version_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_mask_host_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_timers_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_as_path_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_zebra_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_cmd_vtysh); install_element (BGP_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd_vtysh); install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_local_membership_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd_vtysh); install_element (RMAP_NODE, &no_set_weight_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_send_version_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_fpm_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_trace_cmd_vtysh); install_element (RIP_NODE, &rip_default_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd_vtysh); install_element (RMAP_NODE, &no_set_src_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_events_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); install_element (BGP_NODE, &no_bgp_timers_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_packetdump_send_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_join_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_in_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_description_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd_vtysh); install_element (RIP_NODE, &rip_redistribute_type_metric_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd_vtysh); install_element (RIP_NODE, &no_rip_offset_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_nssa_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd_vtysh); install_element (RMAP_NODE, &set_weight_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_forwarding_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd_vtysh); install_element (RMAP_NODE, &no_match_tag_val_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_import_check_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_events_cmd_vtysh); install_element (VIEW_NODE, &show_database_detail_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd_vtysh); install_element (RMAP_NODE, &set_originator_id_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_detail_cmd_vtysh); install_element (RMAP_NODE, &set_metric_addsub_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd_vtysh); install_element (OSPF_NODE, &capability_opaque_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community4_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd_vtysh); install_element (INTERFACE_NODE, &isis_network_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_summary_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (RMAP_NODE, &match_community_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_ge_le_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_mtu_ignore_cmd_vtysh); install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd_vtysh); install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (CONFIG_NODE, &ip_protocol_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_normal_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_first_match_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_router_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd_vtysh); install_element (BGP_NODE, &bgp_enforce_first_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_zebra_fpm_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_err_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd_vtysh); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (ENABLE_NODE, &show_debugging_rip_cmd_vtysh); install_element (CONFIG_NODE, &router_id_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_fpm_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_neighbor_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (OSPF_NODE, &mpls_te_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_packetdump_send_cmd_vtysh); install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_router_id_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_lupd_cmd_vtysh); install_element (INTERFACE_NODE, &no_shutdown_if_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_events_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_translate_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_connect_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_host_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_any_cmd_vtysh); install_element (RIP_NODE, &rip_passive_interface_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_delete_val_cmd_vtysh); install_element (VTY_NODE, &vty_access_class_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd_vtysh); install_element (RIPNG_NODE, &ripng_network_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_parameters_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_forwarding_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_source_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_cmd_vtysh); install_element (CONFIG_NODE, &bgp_multiple_instance_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (CONFIG_NODE, &access_list_standard_nomask_cmd_vtysh); install_element (RIP_NODE, &no_rip_passive_interface_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_authkey_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_events_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authkey_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_bandwidth_if_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_upd_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd_vtysh); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_routemap_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_remote_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_isis_neighbor_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd_vtysh); install_element (OSPF_NODE, &ospf_distance_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rpf_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_timers_cmd_vtysh); install_element (BGP_NODE, &bgp_network_backdoor_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_name_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_network_area_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_router_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_zebra_packet_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_querier_cmd_vtysh); install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_assert_internal_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_packets_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_linkstate_id_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_weight_val_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_update_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_protocol_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_name_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_summary_cmd_vtysh); install_element (RMAP_NODE, &match_aspath_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_source_access_list_cmd_vtysh); install_element (RMAP_NODE, &rmap_onmatch_next_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_join_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_adv_router_cmd_vtysh); install_element (ENABLE_NODE, &debug_mroute_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd_vtysh); install_element (RMAP_NODE, &no_match_probability_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_mode_noarg_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd_vtysh); install_element (RIPNG_NODE, &ripng_default_information_originate_cmd_vtysh); install_element (BGP_NODE, &neighbor_remote_as_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ip_route_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_adv_router_detail_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_update_source_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd_vtysh); install_element (ISIS_NODE, &spf_interval_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_rib_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (CONFIG_NODE, &no_router_bgp_view_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_param1_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_igmp_events_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_remark_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd_vtysh); install_element (OSPF6_NODE, &area_range_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_timers_throttle_spf_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd_vtysh); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd_vtysh); install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd_vtysh); install_element (BGP_NODE, &address_family_ipv6_safi_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_packets_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_join_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (KEYCHAIN_NODE, &no_key_chain_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_irdp_address_preference_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_fsm_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_peer_group_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &accept_lifetime_day_month_month_day_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_topology_l2_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_cmd_vtysh); install_element (VIEW_NODE, &show_babel_database_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_lan_prune_delay_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_filter_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spfstats_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_cmd_vtysh); install_element (BGP_NODE, &neighbor_passive_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_interface_cmd_vtysh); install_element (CONFIG_NODE, &service_advanced_vty_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd_vtysh); install_element (RMAP_NODE, &set_community_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_dr_cmd_vtysh); install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd_vtysh); install_element (RIP_NODE, &rip_timers_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_events_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_timers_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_fsm_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_bgp_events_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd_vtysh); install_element (BGP_NODE, &bgp_network_import_check_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distance_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd_vtysh); install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_pim_packets_filter_cmd_vtysh); install_element (RMAP_NODE, &set_aspath_exclude_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_vlink_authtype_md5_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_adv_router_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_packet_cmd_vtysh); install_element (BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_detail_name_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_events_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_default_cost_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_none_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (VIEW_NODE, &show_ip_community_list_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_secondary_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd_vtysh); install_element (ENABLE_NODE, &show_mpls_te_router_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_adv_router_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_neighbor_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_ge_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (ISIS_NODE, &no_dynamic_hostname_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd_vtysh); install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ssmpingd_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_local_preference_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_call_cmd_vtysh); install_element (INTERFACE_NODE, &multicast_cmd_vtysh); install_element (BGP_NODE, &no_bgp_distance_source_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (BGP_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_zebra_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (ISIS_NODE, &area_passwd_md5_cmd_vtysh); install_element (ISIS_NODE, &no_is_type_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_prefix_list_detail_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_host_any_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_name_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rip_status_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd_vtysh); install_element (OSPF_NODE, &ospf_router_id_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_router_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_cmd_vtysh); install_element (RMAP_NODE, &no_set_originator_id_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_upd_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_chain_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ipv6_prefix_list_name_prefix_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &no_key_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_spftrigg_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_cmd_vtysh); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_packet_direct_cmd_vtysh); install_element (RMAP_NODE, &match_ip_route_source_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd_vtysh); install_element (CONFIG_NODE, &debug_ripng_zebra_cmd_vtysh); install_element (BGP_NODE, &bgp_always_compare_med_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_day_month_day_month_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd_vtysh); install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_in_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spfstats_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (BGP_NODE, &bgp_bestpath_med3_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_spftrigg_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_l1_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd_vtysh); install_element (ISIS_NODE, &lsp_gen_interval_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_flags2_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (BGP_NODE, &no_bgp_always_compare_med_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_cost_inet4_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd_vtysh); install_element (BGP_NODE, &neighbor_default_originate_cmd_vtysh); install_element (BGP_NODE, &bgp_confederation_peers_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd_vtysh); install_element (ISIS_NODE, &domain_passwd_clear_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_assert_metric_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd_vtysh); install_element (RMAP_NODE, &rmap_continue_index_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_l1_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_event_cmd_vtysh); install_element (OSPF_NODE, &ospf_log_adjacency_changes_detail_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd_vtysh); install_element (CONFIG_NODE, &no_router_bgp_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd_vtysh); install_element (ISIS_NODE, &no_spf_interval_arg_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd_vtysh); install_element (BGP_NODE, &neighbor_activate_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_val_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_nssa_translate_no_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_le_ge_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_mode_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_l2_cmd_vtysh); install_element (OSPF6_NODE, &area_export_list_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd_vtysh); install_element (ENABLE_NODE, &test_pim_receive_join_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_cmd_vtysh); install_element (CONFIG_NODE, &debug_pim_packets_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_csum_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_ge_le_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_event_cmd_vtysh); install_element (BGP_NODE, &bgp_timers_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd_vtysh); install_element (BGP_NODE, &neighbor_route_map_cmd_vtysh); install_element (RMAP_NODE, &match_tag_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd_vtysh); install_element (RMAP_NODE, &match_peer_local_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_lan_prune_delay_cmd_vtysh); install_element (RIP_NODE, &rip_offset_list_ifname_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_import_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_interface_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_tag_cmd_vtysh); install_element (RMAP_NODE, &match_ip_address_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packetdump_send_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_events_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_mask_host_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_all_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_pim_packets_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_le_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_join_desired_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_event_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd_vtysh); install_element (RMAP_NODE, &no_match_probability_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_longer_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (RMAP_NODE, &rmap_onmatch_goto_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_upstream_cmd_vtysh); install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_export_list_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_detail_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_backdoor_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd_vtysh); install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_mask_cmd_vtysh); install_element (RMAP_NODE, &no_rmap_continue_cmd_vtysh); install_element (CONFIG_NODE, &undebug_igmp_trace_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd_vtysh); install_element (CONFIG_NODE, &ip_community_list_standard_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd_vtysh); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_rip_cmd_vtysh); install_element (CONFIG_NODE, &ip_mroute_dist_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_dr_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_packet_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd_vtysh); install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_first_match_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_rpf_cmd_vtysh); install_element (BGP_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd_vtysh); install_element (VTY_NODE, &no_vty_access_class_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_import_list_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_database_arg_detail_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_le_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_route_server_client_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_inet4_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_events_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_shutdown_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_range_substitute_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd_vtysh); install_element (VIEW_NODE, &show_ip_community_list_cmd_vtysh); install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_redistribute_type_routemap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_description_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_default_cost_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_cmd_vtysh); install_element (ENABLE_NODE, &show_babel_interface_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_summary_prefix_cmd_vtysh); install_element (OSPF_NODE, &ospf_network_area_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_parameters_cmd_vtysh); install_element (INTERFACE_NODE, &shutdown_if_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd_vtysh); install_element (ENABLE_NODE, &show_zebra_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_as4_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_upstream_join_desired_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_protocol_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd_vtysh); install_element (BGP_NODE, &neighbor_send_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_send_community_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community4_cmd_vtysh); install_element (BGP_NODE, &neighbor_ttl_security_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_nsm_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_flags_distance_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ripng_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_self_originated_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (RIP_NODE, &no_rip_network_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd_vtysh); install_element (VIEW_NODE, &show_ip_protocol_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd_vtysh); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_brouter_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_val_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_route_addr_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_mpls_te_router_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_route_map_cmd_vtysh); install_element (BGP_NODE, &neighbor_weight_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_detail_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_access_list_exact_cmd_vtysh); install_element (INTERFACE_NODE, &interface_ip_igmp_cmd_vtysh); install_element (RIPNG_NODE, &ripng_default_metric_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd_vtysh); install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_assert_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ttl_security_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_join_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd_vtysh); install_element (ENABLE_NODE, &debug_igmp_packets_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_redistribute_source_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd_vtysh); install_element (RMAP_NODE, &match_origin_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_list_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_linkstate_id_detail_cmd_vtysh); install_element (OSPF_NODE, &no_capability_opaque_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_regexp_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); install_element (BGP_NODE, &neighbor_capability_dynamic_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_interface_cmd_vtysh); install_element (RMAP_NODE, &no_set_origin_val_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_database_detail_arg_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_passive_interface_default_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_route_cmd_vtysh); install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd_vtysh); install_element (CONFIG_NODE, &ip_forwarding_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_distance_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd_vtysh); install_element (VIEW_NODE, &show_ip_pim_join_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_normal_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (VIEW_NODE, &show_isis_interface_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &isis_circuit_type_cmd_vtysh); install_element (ISIS_NODE, &is_type_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd_vtysh); install_element (CONFIG_NODE, &ip_ssmpingd_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_all_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_linkstate_id_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_update_cmd_vtysh); install_element (BGP_NODE, &bgp_cluster_id32_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd_vtysh); install_element (ISIS_NODE, &domain_passwd_md5_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_unset_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd_vtysh); install_element (CONFIG_NODE, &debug_rip_events_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_address_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_ge_le_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_any_any_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_upd_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd_vtysh); install_element (RMAP_NODE, &no_match_origin_val_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_network_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_spfstats_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_port_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_seq_le_ge_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd_vtysh); install_element (INTERFACE_NODE, &no_babel_split_horizon_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_neighbors_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_isis_upd_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd_vtysh); install_element (OSPF_NODE, &ospf_distance_ospf_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd_vtysh); install_element (RIP_NODE, &no_rip_timers_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_rip_status_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd_vtysh); install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_self_originated_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd_vtysh); install_element (RIP_NODE, &no_rip_timers_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_cmd_vtysh); install_element (RMAP_NODE, &no_match_ecommunity_val_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd_vtysh); install_element (INTERFACE_NODE, &psnp_interval_l1_cmd_vtysh); install_element (OSPF6_NODE, &area_import_list_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_mroute_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_cmd_vtysh); install_element (BGP_NODE, &no_bgp_confederation_peers_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd_vtysh); install_element (VIEW_NODE, &show_isis_neighbor_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd_vtysh); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd_vtysh); install_element (ENABLE_NODE, &undebug_igmp_trace_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_community_all_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_summary_cmd_vtysh); install_element (INTERFACE_NODE, &isis_passive_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (VIEW_NODE, &show_ip_mroute_count_cmd_vtysh); install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_pim_upstream_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_name_prefix_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd_vtysh); install_element (VIEW_NODE, &show_ip_forwarding_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_remark_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd_vtysh); install_element (CONFIG_NODE, &ip_prefix_list_sequence_number_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd_vtysh); install_element (BGP_NODE, &neighbor_interface_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_interface_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (ENABLE_NODE, &undebug_pim_events_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_weight_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_adj_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_neighbor_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_detail_name_cmd_vtysh); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd_vtysh); install_element (RMAP_NODE, &match_probability_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd_vtysh); install_element (ENABLE_NODE, &rmap_show_name_cmd_vtysh); install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd_vtysh); install_element (ENABLE_NODE, &show_isis_neighbor_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_adv_router_cmd_vtysh); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd_vtysh); install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_route_cmd_vtysh); install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd_vtysh); install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd_vtysh); install_element (INTERFACE_NODE, &ip_rip_split_horizon_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); install_element (RMAP_NODE, &rmap_continue_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd_vtysh); install_element (OSPF_NODE, &ospf_area_authentication_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd_vtysh); install_element (RMAP_NODE, &set_src_cmd_vtysh); install_element (BABEL_NODE, &babel_set_resend_delay_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd_vtysh); install_element (VIEW_NODE, &show_hostname_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd_vtysh); install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (INTERFACE_NODE, &isis_priority_l2_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd_vtysh); install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd_vtysh); install_element (RIP_NODE, &no_rip_allow_ecmp_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_summary_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_address_label_cmd_vtysh); install_element (RMAP_NODE, &no_match_ip_route_source_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_prefix_list_cmd_vtysh); install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_packet_cmd_vtysh); install_element (BGP_NODE, &bgp_distance_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd_vtysh); install_element (BGP_NODE, &neighbor_filter_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd_vtysh); install_element (ENABLE_NODE, &show_database_detail_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged7_cmd_vtysh); install_element (CONFIG_NODE, &access_list_extended_mask_any_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_ssmpingd_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_mroute_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_multicast_routing_cmd_vtysh); install_element (INTERFACE_NODE, &bandwidth_if_cmd_vtysh); install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd_vtysh); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd_vtysh); install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd_vtysh); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_isis_events_cmd_vtysh); install_element (CONFIG_NODE, &debug_zebra_packet_direct_cmd_vtysh); install_element (RMAP_NODE, &no_match_interface_cmd_vtysh); install_element (VIEW_NODE, &show_interface_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_le_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd_vtysh); install_element (RMAP_NODE, &set_metric_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd_vtysh); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd_vtysh); install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_id_router_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_events_cmd_vtysh); install_element (BGP_NODE, &no_bgp_scan_time_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_route_summary_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (CONFIG_NODE, &undebug_ssmpingd_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd_vtysh); install_element (RMAP_NODE, &set_ecommunity_soo_cmd_vtysh); install_element (RIP_NODE, &rip_offset_list_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_name_seq_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_id_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd_vtysh); install_element (RMAP_NODE, &no_match_community_exact_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_self_originated_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd_vtysh); install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd_vtysh); install_element (RMAP_NODE, &set_tag_cmd_vtysh); install_element (INTERFACE_NODE, &babel_set_wireless_cmd_vtysh); install_element (CONFIG_NODE, &ip_route_mask_flags_distance2_cmd_vtysh); install_element (INTERFACE_NODE, &ospf_dead_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_igmp_join_cmd_vtysh); install_element (ENABLE_NODE, &debug_zebra_kernel_cmd_vtysh); install_element (RMAP_NODE, &no_set_metric_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd_vtysh); install_element (RMAP_NODE, &no_match_peer_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd_vtysh); install_element (CONFIG_NODE, &undebug_pim_trace_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_ospf_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_interfaces_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_database_type_self_originated_detail_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_rip_events_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_any_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_igmp_query_max_response_time_cmd_vtysh); install_element (BGP_NODE, &neighbor_send_community_type_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd_vtysh); install_element (INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd_vtysh); install_element (VIEW_NODE, &show_database_detail_arg_cmd_vtysh); install_element (BGP_NODE, &neighbor_port_cmd_vtysh); install_element (VTY_NODE, &exec_timeout_min_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd_vtysh); install_element (RMAP_NODE, &match_ip_next_hop_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd_vtysh); install_element (INTERFACE_NODE, &isis_metric_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_area_vlink_md5_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_local_as_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_trace_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_description_arg_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_flags_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_ge_cmd_vtysh); install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd_vtysh); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf_ism_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd_vtysh); install_element (RIP_NODE, &rip_distance_source_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_adv_router_detail_cmd_vtysh); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd_vtysh); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd_vtysh); install_element (OSPF_NODE, &ospf_distribute_list_out_cmd_vtysh); install_element (ENABLE_NODE, &show_database_arg_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd_vtysh); install_element (BGP_NODE, &neighbor_enforce_multihop_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_remark_arg_cmd_vtysh); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_prefix_list_seq_le_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_mroute_cmd_vtysh); install_element (VIEW_NODE, &show_ip_rip_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd_vtysh); install_element (ENABLE_NODE, &debug_rip_zebra_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_route_summary_prefix_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_ge_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh); install_element (CONFIG_NODE, &debug_isis_events_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd_vtysh); install_element (VIEW_NODE, &show_ip_igmp_interface_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd_vtysh); install_element (RIP_NODE, &rip_distance_source_access_list_cmd_vtysh); install_element (CONFIG_NODE, &ip_as_path_cmd_vtysh); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh); install_element (VIEW_NODE, &show_babel_neighbour_cmd_vtysh); install_element (ENABLE_NODE, &debug_isis_csum_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_out_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd_vtysh); install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd_vtysh); install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd_vtysh); install_element (INTERFACE_NODE, &csnp_interval_cmd_vtysh); install_element (OSPF6_NODE, &no_area_import_list_cmd_vtysh); install_element (RMAP_NODE, &no_set_aspath_exclude_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd_vtysh); install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd_vtysh); install_element (RMAP_NODE, &no_set_community_delete_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_exact_cmd_vtysh); install_element (RIPNG_NODE, &ripng_aggregate_address_cmd_vtysh); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd_vtysh); install_element (RMAP_NODE, &no_set_tag_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd_vtysh); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_route_flags_distance2_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd_vtysh); install_element (OSPF_NODE, &ospf_refresh_timer_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_id_router_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_id_detail_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_prefix_list_prefix_longer_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_network_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd_vtysh); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd_vtysh); install_element (BGP_NODE, &bgp_graceful_restart_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_mroute_dist_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd_vtysh); install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd_vtysh); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd_vtysh); install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_community_list_standard_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd_vtysh); install_element (ENABLE_NODE, &debug_bgp_as4_cmd_vtysh); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd_vtysh); install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd_vtysh); install_element (BGP_NODE, &bgp_damp_set3_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd_vtysh); install_element (ENABLE_NODE, &no_terminal_monitor_cmd_vtysh); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd_vtysh); install_element (BGP_NODE, &no_synchronization_cmd_vtysh); install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd_vtysh); install_element (ENABLE_NODE, &debug_pim_cmd_vtysh); install_element (CONFIG_NODE, &no_bgp_config_type_cmd_vtysh); install_element (ENABLE_NODE, &debug_ospf6_abr_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd_vtysh); install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd_vtysh); install_element (CONFIG_NODE, &no_access_list_extended_host_mask_cmd_vtysh); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd_vtysh); install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_route_map_cmd_vtysh); install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd_vtysh); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_warning_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd_vtysh); install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_igmp_packets_cmd_vtysh); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd_vtysh); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd_vtysh); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd_vtysh); install_element (INTERFACE_NODE, &ipv6_router_isis_cmd_vtysh); install_element (VIEW_NODE, &show_isis_topology_l2_cmd_vtysh); install_element (CONFIG_NODE, &no_ipv6_access_list_all_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd_vtysh); install_element (VIEW_NODE, &show_ip_ssmpingd_cmd_vtysh); install_element (OSPF_NODE, &ospf_default_information_originate_cmd_vtysh); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community3_exact_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd_vtysh); install_element (RIPNG_NODE, &ripng_offset_list_ifname_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_ospf6_database_type_router_cmd_vtysh); install_element (CONFIG_NODE, &ipv6_prefix_list_seq_ge_cmd_vtysh); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd_vtysh); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_prefix_list_summary_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community_cmd_vtysh); install_element (KEYCHAIN_KEY_NODE, &send_lifetime_month_day_month_day_cmd_vtysh); install_element (BGP_NODE, &no_neighbor_description_val_cmd_vtysh); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd_vtysh); install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd_vtysh); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd_vtysh); install_element (CONFIG_NODE, &no_ip_prefix_list_seq_cmd_vtysh); install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd_vtysh); install_element (VIEW_NODE, &show_bgp_community4_exact_cmd_vtysh); install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd_vtysh); install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd_vtysh); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd_vtysh); install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd_vtysh); install_element (CONFIG_NODE, &no_router_ospf_cmd_vtysh); install_element (VIEW_NODE, &show_ipv6_prefix_list_summary_name_cmd_vtysh); install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd_vtysh); install_element (ISIS_NODE, &lsp_refresh_interval_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd_vtysh); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd_vtysh); install_element (ENABLE_NODE, &show_ip_rpf_addr_cmd_vtysh); } quagga-0.99.24.1/tests/test-checksum.c0000644000175000017500000002703012476520570014323 00000000000000/* * Copyright (C) 2008 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include "checksum.h" struct thread_master *master; struct acc_vals { int c0; int c1; }; struct csum_vals { struct acc_vals a; int x; int y; }; static struct csum_vals ospfd_vals, isisd_vals; typedef size_t testsz_t; typedef uint16_t testoff_t; /* Fletcher Checksum -- Refer to RFC1008. */ #define MODX 4102 /* Accumulator phase of checksum */ static struct acc_vals accumulate (u_char *buffer, testsz_t len, testoff_t off) { u_int8_t *p; u_int16_t *csum; int i, partial_len; struct acc_vals ret; csum = (u_int16_t *) (buffer + off); *(csum) = 0; p = buffer; ret.c0 = 0; ret.c1 = 0; while (len != 0) { partial_len = MIN(len, MODX); for (i = 0; i < partial_len; i++) { ret.c0 = ret.c0 + *(p++); ret.c1 += ret.c0; } ret.c0 = ret.c0 % 255; ret.c1 = ret.c1 % 255; len -= partial_len; } return ret; } /* The final reduction phase. * This one should be the original ospfd version */ static u_int16_t reduce_ospfd (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 x = ((len - off - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; /* take care endian issue. */ return htons ((x << 8) + y); #undef x #undef y #undef c0 #undef c1 } /* slightly different concatenation */ static u_int16_t reduce_ospfd1 (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 x = ((len - off - 1) * c0 - c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; /* take care endian issue. */ return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* original isisd version */ static u_int16_t reduce_isisd (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul - 1; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Is the -1 in y wrong perhaps? */ static u_int16_t reduce_isisd_yfix (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Move the mods yp */ static u_int16_t reduce_isisd_mod (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c1 - c0; y = c1 - mul - 1; x %= 255; y %= 255; if (y > 0) y++; if (x < 0) x--; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } /* Move the mods up + fix y */ static u_int16_t reduce_isisd_mody (struct csum_vals *vals, testsz_t len, testoff_t off) { #define x vals->x #define y vals->y #define c0 vals->a.c0 #define c1 vals->a.c1 u_int32_t mul; mul = (len - off)*(c0); x = mul - c0 - c1; y = c1 - mul; x %= 255; y %= 255; if (y > 0) y++; if (x < 0) x--; if (x == 0) x = 255; if (y == 0) y = 1; return htons ((x << 8) | (y & 0xff)); #undef x #undef y #undef c0 #undef c1 } struct reductions_t { const char *name; u_int16_t (*f) (struct csum_vals *, testsz_t, testoff_t); } reducts[] = { { .name = "ospfd", .f = reduce_ospfd }, { .name = "ospfd-1", .f = reduce_ospfd1 }, { .name = "isisd", .f = reduce_isisd }, { .name = "isisd-yfix", .f = reduce_isisd_yfix }, { .name = "isisd-mod", .f = reduce_isisd_mod }, { .name = "isisd-mody", .f = reduce_isisd_mody }, { NULL, NULL }, }; /* The original ospfd checksum */ static u_int16_t ospfd_checksum (u_char *buffer, testsz_t len, testoff_t off) { u_char *sp, *ep, *p, *q; int c0 = 0, c1 = 0; int x, y; u_int16_t checksum, *csum; csum = (u_int16_t *) (buffer + off); *(csum) = 0; sp = buffer; for (ep = sp + len; sp < ep; sp = q) { q = sp + MODX; if (q > ep) q = ep; for (p = sp; p < q; p++) { c0 += *p; c1 += c0; } c0 %= 255; c1 %= 255; } ospfd_vals.a.c0 = c0; ospfd_vals.a.c1 = c1; //printf ("%s: len %u, off %u, c0 %d, c1 %d\n", // __func__, len, off, c0, c1); x = ((int)(len - off - 1) * (int)c0 - (int)c1) % 255; if (x <= 0) x += 255; y = 510 - c0 - x; if (y > 255) y -= 255; ospfd_vals.x = x; ospfd_vals.y = y; buffer[off] = x; buffer[off + 1] = y; /* take care endian issue. */ checksum = htons ((x << 8) | (y & 0xff)); return (checksum); } /* the original, broken isisd checksum */ static u_int16_t iso_csum_create (u_char * buffer, testsz_t len, testoff_t off) { u_int8_t *p; int x; int y; u_int32_t mul; u_int32_t c0; u_int32_t c1; u_int16_t checksum, *csum; int i, init_len, partial_len; checksum = 0; csum = (u_int16_t *) (buffer + off); *(csum) = checksum; p = buffer; c0 = 0; c1 = 0; init_len = len; while (len != 0) { partial_len = MIN(len, MODX); for (i = 0; i < partial_len; i++) { c0 = c0 + *(p++); c1 += c0; } c0 = c0 % 255; c1 = c1 % 255; len -= partial_len; } isisd_vals.a.c0 = c0; isisd_vals.a.c1 = c1; mul = (init_len - off) * c0; x = mul - c1 - c0; y = c1 - mul - 1; if (y > 0) y++; if (x < 0) x--; x %= 255; y %= 255; if (x == 0) x = 255; if (y == 0) y = 1; isisd_vals.x = x; isisd_vals.y = y; checksum = htons((x << 8) | (y & 0xFF)); *(csum) = checksum; /* return the checksum for user usage */ return checksum; } static int verify (u_char * buffer, testsz_t len) { u_int8_t *p; u_int32_t c0; u_int32_t c1; int i, partial_len; p = buffer; c0 = 0; c1 = 0; while (len) { partial_len = MIN(len, 5803); for (i = 0; i < partial_len; i++) { c0 = c0 + *(p++); c1 += c0; } c0 = c0 % 255; c1 = c1 % 255; len -= partial_len; } if (c0 == 0 && c1 == 0) return 0; return 1; } static int /* return checksum in low-order 16 bits */ in_cksum_optimized(void *parg, int nbytes) { u_short *ptr = parg; register long sum; /* assumes long == 32 bits */ register u_short answer; /* assumes u_short == 16 bits */ register int count; /* * Our algorithm is simple, using a 32-bit accumulator (sum), * we add sequential 16-bit words to it, and at the end, fold back * all the carry bits from the top 16 bits into the lower 16 bits. */ sum = 0; count = nbytes >> 1; /* div by 2 */ for(ptr--; count; --count) sum += *++ptr; if (nbytes & 1) /* Odd */ sum += *(u_char *)(++ptr); /* one byte only */ /* * Add back carry outs from top 16 bits to low 16 bits. */ sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* ones-complement, then truncate to 16 bits */ return(answer); } static int /* return checksum in low-order 16 bits */ in_cksum_rfc(void *parg, int count) /* from RFC 1071 */ { u_short *addr = parg; /* Compute Internet Checksum for "count" bytes * beginning at location "addr". */ register long sum = 0; while (count > 1) { /* This is the inner loop */ sum += *addr++; count -= 2; } /* Add left-over byte, if any */ if (count > 0) { sum += *(u_char *)addr; } /* Fold 32-bit sum to 16 bits */ while (sum>>16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } int main(int argc, char **argv) { /* 60017 65629 702179 */ #define MAXDATALEN 60017 #define BUFSIZE MAXDATALEN + sizeof(u_int16_t) u_char buffer[BUFSIZE]; int exercise = 0; #define EXERCISESTEP 257 srandom (time (NULL)); while (1) { u_int16_t ospfd, isisd, lib, in_csum, in_csum_res, in_csum_rfc; int i,j; exercise += EXERCISESTEP; exercise %= MAXDATALEN; for (i = 0; i < exercise; i += sizeof (long int)) { long int rand = random (); for (j = sizeof (long int); j > 0; j--) buffer[i + (sizeof (long int) - j)] = (rand >> (j * 8)) & 0xff; } in_csum = in_cksum(buffer, exercise); in_csum_res = in_cksum_optimized(buffer, exercise); in_csum_rfc = in_cksum_rfc(buffer, exercise); if (in_csum_res != in_csum || in_csum != in_csum_rfc) printf ("verify: in_chksum failed in_csum:%x, in_csum_res:%x," "in_csum_rfc %x, len:%d\n", in_csum, in_csum_res, in_csum_rfc, exercise); ospfd = ospfd_checksum (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: ospfd failed\n"); isisd = iso_csum_create (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: isisd failed\n"); lib = fletcher_checksum (buffer, exercise + sizeof(u_int16_t), exercise); if (verify (buffer, exercise + sizeof(u_int16_t))) printf ("verify: lib failed\n"); if (ospfd != lib) { printf ("Mismatch in values at size %u\n" "ospfd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "isisd: 0x%04x\tc0: %d\tc1: %d\tx: %d\ty: %d\n" "lib: 0x%04x\n", exercise, ospfd, ospfd_vals.a.c0, ospfd_vals.a.c1, ospfd_vals.x, ospfd_vals.y, isisd, isisd_vals.a.c0, isisd_vals.a.c1, isisd_vals.x, isisd_vals.y, lib ); /* Investigate reduction phase discrepencies */ if (ospfd_vals.a.c0 == isisd_vals.a.c0 && ospfd_vals.a.c1 == isisd_vals.a.c1) { printf ("\n"); for (i = 0; reducts[i].name != NULL; i++) { ospfd = reducts[i].f (&ospfd_vals, exercise + sizeof (u_int16_t), exercise); printf ("%20s: x: %02x, y %02x, checksum 0x%04x\n", reducts[i].name, ospfd_vals.x & 0xff, ospfd_vals.y & 0xff, ospfd); } } printf ("\n u_char testdata [] = {\n "); for (i = 0; i < exercise; i++) { printf ("0x%02x,%s", buffer[i], (i + 1) % 8 ? " " : "\n "); } printf ("\n}\n"); exit (1); } } } quagga-0.99.24.1/tests/test-buffer.c0000644000175000017500000000264712476520570014001 00000000000000/* * Copyright (C) 2004 Paul Jakma * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include struct thread_master *master; int main(int argc, char **argv) { struct buffer *b1, *b2; int n; char junk[3]; char c = 'a'; memory_init(); if ((argc != 2) || (sscanf(argv[1], "%d%1s", &n, junk) != 1)) { fprintf(stderr, "Usage: %s \n", *argv); return 1; } b1 = buffer_new(0); b2 = buffer_new(1024); while (n-- > 0) { buffer_put(b1, &c, 1); buffer_put(b2, &c, 1); if (c++ == 'z') c = 'a'; buffer_reset(b1); buffer_reset(b2); } buffer_free(b1); buffer_free(b2); return 0; } quagga-0.99.24.1/tests/bgp_mp_attr_test.c0000644000175000017500000004432412476520570015106 00000000000000/* * Copyright (C) 2008 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define CAPABILITY 0 #define DYNCAP 1 #define OPT_PARAM 2 /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; static int tty = 0; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char data[1024]; int len; #define SHOULD_PARSE 0 #define SHOULD_ERR -1 int parses; /* whether it should parse or not */ /* AFI/SAFI validation */ afi_t afi; safi_t safi; #define VALID_AFI 1 #define INVALID_AFI 0 int afi_valid; } mp_reach_segments [] = { { "IPv6", "IPV6 MP Reach, global nexthop, 1 NLRI", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ }, (4 + 16 + 1 + 5), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-2", "IPV6 MP Reach, global nexthop, 2 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* ffee:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, }, (4 + 16 + 1 + 5 + 9), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-default", "IPV6 MP Reach, global nexthop, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 16 + 1 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-lnh", "IPV6 MP Reach, global+local nexthops, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen", "IPV6 MP Reach, inappropriate nexthop length", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen2", "IPV6 MP Reach, invalid nexthop length", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 5, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen3", "IPV6 MP Reach, nexthop length overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, }, (4 + 16), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nhlen4", "IPV6 MP Reach, nexthop length short", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 16, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-nlri", "IPV6 MP Reach, NLRI bitlen overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop (global) */ 0xff, 0xfe, 0x1, 0x2, /* fffe:102:... */ 0xaa, 0xbb, 0xcc, 0xdd, 0x3, 0x4, 0x5, 0x6, 0xa1, 0xa2, 0xa3, 0xa4, /* Nexthop (local) */ 0xfe, 0x80, 0x0, 0x0, /* fe80::210:2ff:.. */ 0x0, 0x0, 0x0, 0x0, 0x2, 0x10, 0x2, 0xff, 0x1, 0x2, 0x3, 0x4, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 120, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0, /* ::/0 */ }, (4 + 32 + 1 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv4", "IPv4 MP Reach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-nhlen", "IPv4 MP Reach, nexthop lenth overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 32, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 4 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-nlrilen", "IPv4 MP Reach, nlri lenth overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* nexthop bytes */ 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 30, 10, 0, /* 0/0 */ }, (4 + 4 + 1 + 3 + 2 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-MLVPN", "IPv4/MPLS-labeled VPN MP Reach, RD, Nexthop, 3 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 1, 2, 0, 0xff, 3, 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (4 + 12 + 1 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, /* From bug #385 */ { "IPv6-bug", "IPv6, global nexthop, 1 default NLRI", { /* AFI / SAFI */ 0x0, 0x2, 0x1, /* nexthop bytes */ 0x20, /* Nexthop (global) */ 0x20, 0x01, 0x04, 0x70, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, /* Nexthop (local) */ 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0xdb, 0xff, 0xfe, 0xfe, 0xeb, 0x00, /* SNPA (defunct, MBZ) */ 0, /* NLRI tuples */ /* Should have 0 here for ::/0, but dont */ }, 37, SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; /* MP_UNREACH_NLRI tests */ static struct test_segment mp_unreach_segments [] = { { "IPv6-unreach", "IPV6 MP Unreach, 1 NLRI", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ }, (3 + 5), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach2", "IPV6 MP Unreach, 2 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, }, (3 + 5 + 9), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach-default", "IPV6 MP Unreach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 32, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0x0, /* ::/0 */ }, (3 + 5 + 9 + 1), SHOULD_PARSE, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv6-unreach-nlri", "IPV6 MP Unreach, NLRI bitlen overflow", { /* AFI / SAFI */ 0x0, AFI_IP6, SAFI_UNICAST, /* NLRI tuples */ 120, 0xff, 0xfe, 0x1, 0x2, /* fffe:102::/32 */ 64, 0xff, 0xfe, 0x0, 0x1, /* fffe:1:2:3::/64 */ 0x0, 0x2, 0x0, 0x3, 0, /* ::/0 */ }, (3 + 5 + 9 + 1), SHOULD_ERR, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach", "IPv4 MP Unreach, 2 NLRIs + default", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (3 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach-nlrilen", "IPv4 MP Unreach, nlri length overflow", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_UNICAST, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 30, 10, 0, /* 0/0 */ }, (3 + 3 + 2 + 1), SHOULD_ERR, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "IPv4-unreach-MLVPN", "IPv4/MPLS-labeled VPN MP Unreach, RD, 3 NLRIs", { /* AFI / SAFI */ 0x0, AFI_IP, SAFI_MPLS_LABELED_VPN, /* nexthop bytes */ 12, /* RD */ 0, 0, 1, 2, 0, 0xff, 3, 4, /* Nexthop */ 192, 168, 0, 1, /* SNPA (defunct, MBZ) */ 0x0, /* NLRI tuples */ 16, 10, 1, /* 10.1/16 */ 17, 10, 2, 3, /* 10.2.3/17 */ 0, /* 0/0 */ }, (3 + 3 + 4 + 1), SHOULD_PARSE, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int oldfailed = failed; struct attr attr = { }; struct bgp_nlri nlri = { }; struct bgp_attr_parser_args attr_args = { .peer = peer, .length = t->len, .total = 1, .attr = &attr, .type = BGP_ATTR_MP_REACH_NLRI, .flags = BGP_ATTR_FLAG_OPTIONAL, .startp = BGP_INPUT_PNT (peer), }; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); if (type == BGP_ATTR_MP_REACH_NLRI) ret = bgp_mp_reach_parse (&attr_args, &nlri); else ret = bgp_mp_unreach_parse (&attr_args, &nlri); if (!ret) { safi_t safi = t->safi; if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) failed++; printf ("MP: %u/%u (%u): recv %u, nego %u\n", t->afi, t->safi, safi, peer->afc_recv[t->afi][safi], peer->afc_nego[t->afi][safi]); } printf ("parsed?: %s\n", ret ? "no" : "yes"); if ((ret == 0) != (t->parses == 0)) failed++; if (tty) printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET : VT100_GREEN "OK" VT100_RESET); else printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); if (failed) printf (" (%u)", failed); printf ("\n\n"); } static struct bgp *bgp; static as_t asn = 100; int main (void) { struct peer *peer; int i, j; conf_bgp_debug_fsm = -1UL; conf_bgp_debug_events = -1UL; conf_bgp_debug_packet = -1UL; conf_bgp_debug_normal = -1UL; conf_bgp_debug_as4 = -1UL; term_bgp_debug_fsm = -1UL; term_bgp_debug_events = -1UL; term_bgp_debug_packet = -1UL; term_bgp_debug_normal = -1UL; term_bgp_debug_as4 = -1UL; master = thread_master_create (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); if (bgp_get (&bgp, &asn, NULL)) return -1; peer = peer_create_accept (bgp); peer->host = "foo"; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) { peer->afc[i][j] = 1; peer->afc_adv[i][j] = 1; } i = 0; while (mp_reach_segments[i].name) parse_test (peer, &mp_reach_segments[i++], BGP_ATTR_MP_REACH_NLRI); i = 0; while (mp_unreach_segments[i].name) parse_test (peer, &mp_unreach_segments[i++], BGP_ATTR_MP_UNREACH_NLRI); printf ("failures: %d\n", failed); return failed; } quagga-0.99.24.1/tests/bgp_mpath_test.c0000644000175000017500000003254412476520570014552 00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath Unit Test * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vty.h" #include "stream.h" #include "privs.h" #include "linklist.h" #include "memory.h" #include "zclient.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mpath.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define OK VT100_GREEN "OK" VT100_RESET #define FAILED VT100_RED "failed" VT100_RESET #define TEST_PASSED 0 #define TEST_FAILED -1 #define EXPECT_TRUE(expr, res) \ if (!(expr)) \ { \ printf ("Test failure in %s line %u: %s\n", \ __FUNCTION__, __LINE__, #expr); \ (res) = TEST_FAILED; \ } typedef struct testcase_t__ testcase_t; typedef int (*test_setup_func)(testcase_t *); typedef int (*test_run_func)(testcase_t *); typedef int (*test_cleanup_func)(testcase_t *); struct testcase_t__ { const char *desc; void *test_data; void *verify_data; void *tmp_data; test_setup_func setup; test_run_func run; test_cleanup_func cleanup; }; /* need these to link in libbgp */ struct thread_master *master = NULL; struct zclient *zclient; struct zebra_privs_t bgpd_privs = { .user = NULL, .group = NULL, .vty_group = NULL, }; static int tty = 0; /* Create fake bgp instance */ static struct bgp * bgp_create_fake (as_t *as, const char *name) { struct bgp *bgp; afi_t afi; safi_t safi; if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) return NULL; bgp_lock (bgp); //bgp->peer_self = peer_new (bgp); //bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement"); bgp->peer = list_new (); //bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; bgp->group = list_new (); //bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; bgp->rsclient = list_new (); //bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->as = *as; if (name) bgp->name = strdup (name); return bgp; } /*========================================================= * Testcase for maximum-paths configuration */ static int setup_bgp_cfg_maximum_paths (testcase_t *t) { as_t asn = 1; t->tmp_data = bgp_create_fake (&asn, NULL); if (!t->tmp_data) return -1; return 0; } static int run_bgp_cfg_maximum_paths (testcase_t *t) { afi_t afi; safi_t safi; struct bgp *bgp; int api_result; int test_result = TEST_PASSED; bgp = t->tmp_data; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { /* test bgp_maximum_paths_set */ api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, 10); EXPECT_TRUE (api_result == 0, test_result); api_result = bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, 10); EXPECT_TRUE (api_result == 0, test_result); EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ebgp == 10, test_result); EXPECT_TRUE (bgp->maxpaths[afi][safi].maxpaths_ibgp == 10, test_result); /* test bgp_maximum_paths_unset */ api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_EBGP); EXPECT_TRUE (api_result == 0, test_result); api_result = bgp_maximum_paths_unset (bgp, afi, safi, BGP_PEER_IBGP); EXPECT_TRUE (api_result == 0, test_result); EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ebgp == BGP_DEFAULT_MAXPATHS), test_result); EXPECT_TRUE ((bgp->maxpaths[afi][safi].maxpaths_ibgp == BGP_DEFAULT_MAXPATHS), test_result); } return test_result; } static int cleanup_bgp_cfg_maximum_paths (testcase_t *t) { return bgp_delete ((struct bgp *)t->tmp_data); } testcase_t test_bgp_cfg_maximum_paths = { .desc = "Test bgp maximum-paths config", .setup = setup_bgp_cfg_maximum_paths, .run = run_bgp_cfg_maximum_paths, .cleanup = cleanup_bgp_cfg_maximum_paths, }; /*========================================================= * Testcase for bgp_mp_list */ struct peer test_mp_list_peer[] = { { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, { .local_as = 1, .as = 2 }, }; int test_mp_list_peer_count = sizeof (test_mp_list_peer)/ sizeof (struct peer); struct attr test_mp_list_attr[4]; struct bgp_info test_mp_list_info[] = { { .peer = &test_mp_list_peer[0], .attr = &test_mp_list_attr[0] }, { .peer = &test_mp_list_peer[1], .attr = &test_mp_list_attr[1] }, { .peer = &test_mp_list_peer[2], .attr = &test_mp_list_attr[1] }, { .peer = &test_mp_list_peer[3], .attr = &test_mp_list_attr[2] }, { .peer = &test_mp_list_peer[4], .attr = &test_mp_list_attr[3] }, }; int test_mp_list_info_count = sizeof (test_mp_list_info)/sizeof (struct bgp_info); static int setup_bgp_mp_list (testcase_t *t) { test_mp_list_attr[0].nexthop.s_addr = 0x01010101; test_mp_list_attr[1].nexthop.s_addr = 0x02020202; test_mp_list_attr[2].nexthop.s_addr = 0x03030303; test_mp_list_attr[3].nexthop.s_addr = 0x04040404; if ((test_mp_list_peer[0].su_remote = sockunion_str2su ("1.1.1.1")) == NULL) return -1; if ((test_mp_list_peer[1].su_remote = sockunion_str2su ("2.2.2.2")) == NULL) return -1; if ((test_mp_list_peer[2].su_remote = sockunion_str2su ("3.3.3.3")) == NULL) return -1; if ((test_mp_list_peer[3].su_remote = sockunion_str2su ("4.4.4.4")) == NULL) return -1; if ((test_mp_list_peer[4].su_remote = sockunion_str2su ("5.5.5.5")) == NULL) return -1; return 0; } static int run_bgp_mp_list (testcase_t *t) { struct list mp_list; struct listnode *mp_node; struct bgp_info *info; int i; int test_result = TEST_PASSED; bgp_mp_list_init (&mp_list); EXPECT_TRUE (listcount(&mp_list) == 0, test_result); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); bgp_mp_list_add (&mp_list, &test_mp_list_info[2]); bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); for (i = 0, mp_node = listhead(&mp_list); i < test_mp_list_info_count; i++, mp_node = listnextnode(mp_node)) { info = listgetdata(mp_node); EXPECT_TRUE (info == &test_mp_list_info[i], test_result); } bgp_mp_list_clear (&mp_list); EXPECT_TRUE (listcount(&mp_list) == 0, test_result); return test_result; } static int cleanup_bgp_mp_list (testcase_t *t) { int i; for (i = 0; i < test_mp_list_peer_count; i++) sockunion_free (test_mp_list_peer[i].su_remote); return 0; } testcase_t test_bgp_mp_list = { .desc = "Test bgp_mp_list", .setup = setup_bgp_mp_list, .run = run_bgp_mp_list, .cleanup = cleanup_bgp_mp_list, }; /*========================================================= * Testcase for bgp_info_mpath_update */ struct bgp_node test_rn; static int setup_bgp_info_mpath_update (testcase_t *t) { int i; str2prefix ("42.1.1.0/24", &test_rn.p); setup_bgp_mp_list (t); for (i = 0; i < test_mp_list_info_count; i++) bgp_info_add (&test_rn, &test_mp_list_info[i]); return 0; } static int run_bgp_info_mpath_update (testcase_t *t) { struct bgp_info *new_best, *old_best, *mpath; struct list mp_list; struct bgp_maxpaths_cfg mp_cfg = { 3, 3 }; int test_result = TEST_PASSED; bgp_mp_list_init (&mp_list); bgp_mp_list_add (&mp_list, &test_mp_list_info[4]); bgp_mp_list_add (&mp_list, &test_mp_list_info[3]); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[3]; old_best = NULL; bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 2, test_result); mpath = bgp_info_mpath_first (new_best); EXPECT_TRUE (mpath == &test_mp_list_info[0], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); mpath = bgp_info_mpath_next (mpath); EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); bgp_mp_list_add (&mp_list, &test_mp_list_info[0]); bgp_mp_list_add (&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[0]; old_best = &test_mp_list_info[3]; bgp_info_mpath_update (&test_rn, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear (&mp_list); EXPECT_TRUE (bgp_info_mpath_count (new_best) == 1, test_result); mpath = bgp_info_mpath_first (new_best); EXPECT_TRUE (mpath == &test_mp_list_info[1], test_result); EXPECT_TRUE (CHECK_FLAG (mpath->flags, BGP_INFO_MULTIPATH), test_result); EXPECT_TRUE (!CHECK_FLAG (test_mp_list_info[0].flags, BGP_INFO_MULTIPATH), test_result); return test_result; } static int cleanup_bgp_info_mpath_update (testcase_t *t) { int i; for (i = 0; i < test_mp_list_peer_count; i++) sockunion_free (test_mp_list_peer[i].su_remote); return 0; } testcase_t test_bgp_info_mpath_update = { .desc = "Test bgp_info_mpath_update", .setup = setup_bgp_info_mpath_update, .run = run_bgp_info_mpath_update, .cleanup = cleanup_bgp_info_mpath_update, }; /*========================================================= * Set up testcase vector */ testcase_t *all_tests[] = { &test_bgp_cfg_maximum_paths, &test_bgp_mp_list, &test_bgp_info_mpath_update, }; int all_tests_count = (sizeof(all_tests)/sizeof(testcase_t *)); /*========================================================= * Test Driver Functions */ static int global_test_init (void) { master = thread_master_create (); zclient = zclient_new (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); return 0; } static int global_test_cleanup (void) { zclient_free (zclient); thread_master_free (master); return 0; } static void display_result (testcase_t *test, int result) { if (tty) printf ("%s: %s\n", test->desc, result == TEST_PASSED ? OK : FAILED); else printf ("%s: %s\n", test->desc, result == TEST_PASSED ? "OK" : "FAILED"); } static int setup_test (testcase_t *t) { int res = 0; if (t->setup) res = t->setup (t); return res; } static int cleanup_test (testcase_t *t) { int res = 0; if (t->cleanup) res = t->cleanup (t); return res; } static void run_tests (testcase_t *tests[], int num_tests, int *pass_count, int *fail_count) { int test_index, result; testcase_t *cur_test; *pass_count = *fail_count = 0; for (test_index = 0; test_index < num_tests; test_index++) { cur_test = tests[test_index]; if (!cur_test->desc) { printf ("error: test %d has no description!\n", test_index); continue; } if (!cur_test->run) { printf ("error: test %s has no run function!\n", cur_test->desc); continue; } if (setup_test (cur_test) != 0) { printf ("error: setup failed for test %s\n", cur_test->desc); continue; } result = cur_test->run (cur_test); if (result == TEST_PASSED) *pass_count += 1; else *fail_count += 1; display_result (cur_test, result); if (cleanup_test (cur_test) != 0) { printf ("error: cleanup failed for test %s\n", cur_test->desc); continue; } } } int main (void) { int pass_count, fail_count; time_t cur_time; time (&cur_time); printf("BGP Multipath Tests Run at %s", ctime(&cur_time)); if (global_test_init () != 0) { printf("Global init failed. Terminating.\n"); exit(1); } run_tests (all_tests, all_tests_count, &pass_count, &fail_count); global_test_cleanup (); printf("Total pass/fail: %d/%d\n", pass_count, fail_count); return fail_count; } quagga-0.99.24.1/tests/bgp_capability_test.c0000644000175000017500000004332212476520570015556 00000000000000/* * Copyright (C) 2007 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define CAPABILITY 0 #define DYNCAP 1 #define OPT_PARAM 2 /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; static int tty = 0; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char data[1024]; int len; #define SHOULD_PARSE 0 #define SHOULD_ERR -1 int parses; /* whether it should parse or not */ as_t peek_for; /* what peek_for_as4_capability should say */ /* AFI/SAFI validation */ int validate_afi; afi_t afi; safi_t safi; #define VALID_AFI 1 #define INVALID_AFI 0 int afi_valid; } test_segments [] = { /* 0 */ { "caphdr", "capability header, and no more", { CAPABILITY_CODE_REFRESH, 0x0 }, 2, SHOULD_PARSE, }, /* 1 */ { "nodata", "header, no data but length says there is", { 0x1, 0xa }, 2, SHOULD_ERR, }, /* 2 */ { "padded", "valid, with padding", { CAPABILITY_CODE_REFRESH, 0x2, 0x0, 0x0 }, 4, SHOULD_PARSE, }, /* 3 */ { "minsize", "violates minsize requirement", { CAPABILITY_CODE_ORF, 0x2, 0x0, 0x0 }, 4, SHOULD_ERR, }, { NULL, NULL, {0}, 0, 0}, }; static struct test_segment mp_segments[] = { { "MP4", "MP IP/Uni", { 0x1, 0x4, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { "MPv6", "MP IPv6/Uni", { 0x1, 0x4, 0x0, 0x2, 0x0, 0x1 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_UNICAST, VALID_AFI, }, /* 5 */ { "MP2", "MP IP/Multicast", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x2 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_MULTICAST, VALID_AFI, }, /* 6 */ { "MP3", "MP IP6/MPLS-labeled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x80 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 7 */ { "MP5", "MP IP6/MPLS-VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x2, 0x0, 0x4 }, 6, SHOULD_PARSE, 0, 1, AFI_IP6, SAFI_MPLS_VPN, VALID_AFI, }, /* 8 */ { "MP6", "MP IP4/MPLS-laveled VPN", { CAPABILITY_CODE_MP, 0x4, 0x0, 0x1, 0x0, 0x80 }, 6, SHOULD_PARSE, 0, 1, AFI_IP, SAFI_MPLS_LABELED_VPN, VALID_AFI, }, /* 10 */ { "MP8", "MP unknown AFI/SAFI", { CAPABILITY_CODE_MP, 0x4, 0x0, 0xa, 0x0, 0x81 }, 6, SHOULD_PARSE, 0, 1, 0xa, 0x81, INVALID_AFI, /* parses, but unknown */ }, /* 11 */ { "MP-short", "MP IP4/Unicast, length too short (< minimum)", { CAPABILITY_CODE_MP, 0x2, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_ERR, }, /* 12 */ { "MP-overflow", "MP IP4/Unicast, length too long", { CAPABILITY_CODE_MP, 0x6, 0x0, 0x1, 0x0, 0x1 }, 6, SHOULD_ERR, 0, 1, AFI_IP, SAFI_UNICAST, VALID_AFI, }, { NULL, NULL, {0}, 0, 0} }; static struct test_segment misc_segments[] = { /* 13 */ { "ORF", "ORF, simple, single entry, single tuple", { /* hdr */ CAPABILITY_CODE_ORF, 0x7, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x1, /* tuples */ 0x40, 0x3 }, 9, SHOULD_PARSE, }, /* 14 */ { "ORF-many", "ORF, multi entry/tuple", { /* hdr */ CAPABILITY_CODE_ORF, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_BOTH, 0x80, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_BOTH, 0x80, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, ORF_MODE_RECEIVE, 0x80, ORF_MODE_SEND, 0x80, ORF_MODE_BOTH, }, 35, SHOULD_PARSE, }, /* 15 */ { "ORFlo", "ORF, multi entry/tuple, hdr length too short", { /* hdr */ CAPABILITY_CODE_ORF, 0x15, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_ERR, /* It should error on invalid Route-Refresh.. */ }, /* 16 */ { "ORFlu", "ORF, multi entry/tuple, length too long", { /* hdr */ 0x3, 0x22, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_ERR }, /* 17 */ { "ORFnu", "ORF, multi entry/tuple, entry number too long", { /* hdr */ 0x3, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x4, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_PARSE, /* parses, but last few tuples should be gibberish */ }, /* 18 */ { "ORFno", "ORF, multi entry/tuple, entry number too short", { /* hdr */ 0x3, 0x21, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x1, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, }, 35, SHOULD_PARSE, /* Parses, but should get gibberish afi/safis */ }, /* 17 */ { "ORFpad", "ORF, multi entry/tuple, padded to align", { /* hdr */ 0x3, 0x22, /* mpc */ 0x0, 0x1, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x1, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, /* mpc */ 0x0, 0x2, 0x0, 0x2, /* num */ 0x3, /* tuples */ 0x40, 0x3, 0x80, 0x1, 0x80, 0x2, 0x00, }, 36, SHOULD_PARSE, }, /* 19 */ { "AS4", "AS4 capability", { 0x41, 0x4, 0xab, 0xcd, 0xef, 0x12 }, /* AS: 2882400018 */ 6, SHOULD_PARSE, 2882400018, }, /* 20 */ { "GR", "GR capability", { /* hdr */ CAPABILITY_CODE_RESTART, 0xe, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 16, SHOULD_PARSE, }, /* 21 */ { "GR-short", "GR capability, but header length too short", { /* hdr */ 0x40, 0xa, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 16, SHOULD_PARSE, }, /* 22 */ { "GR-long", "GR capability, but header length too long", { /* hdr */ 0x40, 0xf, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, }, 16, SHOULD_ERR, }, { "GR-trunc", "GR capability, but truncated", { /* hdr */ 0x40, 0xf, /* R-bit, time */ 0xf1, 0x12, /* afi */ 0x0, 0x1, /* safi */ 0x1, /* flags */ 0xf, /* afi */ 0x0, 0x2, /* safi */ 0x1, /* flags */ 0x0, /* afi */ 0x0, 0x2, /* safi */ 0x2, /* flags */ 0x1, }, 15, SHOULD_ERR, }, { "GR-empty", "GR capability, but empty.", { /* hdr */ 0x40, 0x0, }, 2, SHOULD_ERR, }, { "MP-empty", "MP capability, but empty.", { /* hdr */ 0x1, 0x0, }, 2, SHOULD_ERR, }, { "ORF-empty", "ORF capability, but empty.", { /* hdr */ 0x3, 0x0, }, 2, SHOULD_ERR, }, { "AS4-empty", "AS4 capability, but empty.", { /* hdr */ 0x41, 0x0, }, 2, SHOULD_ERR, }, { "dyn-empty", "Dynamic capability, but empty.", { /* hdr */ 0x42, 0x0, }, 2, SHOULD_PARSE, }, { "dyn-old", "Dynamic capability (deprecated version)", { CAPABILITY_CODE_DYNAMIC, 0x0 }, 2, SHOULD_PARSE, }, { NULL, NULL, {0}, 0, 0} }; /* DYNAMIC message */ struct test_segment dynamic_cap_msgs[] = { { "DynCap", "Dynamic Capability Message, IP/Multicast", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 }, 7, SHOULD_PARSE, /* horrible alignment, just as with ORF */ }, { "DynCapLong", "Dynamic Capability Message, IP/Multicast, truncated", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2 }, 5, SHOULD_ERR, }, { "DynCapPadded", "Dynamic Capability Message, IP/Multicast, padded", { 0x0, 0x1, 0x4, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_ERR, /* No way to tell padding from data.. */ }, { "DynCapMPCpadded", "Dynamic Capability Message, IP/Multicast, cap data padded", { 0x0, 0x1, 0x5, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_PARSE, /* You can though add padding to the capability data */ }, { "DynCapMPCoverflow", "Dynamic Capability Message, IP/Multicast, cap data != length", { 0x0, 0x1, 0x3, 0x0, 0x1, 0x0, 0x2, 0x0 }, 8, SHOULD_ERR, }, { NULL, NULL, {0}, 0, 0} }; /* Entire Optional-Parameters block */ struct test_segment opt_params[] = { { "Cap-singlets", "One capability per Optional-Param", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x02, 0x02, 0x80, 0x00, /* RR (old) */ 0x02, 0x02, 0x02, 0x00, /* RR */ }, 24, SHOULD_PARSE, }, { "Cap-series", "Series of capability, one Optional-Param", { 0x02, 0x10, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x80, 0x00, /* RR (old) */ 0x02, 0x00, /* RR */ }, 18, SHOULD_PARSE, }, { "AS4more", "AS4 capability after other caps (singlets)", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x02, 0x02, 0x80, 0x00, /* RR (old) */ 0x02, 0x02, 0x02, 0x00, /* RR */ 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */ }, 32, SHOULD_PARSE, 196614, }, { "AS4series", "AS4 capability, in series of capabilities", { 0x02, 0x16, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/Uni */ 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/Uni */ 0x80, 0x00, /* RR (old) */ 0x02, 0x00, /* RR */ 0x41, 0x04, 0x00, 0x03, 0x00, 0x06 /* AS4: 1996614 */ }, 24, SHOULD_PARSE, 196614, }, { "AS4real", "AS4 capability, in series of capabilities", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, /* MP IPv4/uni */ 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, /* MP IPv6/uni */ 0x02, 0x02, 0x80, 0x00, /* RR old */ 0x02, 0x02, 0x02, 0x00, /* RR */ 0x02, 0x06, 0x41, 0x04, 0x00, 0x03, 0x00, 0x06, /* AS4 */ }, 32, SHOULD_PARSE, 196614, }, { "AS4real2", "AS4 capability, in series of capabilities", { 0x02, 0x06, 0x01, 0x04, 0x00, 0x01, 0x00, 0x01, 0x02, 0x06, 0x01, 0x04, 0x00, 0x02, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x06, 0x41, 0x04, 0x00, 0x00, 0xfc, 0x03, 0x02, 0x09, 0x82, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x80, 0x03, 0x02, 0x09, 0x03, 0x07, 0x00, 0x01, 0x00, 0x01, 0x01, 0x40, 0x03, 0x02, 0x02, 0x42, 0x00, }, 58, SHOULD_PARSE, 64515, }, { NULL, NULL, {0}, 0, 0} }; /* basic parsing test */ static void parse_test (struct peer *peer, struct test_segment *t, int type) { int ret; int capability = 0; as_t as4 = 0; int oldfailed = failed; int len = t->len; #define RANDOM_FUZZ 35 stream_reset (peer->ibuf); stream_put (peer->ibuf, NULL, RANDOM_FUZZ); stream_set_getp (peer->ibuf, RANDOM_FUZZ); switch (type) { case CAPABILITY: stream_putc (peer->ibuf, BGP_OPEN_OPT_CAP); stream_putc (peer->ibuf, t->len); break; case DYNCAP: /* for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (peer->, 0xff); stream_putw (s, 0); stream_putc (s, BGP_MSG_CAPABILITY);*/ break; } stream_write (peer->ibuf, t->data, t->len); printf ("%s: %s\n", t->name, t->desc); switch (type) { case CAPABILITY: len += 2; /* to cover the OPT-Param header */ case OPT_PARAM: printf ("len: %u\n", len); /* peek_for_as4 wants getp at capibility*/ as4 = peek_for_as4_capability (peer, len); printf ("peek_for_as4: as4 is %u\n", as4); /* and it should leave getp as it found it */ assert (stream_get_getp (peer->ibuf) == RANDOM_FUZZ); ret = bgp_open_option_parse (peer, len, &capability); break; case DYNCAP: ret = bgp_capability_receive (peer, t->len); break; default: printf ("unknown type %u\n", type); exit(1); } if (!ret && t->validate_afi) { safi_t safi = t->safi; if (bgp_afi_safi_valid_indices (t->afi, &safi) != t->afi_valid) failed++; printf ("MP: %u/%u (%u): recv %u, nego %u\n", t->afi, t->safi, safi, peer->afc_recv[t->afi][safi], peer->afc_nego[t->afi][safi]); if (t->afi_valid == VALID_AFI) { if (!peer->afc_recv[t->afi][safi]) failed++; if (!peer->afc_nego[t->afi][safi]) failed++; } } if (as4 != t->peek_for) { printf ("as4 %u != %u\n", as4, t->peek_for); failed++; } printf ("parsed?: %s\n", ret ? "no" : "yes"); if (ret != t->parses) failed++; if (tty) printf ("%s", (failed > oldfailed) ? VT100_RED "failed!" VT100_RESET : VT100_GREEN "OK" VT100_RESET); else printf ("%s", (failed > oldfailed) ? "failed!" : "OK" ); if (failed) printf (" (%u)", failed); printf ("\n\n"); } static struct bgp *bgp; static as_t asn = 100; int main (void) { struct peer *peer; int i, j; conf_bgp_debug_fsm = -1UL; conf_bgp_debug_events = -1UL; conf_bgp_debug_packet = -1UL; conf_bgp_debug_normal = -1UL; conf_bgp_debug_as4 = -1UL; term_bgp_debug_fsm = -1UL; term_bgp_debug_events = -1UL; term_bgp_debug_packet = -1UL; term_bgp_debug_normal = -1UL; term_bgp_debug_as4 = -1UL; master = thread_master_create (); bgp_master_init (); bgp_option_set (BGP_OPT_NO_LISTEN); if (fileno (stdout) >= 0) tty = isatty (fileno (stdout)); if (bgp_get (&bgp, &asn, NULL)) return -1; peer = peer_create_accept (bgp); peer->host = (char *) "foo"; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) { peer->afc[i][j] = 1; peer->afc_adv[i][j] = 1; } i = 0; while (mp_segments[i].name) parse_test (peer, &mp_segments[i++], CAPABILITY); /* These tests assume mp_segments tests set at least * one of the afc_nego's */ i = 0; while (test_segments[i].name) parse_test (peer, &test_segments[i++], CAPABILITY); i = 0; while (misc_segments[i].name) parse_test (peer, &misc_segments[i++], CAPABILITY); i = 0; while (opt_params[i].name) parse_test (peer, &opt_params[i++], OPT_PARAM); SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); peer->status = Established; i = 0; while (dynamic_cap_msgs[i].name) parse_test (peer, &dynamic_cap_msgs[i++], DYNCAP); printf ("failures: %d\n", failed); return failed; } quagga-0.99.24.1/tests/test-timer-performance.c0000644000175000017500000000565212476520570016146 00000000000000/* * Test program which measures the time it takes to schedule and * remove timers. * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include "thread.h" #include "pqueue.h" #include "prng.h" #define SCHEDULE_TIMERS 1000000 #define REMOVE_TIMERS 500000 struct thread_master *master; static int dummy_func(struct thread *thread) { return 0; } int main(int argc, char **argv) { struct prng *prng; int i; struct thread **timers; struct timeval tv_start, tv_lap, tv_stop; unsigned long t_schedule, t_remove; master = thread_master_create(); prng = prng_new(0); timers = calloc(SCHEDULE_TIMERS, sizeof(*timers)); /* create thread structures so they won't be allocated during the * time measurement */ for (i = 0; i < SCHEDULE_TIMERS; i++) timers[i] = thread_add_timer_msec(master, dummy_func, NULL, 0); for (i = 0; i < SCHEDULE_TIMERS; i++) thread_cancel(timers[i]); quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_start); for (i = 0; i < SCHEDULE_TIMERS; i++) { long interval_msec; interval_msec = prng_rand(prng) % (100 * SCHEDULE_TIMERS); timers[i] = thread_add_timer_msec(master, dummy_func, NULL, interval_msec); } quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_lap); for (i = 0; i < REMOVE_TIMERS; i++) { int index; index = prng_rand(prng) % SCHEDULE_TIMERS; if (timers[index]) thread_cancel(timers[index]); timers[index] = NULL; } quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv_stop); t_schedule = 1000 * (tv_lap.tv_sec - tv_start.tv_sec); t_schedule += (tv_lap.tv_usec - tv_start.tv_usec) / 1000; t_remove = 1000 * (tv_stop.tv_sec - tv_lap.tv_sec); t_remove += (tv_stop.tv_usec - tv_lap.tv_usec) / 1000; printf("Scheduling %d random timers took %ld.%03ld seconds.\n", SCHEDULE_TIMERS, t_schedule/1000, t_schedule%1000); printf("Removing %d random timers took %ld.%03ld seconds.\n", REMOVE_TIMERS, t_remove/1000, t_remove%1000); fflush(stdout); free(timers); thread_master_free(master); prng_free(prng); return 0; } quagga-0.99.24.1/tests/prng.c0000644000175000017500000000551712476520570012520 00000000000000/* * Very simple prng to allow for randomized tests with reproducable * results. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include "prng.h" struct prng { unsigned long long state1; unsigned long long state2; }; static char prng_bit(struct prng *prng) { prng->state1 *= 2416; prng->state1 += 374441; prng->state1 %= 1771875; if (prng->state1 % 2) { prng->state2 *= 84589; prng->state2 += 45989; prng->state2 %= 217728; } return prng->state2 % 2; } struct prng* prng_new(unsigned long long seed) { struct prng *rv = calloc(sizeof(*rv), 1); assert(rv); rv->state1 = rv->state2 = seed; return rv; } unsigned int prng_rand(struct prng *prng) { unsigned int i, rv = 0; for (i = 0; i < 32; i++) { rv |= prng_bit(prng); rv <<= 1; } return rv; } const char * prng_fuzz(struct prng *prng, const char *string, const char *charset, unsigned int operations) { static char buf[256]; unsigned int charset_len; unsigned int i; unsigned int offset; unsigned int op; unsigned int character; assert(strlen(string) < sizeof(buf)); strncpy(buf, string, sizeof(buf)); charset_len = strlen(charset); for (i = 0; i < operations; i++) { offset = prng_rand(prng) % strlen(buf); op = prng_rand(prng) % 3; switch (op) { case 0: /* replace */ character = prng_rand(prng) % charset_len; buf[offset] = charset[character]; break; case 1: /* remove */ memmove(buf + offset, buf + offset + 1, strlen(buf) - offset); break; case 2: /* insert */ assert(strlen(buf) + 1 < sizeof(buf)); memmove(buf + offset + 1, buf + offset, strlen(buf) + 1 - offset); character = prng_rand(prng) % charset_len; buf[offset] = charset[character]; break; } } return buf; } void prng_free(struct prng *prng) { free(prng); } quagga-0.99.24.1/tests/test-timer-correctness.c0000644000175000017500000001154512476520570016175 00000000000000/* * Test program to verify that scheduled timers are executed in the * correct order. * * Copyright (C) 2013 by Open Source Routing. * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include #include "memory.h" #include "pqueue.h" #include "prng.h" #include "thread.h" #define SCHEDULE_TIMERS 800 #define REMOVE_TIMERS 200 #define TIMESTR_LEN strlen("4294967296.999999") struct thread_master *master; static size_t log_buf_len; static size_t log_buf_pos; static char *log_buf; static size_t expected_buf_len; static size_t expected_buf_pos; static char *expected_buf; static struct prng *prng; static struct thread **timers; static int timers_pending; static void terminate_test(void) { int exit_code; if (strcmp(log_buf, expected_buf)) { fprintf(stderr, "Expected output and received output differ.\n"); fprintf(stderr, "---Expected output: ---\n%s", expected_buf); fprintf(stderr, "---Actual output: ---\n%s", log_buf); exit_code = 1; } else { printf("Expected output and actual output match.\n"); exit_code = 0; } thread_master_free(master); XFREE(MTYPE_TMP, log_buf); XFREE(MTYPE_TMP, expected_buf); prng_free(prng); XFREE(MTYPE_TMP, timers); exit(exit_code); } static int timer_func(struct thread *thread) { int rv; rv = snprintf(log_buf + log_buf_pos, log_buf_len - log_buf_pos, "%s\n", (char*)thread->arg); assert(rv >= 0); log_buf_pos += rv; assert(log_buf_pos < log_buf_len); XFREE(MTYPE_TMP, thread->arg); timers_pending--; if (!timers_pending) terminate_test(); return 0; } static int cmp_timeval(const void* a, const void *b) { const struct timeval *ta = *(struct timeval * const *)a; const struct timeval *tb = *(struct timeval * const *)b; if (timercmp(ta, tb, <)) return -1; if (timercmp(ta, tb, >)) return 1; return 0; } int main(int argc, char **argv) { int i, j; struct thread t; struct timeval **alarms; master = thread_master_create(); log_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; log_buf_pos = 0; log_buf = XMALLOC(MTYPE_TMP, log_buf_len); expected_buf_len = SCHEDULE_TIMERS * (TIMESTR_LEN + 1) + 1; expected_buf_pos = 0; expected_buf = XMALLOC(MTYPE_TMP, expected_buf_len); prng = prng_new(0); timers = XMALLOC(MTYPE_TMP, SCHEDULE_TIMERS * sizeof(*timers)); for (i = 0; i < SCHEDULE_TIMERS; i++) { long interval_msec; int ret; char *arg; /* Schedule timers to expire in 0..5 seconds */ interval_msec = prng_rand(prng) % 5000; arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1); timers[i] = thread_add_timer_msec(master, timer_func, arg, interval_msec); ret = snprintf(arg, TIMESTR_LEN + 1, "%ld.%06ld", timers[i]->u.sands.tv_sec, timers[i]->u.sands.tv_usec); assert(ret > 0); assert((size_t)ret < TIMESTR_LEN + 1); timers_pending++; } for (i = 0; i < REMOVE_TIMERS; i++) { int index; index = prng_rand(prng) % SCHEDULE_TIMERS; if (!timers[index]) continue; XFREE(MTYPE_TMP, timers[index]->arg); thread_cancel(timers[index]); timers[index] = NULL; timers_pending--; } /* We create an array of pointers to the alarm times and sort * that array. That sorted array is used to generate a string * representing the expected "output" of the timers when they * are run. */ j = 0; alarms = XMALLOC(MTYPE_TMP, timers_pending * sizeof(*alarms)); for (i = 0; i < SCHEDULE_TIMERS; i++) { if (!timers[i]) continue; alarms[j++] = &timers[i]->u.sands; } qsort(alarms, j, sizeof(*alarms), cmp_timeval); for (i = 0; i < j; i++) { int ret; ret = snprintf(expected_buf + expected_buf_pos, expected_buf_len - expected_buf_pos, "%ld.%06ld\n", alarms[i]->tv_sec, alarms[i]->tv_usec); assert(ret > 0); expected_buf_pos += ret; assert(expected_buf_pos < expected_buf_len); } XFREE(MTYPE_TMP, alarms); while (thread_fetch(master, &t)) thread_call(&t); return 0; } quagga-0.99.24.1/tests/table_test.c0000644000175000017500000002733412476520570013701 00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * Routing table test * Copyright (C) 2012 OSR. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "table.h" /* * test_node_t * * Information that is kept for each node in the radix tree. */ typedef struct test_node_t_ { /* * Human readable representation of the string. Allocated using * malloc()/dup(). */ char *prefix_str; } test_node_t; struct thread_master *master; /* * add_node * * Add the given prefix (passed in as a string) to the given table. */ static void add_node (struct route_table *table, const char *prefix_str) { struct prefix_ipv4 p; test_node_t *node; struct route_node *rn; assert (prefix_str); if (str2prefix_ipv4 (prefix_str, &p) <= 0) { assert (0); } rn = route_node_get (table, (struct prefix *) &p); if (rn->info) { assert (0); return; } node = malloc (sizeof (test_node_t)); assert (node); node->prefix_str = strdup (prefix_str); assert (node->prefix_str); rn->info = node; } /* * add_nodes * * Convenience function to add a bunch of nodes together. * * The arguments must be prefixes in string format, with a NULL as the * last argument. */ static void add_nodes (struct route_table *table, ...) { va_list arglist; char *prefix; va_start (arglist, table); prefix = va_arg (arglist, char *); while (prefix) { add_node (table, prefix); prefix = va_arg (arglist, char *); } va_end (arglist); } /* * print_subtree * * Recursive function to print a route node and its children. * * @see print_table */ static void print_subtree (struct route_node *rn, const char *legend, int indent_level) { char buf[INET_ADDRSTRLEN + 4]; int i; /* * Print this node first. */ for (i = 0; i < indent_level; i++) { printf (" "); } prefix2str (&rn->p, buf, sizeof (buf)); printf ("%s: %s", legend, buf); if (!rn->info) { printf (" (internal)"); } printf ("\n"); if (rn->l_left) { print_subtree (rn->l_left, "Left", indent_level + 1); } if (rn->l_right) { print_subtree (rn->l_right, "Right", indent_level + 1); } } /* * print_table * * Function that prints out the internal structure of a route table. */ static void print_table (struct route_table *table) { struct route_node *rn; rn = table->top; if (!rn) { printf ("\n"); return; } print_subtree (rn, "Top", 0); } /* * clear_table * * Remove all nodes from the given table. */ static void clear_table (struct route_table *table) { route_table_iter_t iter; struct route_node *rn; test_node_t *node; route_table_iter_init (&iter, table); while ((rn = route_table_iter_next (&iter))) { node = rn->info; if (!node) { continue; } rn->info = NULL; route_unlock_node (rn); free (node->prefix_str); free (node); } route_table_iter_cleanup (&iter); assert (table->top == NULL); } /* * verify_next_by_iterating * * Iterate over the tree to make sure that the first prefix after * target_pfx is the expected one. Note that target_pfx may not be * present in the tree. */ static void verify_next_by_iterating (struct route_table *table, struct prefix *target_pfx, struct prefix *next_pfx) { route_table_iter_t iter; struct route_node *rn; route_table_iter_init (&iter, table); while ((rn = route_table_iter_next (&iter))) { if (route_table_prefix_iter_cmp (&rn->p, target_pfx) > 0) { assert (!prefix_cmp (&rn->p, next_pfx)); break; } } if (!rn) { assert (!next_pfx); } route_table_iter_cleanup (&iter); } /* * verify_next * * Verifies that route_table_get_next() returns the expected result * (result) for the prefix string 'target'. */ static void verify_next (struct route_table *table, const char *target, const char *next) { struct prefix_ipv4 target_pfx, next_pfx; struct route_node *rn; char result_buf[INET_ADDRSTRLEN + 4]; if (str2prefix_ipv4 (target, &target_pfx) <= 0) { assert (0); } rn = route_table_get_next (table, (struct prefix *) &target_pfx); if (rn) { prefix2str (&rn->p, result_buf, sizeof (result_buf)); } else { snprintf (result_buf, sizeof (result_buf), "(Null)"); } printf ("\n"); print_table (table); printf ("Verifying successor of %s. Expected: %s, Result: %s\n", target, next ? next : "(Null)", result_buf); if (!rn) { assert (!next); verify_next_by_iterating (table, (struct prefix *) &target_pfx, NULL); return; } assert (next); if (str2prefix_ipv4 (next, &next_pfx) <= 0) { assert (0); } if (prefix_cmp (&rn->p, (struct prefix *) &next_pfx)) { assert (0); } route_unlock_node (rn); verify_next_by_iterating (table, (struct prefix *) &target_pfx, (struct prefix *) &next_pfx); } /* * test_get_next */ static void test_get_next (void) { struct route_table *table; printf ("\n\nTesting route_table_get_next()\n"); table = route_table_init (); /* * Target exists in tree, but has no successor. */ add_nodes (table, "1.0.1.0/24", NULL); verify_next (table, "1.0.1.0/24", NULL); clear_table (table); /* * Target exists in tree, and there is a node in its left subtree. */ add_nodes (table, "1.0.1.0/24", "1.0.1.0/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); clear_table (table); /* * Target exists in tree, and there is a node in its right subtree. */ add_nodes (table, "1.0.1.0/24", "1.0.1.128/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); clear_table (table); /* * Target exists in the tree, next node is outside subtree. */ add_nodes (table, "1.0.1.0/24", "1.1.0.0/16", NULL); verify_next (table, "1.0.1.0/24", "1.1.0.0/16"); clear_table (table); /* * The target node does not exist in the tree for all the test cases * below this point. */ /* * There is no successor in the tree. */ add_nodes (table, "1.0.0.0/16", NULL); verify_next (table, "1.0.1.0/24", NULL); clear_table (table); /* * There exists a node that would be in the target's left subtree. */ add_nodes (table, "1.0.0.0/16", "1.0.1.0/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.0/25"); clear_table (table); /* * There exists a node would be in the target's right subtree. */ add_nodes (table, "1.0.0.0/16", "1.0.1.128/25", NULL); verify_next (table, "1.0.1.0/24", "1.0.1.128/25"); clear_table (table); /* * A search for the target reaches a node where there are no child * nodes in the direction of the target (left), but the node has a * right child. */ add_nodes (table, "1.0.0.0/16", "1.0.128.0/17", NULL); verify_next (table, "1.0.0.0/17", "1.0.128.0/17"); clear_table (table); /* * A search for the target reaches a node with no children. We have * to go upwards in the tree to find a successor. */ add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/24", "1.0.128.0/17", NULL); verify_next (table, "1.0.1.0/25", "1.0.128.0/17"); clear_table (table); /* * A search for the target reaches a node where neither the node nor * the target prefix contain each other. * * In first case below the node succeeds the target. * * In the second case, the node comes before the target, so we have * to go up the tree looking for a successor. */ add_nodes (table, "1.0.0.0/16", "1.0.1.0/24", NULL); verify_next (table, "1.0.0.0/24", "1.0.1.0/24"); clear_table (table); add_nodes (table, "1.0.0.0/16", "1.0.0.0/24", "1.0.1.0/25", "1.0.128.0/17", NULL); verify_next (table, "1.0.1.128/25", "1.0.128.0/17"); clear_table (table); route_table_finish (table); } /* * verify_prefix_iter_cmp */ static void verify_prefix_iter_cmp (const char *p1, const char *p2, int exp_result) { struct prefix_ipv4 p1_pfx, p2_pfx; int result; if (str2prefix_ipv4 (p1, &p1_pfx) <= 0) { assert (0); } if (str2prefix_ipv4 (p2, &p2_pfx) <= 0) { assert (0); } result = route_table_prefix_iter_cmp ((struct prefix *) &p1_pfx, (struct prefix *) &p2_pfx); printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); assert (exp_result == result); /* * Also check the reverse comparision. */ result = route_table_prefix_iter_cmp ((struct prefix *) &p2_pfx, (struct prefix *) &p1_pfx); if (exp_result) { exp_result = -exp_result; } printf ("Verifying cmp(%s, %s) returns %d\n", p1, p2, exp_result); assert (result == exp_result); } /* * test_prefix_iter_cmp * * Tests comparision of prefixes according to order of iteration. */ static void test_prefix_iter_cmp () { printf ("\n\nTesting route_table_prefix_iter_cmp()\n"); verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/8", 0); verify_prefix_iter_cmp ("1.0.0.0/8", "1.0.0.0/16", -1); verify_prefix_iter_cmp ("1.0.0.0/16", "1.128.0.0/16", -1); } /* * verify_iter_with_pause * * Iterates over a tree using two methods: 'normal' iteration, and an * iterator that pauses at each node. Verifies that the two methods * yield the same results. */ static void verify_iter_with_pause (struct route_table *table) { unsigned long num_nodes; struct route_node *rn, *iter_rn; route_table_iter_t iter_space; route_table_iter_t *iter = &iter_space; route_table_iter_init (iter, table); num_nodes = 0; for (rn = route_top (table); rn; rn = route_next (rn)) { num_nodes++; route_table_iter_pause (iter); assert (iter->current == NULL); if (route_table_iter_started (iter)) { assert (iter->state == RT_ITER_STATE_PAUSED); } else { assert (rn == table->top); assert (iter->state == RT_ITER_STATE_INIT); } iter_rn = route_table_iter_next (iter); /* * Make sure both iterations return the same node. */ assert (rn == iter_rn); } assert (num_nodes == route_table_count (table)); route_table_iter_pause (iter); iter_rn = route_table_iter_next (iter); assert (iter_rn == NULL); assert (iter->state == RT_ITER_STATE_DONE); assert (route_table_iter_next (iter) == NULL); assert (iter->state == RT_ITER_STATE_DONE); route_table_iter_cleanup (iter); print_table (table); printf ("Verified pausing iteration on tree with %lu nodes\n", num_nodes); } /* * test_iter_pause */ static void test_iter_pause (void) { struct route_table *table; int i, num_prefixes; const char *prefixes[] = { "1.0.1.0/24", "1.0.1.0/25", "1.0.1.128/25", "1.0.2.0/24", "2.0.0.0/8" }; num_prefixes = sizeof (prefixes) / sizeof (prefixes[0]); printf ("\n\nTesting that route_table_iter_pause() works as expected\n"); table = route_table_init (); for (i = 0; i < num_prefixes; i++) { add_nodes (table, prefixes[i], NULL); } verify_iter_with_pause (table); clear_table (table); route_table_finish (table); } /* * run_tests */ static void run_tests (void) { test_prefix_iter_cmp (); test_get_next (); test_iter_pause (); } /* * main */ int main (void) { run_tests (); } quagga-0.99.24.1/tests/heavy-wq.c0000644000175000017500000001006712476520570013307 00000000000000/* * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that the vty interface is unresponsive * for quite a period of time, due to the clear_something command * taking a very long time to complete. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include "log.h" #include "workqueue.h" #include extern struct thread_master *master; static struct work_queue *heavy_wq; struct heavy_wq_node { char *str; int i; }; enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; static void heavy_wq_add (struct vty *vty, const char *str, int i) { struct heavy_wq_node *hn; if ((hn = XCALLOC (MTYPE_PREFIX_LIST, sizeof(struct heavy_wq_node))) == NULL) { zlog_err ("%s: unable to allocate hn", __func__); return; } hn->i = i; if (!(hn->str = XSTRDUP (MTYPE_PREFIX_LIST_STR, str))) { zlog_err ("%s: unable to xstrdup", __func__); XFREE (MTYPE_PREFIX_LIST, hn); return; } work_queue_add (heavy_wq, hn); return; } static void slow_func_err (struct work_queue *wq, struct work_queue_item *item) { printf ("%s: running error function\n", __func__); } static void slow_func_del (struct work_queue *wq, void *data) { struct heavy_wq_node *hn = data; assert (hn && hn->str); printf ("%s: %s\n", __func__, hn->str); XFREE (MTYPE_PREFIX_LIST_STR, hn->str); hn->str = NULL; XFREE(MTYPE_PREFIX_LIST, hn); } static wq_item_status slow_func (struct work_queue *wq, void *data) { struct heavy_wq_node *hn = data; double x = 1; int j; assert (hn && hn->str); for (j = 0; j < 300; j++) x += sin(x)*j; if ((hn->i % ITERS_LATER) == 0) return WQ_RETRY_LATER; if ((hn->i % ITERS_ERR) == 0) return WQ_RETRY_NOW; if ((hn->i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g\n", hn->str, hn->i, x); return WQ_SUCCESS; } static void clear_something (struct vty *vty, const char *str) { int i; /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ for (i = ITERS_FIRST; i < ITERS_MAX; i++) heavy_wq_add (vty, str, i); } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); clear_something (vty, str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } static int heavy_wq_init () { if (! (heavy_wq = work_queue_new (master, "heavy_work_queue"))) { zlog_err ("%s: could not get new work queue!", __func__); return -1; } heavy_wq->spec.workfunc = &slow_func; heavy_wq->spec.errorfunc = &slow_func_err; heavy_wq->spec.del_item_data = &slow_func_del; heavy_wq->spec.max_retries = 3; heavy_wq->spec.hold = 1000; return 0; } void test_init() { install_element (VIEW_NODE, &clear_foo_cmd); heavy_wq_init(); } quagga-0.99.24.1/tests/heavy-thread.c0000644000175000017500000000665212476520570014134 00000000000000/* * $Id: heavy-thread.c,v 1.2 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model, as demonstrated by heavy.c, and how * they can be mitigated using a background thread. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that, unlike heavy.c, the vty interface * remains responsive. */ #include #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include "log.h" extern struct thread_master *master; enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; struct work_state { struct vty *vty; char *str; int i; }; static void slow_func (struct vty *vty, const char *str, const int i) { double x = 1; int j; for (j = 0; j < 300; j++) x += sin(x)*j; if ((i % ITERS_LATER) == 0) printf ("%s: %d, temporary error, save this somehow and do it later..\n", __func__, i); if ((i % ITERS_ERR) == 0) printf ("%s: hard error\n", __func__); if ((i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g\n", str, i, x); } static int clear_something (struct thread *thread) { struct work_state *ws = THREAD_ARG(thread); /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ while (ws->i < ITERS_MAX) { slow_func(ws->vty, ws->str, ws->i); ws->i++; if (thread_should_yield(thread)) { thread_add_background(master, clear_something, ws, 0); return 0; } } /* All done! */ XFREE (MTYPE_TMP, ws->str); XFREE (MTYPE_TMP, ws); return 0; } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; struct work_state *ws; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); if ((ws = XMALLOC(MTYPE_TMP, sizeof(*ws))) == NULL) { zlog_err ("%s: unable to allocate work_state", __func__); return CMD_WARNING; } if (!(ws->str = XSTRDUP (MTYPE_TMP, str))) { zlog_err ("%s: unable to xstrdup", __func__); XFREE (MTYPE_TMP, ws); return CMD_WARNING; } ws->vty = vty; ws->i = ITERS_FIRST; thread_add_background(master, clear_something, ws, 0); return CMD_SUCCESS; } void test_init() { install_element (VIEW_NODE, &clear_foo_cmd); } quagga-0.99.24.1/tests/main.c0000644000175000017500000001040112476520570012462 00000000000000/* * $Id: main.c,v 1.1 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" extern void test_init(); struct thread_master *master; struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "version", no_argument, NULL, 'v'}, { 0 } }; DEFUN (daemon_exit, daemon_exit_cmd, "daemon-exit", "Make the daemon exit\n") { exit(0); } static int timer_count; int test_timer (struct thread *thread) { int *count = THREAD_ARG(thread); printf ("run %d of timer\n", (*count)++); thread_add_timer (master, test_timer, count, 5); return 0; } static void test_timer_init() { thread_add_timer (master, test_timer, &timer_count, 10); } static void test_vty_init() { install_element (VIEW_NODE, &daemon_exit_cmd); } /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which does 'slow' things.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* main routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = 4000; int daemon_mode = 0; char *progname; struct thread thread; char *config_file = NULL; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* master init. */ master = thread_master_create (); while (1) { int opt; opt = getopt_long (argc, argv, "dhf:A:P:v", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'f': config_file = optarg; break; case 'd': daemon_mode = 1; break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : 4000); break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Library inits. */ cmd_init (1); vty_init (master); memory_init (); /* OSPF vty inits. */ test_vty_init (); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { fprintf(stderr, "daemon failed: %s", strerror(errno)); exit (1); } /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, "/tmp/.heavy.sock"); /* Configuration file read*/ if (!config_file) usage (progname, 1); vty_read_config (config_file, NULL); test_timer_init(); test_init(); /* Fetch next active thread. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ exit (0); } quagga-0.99.24.1/tests/heavy.c0000644000175000017500000000532312476520570012661 00000000000000/* * $Id: heavy.c,v 1.3 2005/04/25 16:42:24 paul Exp $ * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This programme shows the effects of 'heavy' long-running functions * on the cooperative threading model. * * Run it with a config file containing 'password whatever', telnet to it * (it defaults to port 4000) and enter the 'clear foo string' command. * then type whatever and observe that the vty interface is unresponsive * for quite a period of time, due to the clear_something command * taking a very long time to complete. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "memory.h" #include enum { ITERS_FIRST = 0, ITERS_ERR = 100, ITERS_LATER = 400, ITERS_PRINT = 10, ITERS_MAX = 1000, }; static void slow_func (struct vty *vty, const char *str, const int i) { double x = 1; int j; for (j = 0; j < 300; j++) x += sin(x)*j; if ((i % ITERS_LATER) == 0) printf ("%s: %d, temporary error, save this somehow and do it later..\n", __func__, i); if ((i % ITERS_ERR) == 0) printf ("%s: hard error\n", __func__); if ((i % ITERS_PRINT) == 0) printf ("%s did %d, x = %g%s", str, i, x, VTY_NEWLINE); } static void clear_something (struct vty *vty, const char *str) { int i; /* this could be like iterating through 150k of route_table * or worse, iterating through a list of peers, to bgp_stop them with * each having 150k route tables to process... */ for (i = ITERS_FIRST; i < ITERS_MAX; i++) slow_func (vty, str, i); } DEFUN (clear_foo, clear_foo_cmd, "clear foo .LINE", "clear command\n" "arbitrary string\n") { char *str; if (!argc) { vty_out (vty, "%% string argument required%s", VTY_NEWLINE); return CMD_WARNING; } str = argv_concat (argv, argc, 0); clear_something (vty, str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } static void slow_vty_init() { install_element (VIEW_NODE, &clear_foo_cmd); } void test_init() { slow_vty_init(); } quagga-0.99.24.1/tests/ecommunity_test.c0000644000175000017500000000735212476520570015001 00000000000000/* * Copyright (C) 2007 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vty.h" #include "stream.h" #include "privs.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; /* specification for a test - what the results should be */ struct test_spec { const char *shouldbe; /* the string the path should parse to */ }; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_int8_t data[1024]; int len; struct test_spec sp; } test_segments [] = { { /* 0 */ "ipaddr", "rt 1.2.3.4:257", { ECOMMUNITY_ENCODE_IP, ECOMMUNITY_ROUTE_TARGET, 0x1,0x2,0x3,0x4, 0x1,0x1 }, 8, { "rt 1.2.3.4:257" } }, { /* 1 */ "ipaddr-so", "soo 1.2.3.4:257", { ECOMMUNITY_ENCODE_IP, ECOMMUNITY_SITE_ORIGIN, 0x1,0x2,0x3,0x4, 0x1,0x1}, 8, { "soo 1.2.3.4:257" } }, { /* 2 */ "asn", "rt 23456:987654321", { ECOMMUNITY_ENCODE_AS, ECOMMUNITY_SITE_ORIGIN, 0x5b,0xa0, 0x3a,0xde,0x68,0xb1 }, 8, { "soo 23456:987654321" } }, { /* 3 */ "asn4", "rt 168450976:4321", { ECOMMUNITY_ENCODE_AS4, ECOMMUNITY_SITE_ORIGIN, 0xa,0xa,0x5b,0xa0, 0x10,0xe1 }, 8, { "soo 168450976:4321" } }, { NULL, NULL, {0}, 0, { NULL } } }; /* validate the given aspath */ static int validate (struct ecommunity *ecom, const struct test_spec *sp) { int fails = 0; struct ecommunity *etmp; char *str1, *str2; printf ("got:\n %s\n", ecommunity_str (ecom)); str1 = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); etmp = ecommunity_str2com (str1, 0, 1); if (etmp) str2 = ecommunity_ecom2str (etmp, ECOMMUNITY_FORMAT_COMMUNITY_LIST); else str2 = NULL; if (strcmp (sp->shouldbe, str1)) { failed++; fails++; printf ("shouldbe: %s\n%s\n", str1, sp->shouldbe); } if (!etmp || strcmp (str1, str2)) { failed++; fails++; printf ("dogfood: in %s\n" " in->out %s\n", str1, (etmp && str2) ? str2 : "NULL"); } ecommunity_free (&etmp); XFREE (MTYPE_ECOMMUNITY_STR, str1); XFREE (MTYPE_ECOMMUNITY_STR, str2); return fails; } /* basic parsing test */ static void parse_test (struct test_segment *t) { struct ecommunity *ecom; printf ("%s: %s\n", t->name, t->desc); ecom = ecommunity_parse (t->data, t->len); printf ("ecom: %s\nvalidating...:\n", ecommunity_str (ecom)); if (!validate (ecom, &t->sp)) printf ("OK\n"); else printf ("failed\n"); printf ("\n"); ecommunity_unintern (&ecom); } int main (void) { int i = 0; ecommunity_init(); while (test_segments[i].name) parse_test (&test_segments[i++]); printf ("failures: %d\n", failed); //printf ("aspath count: %ld\n", aspath_count()); return failed; //return (failed + aspath_count()); } quagga-0.99.24.1/tests/aspath_test.c0000644000175000017500000012344112476520570014066 00000000000000/* * Copyright (C) 2005 Sun Microsystems, Inc. * * This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vty.h" #include "stream.h" #include "privs.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" #define VT100_RESET "\x1b[0m" #define VT100_RED "\x1b[31m" #define VT100_GREEN "\x1b[32m" #define VT100_YELLOW "\x1b[33m" #define OK VT100_GREEN "OK" VT100_RESET #define FAILED VT100_RED "failed" VT100_RESET /* need these to link in libbgp */ struct zebra_privs_t *bgpd_privs = NULL; struct thread_master *master = NULL; static int failed = 0; /* specification for a test - what the results should be */ struct test_spec { const char *shouldbe; /* the string the path should parse to */ const char *shouldbe_delete_confed; /* ditto, but once confeds are deleted */ const unsigned int hops; /* aspath_count_hops result */ const unsigned int confeds; /* aspath_count_confeds */ const int private_as; /* whether the private_as check should pass or fail */ #define NOT_ALL_PRIVATE 0 #define ALL_PRIVATE 1 const as_t does_loop; /* an ASN which should trigger loop-check */ const as_t doesnt_loop; /* one which should not */ const as_t first; /* the first ASN, if there is one */ #define NULL_ASN 0 }; /* test segments to parse and validate, and use for other tests */ static struct test_segment { const char *name; const char *desc; const u_char asdata[1024]; int len; struct test_spec sp; } test_segments [] = { { /* 0 */ "seq1", "seq(8466,3,52737,4096)", { 0x2,0x4, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00 }, 10, { "8466 3 52737 4096", "8466 3 52737 4096", 4, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 1 */ "seq2", "seq(8722) seq(4)", { 0x2,0x1, 0x22,0x12, 0x2,0x1, 0x00,0x04 }, 8, { "8722 4", "8722 4", 2, 0, NOT_ALL_PRIVATE, 4, 5, 8722, }, }, { /* 2 */ "seq3", "seq(8466,3,52737,4096,8722,4)", { 0x2,0x6, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x22,0x12, 0x00,0x04}, 14, { "8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 3, 5, 8466 }, }, { /* 3 */ "seqset", "seq(8482,51457) set(5204)", { 0x2,0x2, 0x21,0x22, 0xc9,0x01, 0x1,0x1, 0x14,0x54 }, 10, { "8482 51457 {5204}", "8482 51457 {5204}", 3, 0, NOT_ALL_PRIVATE, 5204, 51456, 8482}, }, { /* 4 */ "seqset2", "seq(8467, 59649) set(4196,48658) set(17322,30745)", { 0x2,0x2, 0x21,0x13, 0xe9,0x01, 0x1,0x2, 0x10,0x64, 0xbe,0x12, 0x1,0x2, 0x43,0xaa, 0x78,0x19 }, 18, { "8467 59649 {4196,48658} {17322,30745}", "8467 59649 {4196,48658} {17322,30745}", 4, 0, NOT_ALL_PRIVATE, 48658, 1, 8467}, }, { /* 5 */ "multi", "seq(6435,59408,21665) set(2457,61697,4369), seq(1842,41590,51793)", { 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x09,0x99, 0xf1,0x01, 0x11,0x11, 0x2,0x3, 0x07,0x32, 0xa2,0x76, 0xca,0x51 }, 24, { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { /* 6 */ "confed", "confseq(123,456,789)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15 }, 8, { "(123 456 789)", "", 0, 3, NOT_ALL_PRIVATE, 789, 1, NULL_ASN }, }, { /* 7 */ "confed2", "confseq(123,456,789) confseq(111,222)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x3,0x2, 0x00,0x6f, 0x00,0xde }, 14, { "(123 456 789) (111 222)", "", 0, 5, NOT_ALL_PRIVATE, 111, 1, NULL_ASN }, }, { /* 8 */ "confset", "confset(456,123,789)", { 0x4,0x3, 0x01,0xc8, 0x00,0x7b, 0x03,0x15 }, 8, { "[123,456,789]", "[123,456,789]", 0, 1, NOT_ALL_PRIVATE, 123, 1, NULL_ASN }, }, { /* 9 */ "confmulti", "confseq(123,456,789) confset(222,111) seq(8722) set(4196,48658)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x4,0x2, 0x00,0xde, 0x00,0x6f, 0x2,0x1, 0x22,0x12, 0x1,0x2, 0x10,0x64, 0xbe,0x12 }, 24, { "(123 456 789) [111,222] 8722 {4196,48658}", "8722 {4196,48658}", 2, 4, NOT_ALL_PRIVATE, 123, 1, NULL_ASN }, }, { /* 10 */ "seq4", "seq(8466,2,52737,4096,8722,4)", { 0x2,0x6, 0x21,0x12, 0x00,0x02, 0xce,0x01, 0x10,0x00, 0x22,0x12, 0x00,0x04}, 14, { "8466 2 52737 4096 8722 4", "8466 2 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, { /* 11 */ "tripleseq1", "seq(8466,2,52737) seq(4096,8722,4) seq(8722)", { 0x2,0x3, 0x21,0x12, 0x00,0x02, 0xce,0x01, 0x2,0x3, 0x10,0x00, 0x22,0x12, 0x00,0x04, 0x2,0x1, 0x22,0x12}, 20, { "8466 2 52737 4096 8722 4 8722", "8466 2 52737 4096 8722 4 8722", 7, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, { /* 12 */ "someprivate", "seq(8466,64512,52737,65535)", { 0x2,0x4, 0x21,0x12, 0xfc,0x00, 0xce,0x01, 0xff,0xff }, 10, { "8466 64512 52737 65535", "8466 64512 52737 65535", 4, 0, NOT_ALL_PRIVATE, 65535, 4, 8466 }, }, { /* 13 */ "allprivate", "seq(65534,64512,64513,65535)", { 0x2,0x4, 0xff,0xfe, 0xfc,0x00, 0xfc,0x01, 0xff,0xff }, 10, { "65534 64512 64513 65535", "65534 64512 64513 65535", 4, 0, ALL_PRIVATE, 65534, 4, 65534 }, }, { /* 14 */ "long", "seq(8466,3,52737,4096,34285,)", { 0x2,0xfa, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x85,0xed, }, 502, { "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285", "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285", 250, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 15 */ "seq1extra", "seq(8466,3,52737,4096,3456)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 }, 12, { "8466 3 52737 4096 3456", "8466 3 52737 4096 3456", 5, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 16 */ "empty", "", {}, 0, { "", "", 0, 0, 0, 0, 0, 0 }, }, { /* 17 */ "redundantset", "seq(8466,3,52737,4096,3456) set(7099,8153,8153,8153)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80, 0x1,0x4, 0x1b,0xbb, 0x1f,0xd9, 0x1f,0xd9, 0x1f,0xd9 }, 22, { /* We shouldn't ever /generate/ such paths. However, we should * cope with them fine. */ "8466 3 52737 4096 3456 {7099,8153}", "8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 18 */ "reconcile_lead_asp", "seq(6435,59408,21665) set(23456,23456,23456), seq(23456,23456,23456)", { 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, 24, { "6435 59408 21665 {23456} 23456 23456 23456", "6435 59408 21665 {23456} 23456 23456 23456", 7, 0, NOT_ALL_PRIVATE, 23456, 1, 6435 }, }, { /* 19 */ "reconcile_new_asp", "set(2457,61697,4369), seq(1842,41591,51793)", { 0x1,0x3, 0x09,0x99, 0xf1,0x01, 0x11,0x11, 0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51 }, 16, { "{2457,4369,61697} 1842 41591 51793", "{2457,4369,61697} 1842 41591 51793", 4, 0, NOT_ALL_PRIVATE, 51793, 1, 2457 }, }, { /* 20 */ "reconcile_confed", "confseq(123,456,789) confset(456,124,788) seq(6435,59408,21665)" " set(23456,23456,23456), seq(23456,23456,23456)", { 0x3,0x3, 0x00,0x7b, 0x01,0xc8, 0x03,0x15, 0x4,0x3, 0x01,0xc8, 0x00,0x7c, 0x03,0x14, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, 0x1,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0 }, 40, { "(123 456 789) [124,456,788] 6435 59408 21665" " {23456} 23456 23456 23456", "6435 59408 21665 {23456} 23456 23456 23456", 7, 4, NOT_ALL_PRIVATE, 23456, 1, 6435 }, }, { /* 21 */ "reconcile_start_trans", "seq(23456,23456,23456) seq(6435,59408,21665)", { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, 16, { "23456 23456 23456 6435 59408 21665", "23456 23456 23456 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 21665, 1, 23456 }, }, { /* 22 */ "reconcile_start_trans4", "seq(1842,41591,51793) seq(6435,59408,21665)", { 0x2,0x3, 0x07,0x32, 0xa2,0x77, 0xca,0x51, 0x2,0x3, 0x19,0x23, 0xe8,0x10, 0x54,0xa1, }, 16, { "1842 41591 51793 6435 59408 21665", "1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 41591, 1, 1842 }, }, { /* 23 */ "reconcile_start_trans_error", "seq(23456,23456,23456) seq(6435,59408)", { 0x2,0x3, 0x5b,0xa0, 0x5b,0xa0, 0x5b,0xa0, 0x2,0x2, 0x19,0x23, 0xe8,0x10, }, 14, { "23456 23456 23456 6435 59408", "23456 23456 23456 6435 59408", 5, 0, NOT_ALL_PRIVATE, 59408, 1, 23456 }, }, { /* 24 */ "redundantset2", "seq(8466,3,52737,4096,3456) set(7099,8153,8153,8153,7099)", { 0x2,0x5, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80, 0x1,0x5, 0x1b,0xbb, 0x1f,0xd9, 0x1f,0xd9, 0x1f,0xd9, 0x1b,0xbb,}, 24, { /* We should weed out duplicate set members. */ "8466 3 52737 4096 3456 {7099,8153}", "8466 3 52737 4096 3456 {7099,8153}", 6, 0, NOT_ALL_PRIVATE, 4096, 4, 8466 }, }, { /* 25 */ "zero-size overflow", "#ASNs = 0, data = seq(8466 3 52737 4096 3456)", { 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 }, 12, { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { /* 26 */ "zero-size overflow + valid segment", "seq(#AS=0:8466 3 52737),seq(4096 3456)", { 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x2,0x2, 0x10,0x00, 0x0d,0x80 }, 14 , { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { /* 27 */ "invalid segment type", "type=8(4096 3456)", { 0x8,0x2, 0x10,0x00, 0x0d,0x80 }, 14 , { NULL, NULL, 0, 0, 0, 0, 0, 0 }, }, { NULL, NULL, {0}, 0, { NULL, 0, 0 } } }; #define COMMON_ATTRS \ BGP_ATTR_FLAG_TRANS, \ BGP_ATTR_ORIGIN, \ 1, \ BGP_ORIGIN_EGP, \ BGP_ATTR_FLAG_TRANS, \ BGP_ATTR_NEXT_HOP, \ 4, 192, 0, 2, 0 #define COMMON_ATTR_SIZE 11 /* */ static struct aspath_tests { const char *desc; const struct test_segment *segment; const char *shouldbe; /* String it should evaluate to */ const enum as4 { AS4_DATA, AS2_DATA } as4; /* whether data should be as4 or not (ie as2) */ const int result; /* expected result for bgp_attr_parse */ const int cap; /* capabilities to set for peer */ const char attrheader [1024]; size_t len; const struct test_segment *old_segment; } aspath_tests [] = { /* 0 */ { "basic test", &test_segments[0], "8466 3 52737 4096", AS2_DATA, 0, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 1 */ { "length too short", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8, }, COMMON_ATTR_SIZE + 3, }, /* 2 */ { "length too long", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12, }, COMMON_ATTR_SIZE + 3, }, /* 3 */ { "incorrect flag", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 4 */ { "as4_path, with as2 format data", &test_segments[0], "8466 3 52737 4096", AS2_DATA, -1, 0, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 5 */ { "as4, with incorrect attr length", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 10, }, COMMON_ATTR_SIZE + 3, }, /* 6 */ { "basic 4-byte as-path", &test_segments[0], "8466 3 52737 4096", AS4_DATA, 0, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18, }, COMMON_ATTR_SIZE + 3, }, /* 7 */ { "4b AS_PATH: too short", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16, }, COMMON_ATTR_SIZE + 3, }, /* 8 */ { "4b AS_PATH: too long", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20, }, COMMON_ATTR_SIZE + 3, }, /* 9 */ { "4b AS_PATH: too long2", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22, }, COMMON_ATTR_SIZE + 3, }, /* 10 */ { "4b AS_PATH: bad flags", &test_segments[0], "8466 3 52737 4096", AS4_DATA, -1, PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS_PATH, 18, }, COMMON_ATTR_SIZE + 3, }, /* 11 */ { "4b AS4_PATH w/o AS_PATH", &test_segments[6], NULL, AS4_DATA, -1, PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, COMMON_ATTR_SIZE + 3, }, /* 12 */ { "4b AS4_PATH: confed", &test_segments[6], "8466 3 52737 4096 (123 456 789)", AS4_DATA, 0, PEER_CAP_AS4_ADV, { COMMON_ATTRS, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL, BGP_ATTR_AS4_PATH, 14, }, COMMON_ATTR_SIZE + 3, &test_segments[0], }, { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 }, }; /* prepending tests */ static struct tests { const struct test_segment *test1; const struct test_segment *test2; struct test_spec sp; } prepend_tests[] = { /* 0 */ { &test_segments[0], &test_segments[1], { "8466 3 52737 4096 8722 4", "8466 3 52737 4096 8722 4", 6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 }, }, /* 1 */ { &test_segments[1], &test_segments[3], { "8722 4 8482 51457 {5204}", "8722 4 8482 51457 {5204}", 5, 0, NOT_ALL_PRIVATE, 5204, 1, 8722 } }, /* 2 */ { &test_segments[3], &test_segments[4], { "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}", "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}", 7, 0, NOT_ALL_PRIVATE, 5204, 1, 8482 }, }, /* 3 */ { &test_segments[4], &test_segments[5], { "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665" " {2457,4369,61697} 1842 41590 51793", "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665" " {2457,4369,61697} 1842 41590 51793", 11, 0, NOT_ALL_PRIVATE, 61697, 1, 8467 } }, /* 4 */ { &test_segments[5], &test_segments[6], { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", "6435 59408 21665 {2457,4369,61697} 1842 41590 51793", 7, 0, NOT_ALL_PRIVATE, 1842, 1, 6435 }, }, /* 5 */ { &test_segments[6], &test_segments[7], { "(123 456 789) (123 456 789) (111 222)", "", 0, 8, NOT_ALL_PRIVATE, 111, 1, 0 } }, { &test_segments[7], &test_segments[8], { "(123 456 789) (111 222) [123,456,789]", "", 0, 6, NOT_ALL_PRIVATE, 111, 1, 0 } }, { &test_segments[8], &test_segments[9], { "[123,456,789] (123 456 789) [111,222] 8722 {4196,48658}", "[123,456,789] (123 456 789) [111,222] 8722 {4196,48658}", 2, 5, NOT_ALL_PRIVATE, 456, 1, NULL_ASN }, }, { &test_segments[9], &test_segments[8], { "(123 456 789) [111,222] 8722 {4196,48658} [123,456,789]", "8722 {4196,48658} [123,456,789]", 2, 5, NOT_ALL_PRIVATE, 48658, 1, NULL_ASN }, }, { &test_segments[14], &test_segments[11], { "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 2 52737 4096 8722 4 8722", "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 3 52737 4096 34285 8466 3 52737 4096 34285 " "8466 2 52737 4096 8722 4 8722", 257, 0, NOT_ALL_PRIVATE, 4096, 1000, 8466 }, }, { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, }; struct tests reconcile_tests[] = { { &test_segments[18], &test_segments[19], { "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", 7, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[19], &test_segments[18], /* AS_PATH (19) has more hops than NEW_AS_PATH, * so just AS_PATH should be used (though, this practice * is bad imho). */ { "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", "{2457,4369,61697} 1842 41591 51793 6435 59408 21665 {23456} 23456 23456 23456", 11, 0, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[20], &test_segments[19], { "(123 456 789) [124,456,788] 6435 59408 21665" " {2457,4369,61697} 1842 41591 51793", "6435 59408 21665 {2457,4369,61697} 1842 41591 51793", 7, 4, NOT_ALL_PRIVATE, 51793, 1, 6435 }, }, { &test_segments[21], &test_segments[22], { "1842 41591 51793 6435 59408 21665", "1842 41591 51793 6435 59408 21665", 6, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 }, }, { &test_segments[23], &test_segments[22], { "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", "23456 23456 23456 6435 59408 1842 41591 51793 6435 59408 21665", 11, 0, NOT_ALL_PRIVATE, 51793, 1, 1842 }, }, { NULL, NULL, { NULL, 0, 0, 0, 0, 0, 0, } }, }; struct tests aggregate_tests[] = { { &test_segments[0], &test_segments[2], { "8466 3 52737 4096 {4,8722}", "8466 3 52737 4096 {4,8722}", 5, 0, NOT_ALL_PRIVATE, 4, 1, 8466 }, }, { &test_segments[2], &test_segments[0], { "8466 3 52737 4096 {4,8722}", "8466 3 52737 4096 {4,8722}", 5, 0, NOT_ALL_PRIVATE, 8722, 1, 8466 }, }, { &test_segments[2], &test_segments[10], { "8466 {2,3,4,4096,8722,52737}", "8466 {2,3,4,4096,8722,52737}", 2, 0, NOT_ALL_PRIVATE, 8722, 5, 8466 }, }, { &test_segments[10], &test_segments[2], { "8466 {2,3,4,4096,8722,52737}", "8466 {2,3,4,4096,8722,52737}", 2, 0, NOT_ALL_PRIVATE, 2, 20000, 8466 }, }, { &test_segments[5], &test_segments[18], { "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", "6435 59408 21665 {1842,2457,4369,23456,41590,51793,61697}", 4, 0, NOT_ALL_PRIVATE, 41590, 1, 6435 }, }, { NULL, NULL, { NULL, 0, 0} }, }; struct compare_tests { int test_index1; int test_index2; #define CMP_RES_YES 1 #define CMP_RES_NO 0 char shouldbe_cmp; char shouldbe_confed; } left_compare [] = { { 0, 1, CMP_RES_NO, CMP_RES_NO }, { 0, 2, CMP_RES_YES, CMP_RES_NO }, { 0, 11, CMP_RES_YES, CMP_RES_NO }, { 0, 15, CMP_RES_YES, CMP_RES_NO }, { 0, 16, CMP_RES_NO, CMP_RES_NO }, { 1, 11, CMP_RES_NO, CMP_RES_NO }, { 6, 7, CMP_RES_NO, CMP_RES_YES }, { 6, 8, CMP_RES_NO, CMP_RES_NO }, { 7, 8, CMP_RES_NO, CMP_RES_NO }, { 1, 9, CMP_RES_YES, CMP_RES_NO }, { 0, 9, CMP_RES_NO, CMP_RES_NO }, { 3, 9, CMP_RES_NO, CMP_RES_NO }, { 0, 6, CMP_RES_NO, CMP_RES_NO }, { 1, 6, CMP_RES_NO, CMP_RES_NO }, { 0, 8, CMP_RES_NO, CMP_RES_NO }, { 1, 8, CMP_RES_NO, CMP_RES_NO }, { 11, 6, CMP_RES_NO, CMP_RES_NO }, { 11, 7, CMP_RES_NO, CMP_RES_NO }, { 11, 8, CMP_RES_NO, CMP_RES_NO }, { 9, 6, CMP_RES_NO, CMP_RES_YES }, { 9, 7, CMP_RES_NO, CMP_RES_YES }, { 9, 8, CMP_RES_NO, CMP_RES_NO }, }; /* make an aspath from a data stream */ static struct aspath * make_aspath (const u_char *data, size_t len, int use32bit) { struct stream *s = NULL; struct aspath *as; if (len) { s = stream_new (len); stream_put (s, data, len); } as = aspath_parse (s, len, use32bit); if (s) stream_free (s); return as; } static void printbytes (const u_char *bytes, int len) { int i = 0; while (i < len) { if (i % 2) printf ("%02hhx%s", bytes[i], " "); else printf ("0x%02hhx", bytes[i]); i++; } printf ("\n"); } /* validate the given aspath */ static int validate (struct aspath *as, const struct test_spec *sp) { size_t bytes, bytes4; int fails = 0; const u_char *out; static struct stream *s; struct aspath *asinout, *asconfeddel, *asstr, *as4; if (as == NULL && sp->shouldbe == NULL) { printf ("Correctly failed to parse\n"); return fails; } out = aspath_snmp_pathseg (as, &bytes); asinout = make_aspath (out, bytes, 0); /* Excercise AS4 parsing a bit, with a dogfood test */ if (!s) s = stream_new (4096); bytes4 = aspath_put (s, as, 1); as4 = make_aspath (STREAM_DATA(s), bytes4, 1); asstr = aspath_str2aspath (sp->shouldbe); asconfeddel = aspath_delete_confed_seq (aspath_dup (asinout)); printf ("got: %s\n", aspath_print(as)); /* the parsed path should match the specified 'shouldbe' string. * We should pass the "eat our own dog food" test, be able to output * this path and then input it again. Ie the path resulting from: * * aspath_parse(aspath_put(as)) * * should: * * - also match the specified 'shouldbe' value * - hash to same value as original path * - have same hops and confed counts as original, and as the * the specified counts * * aspath_str2aspath() and shouldbe should match * * We do the same for: * * aspath_parse(aspath_put(as,USE32BIT)) * * Confederation related tests: * - aspath_delete_confed_seq(aspath) should match shouldbe_confed * - aspath_delete_confed_seq should be idempotent. */ if (strcmp(aspath_print (as), sp->shouldbe) /* hash validation */ || (aspath_key_make (as) != aspath_key_make (asinout)) /* by string */ || strcmp(aspath_print (asinout), sp->shouldbe) /* By 4-byte parsing */ || strcmp(aspath_print (as4), sp->shouldbe) /* by various path counts */ || (aspath_count_hops (as) != sp->hops) || (aspath_count_confeds (as) != sp->confeds) || (aspath_count_hops (asinout) != sp->hops) || (aspath_count_confeds (asinout) != sp->confeds)) { failed++; fails++; printf ("shouldbe:\n%s\n", sp->shouldbe); printf ("as4:\n%s\n", aspath_print (as4)); printf ("hash keys: in: %d out->in: %d\n", aspath_key_make (as), aspath_key_make (asinout)); printf ("hops: %d, counted %d %d\n", sp->hops, aspath_count_hops (as), aspath_count_hops (asinout) ); printf ("confeds: %d, counted %d %d\n", sp->confeds, aspath_count_confeds (as), aspath_count_confeds (asinout)); printf ("out->in:\n%s\nbytes: ", aspath_print(asinout)); printbytes (out, bytes); } /* basic confed related tests */ if ((aspath_print (asconfeddel) == NULL && sp->shouldbe_delete_confed != NULL) || (aspath_print (asconfeddel) != NULL && sp->shouldbe_delete_confed == NULL) || strcmp(aspath_print (asconfeddel), sp->shouldbe_delete_confed) /* delete_confed_seq should be idempotent */ || (aspath_key_make (asconfeddel) != aspath_key_make (aspath_delete_confed_seq (asconfeddel)))) { failed++; fails++; printf ("confed_del: %s\n", aspath_print (asconfeddel)); printf ("should be: %s\n", sp->shouldbe_delete_confed); } /* aspath_str2aspath test */ if ((aspath_print (asstr) == NULL && sp->shouldbe != NULL) || (aspath_print (asstr) != NULL && sp->shouldbe == NULL) || strcmp(aspath_print (asstr), sp->shouldbe)) { failed++; fails++; printf ("asstr: %s\n", aspath_print (asstr)); } /* loop, private and first as checks */ if ((sp->does_loop && aspath_loop_check (as, sp->does_loop) == 0) || (sp->doesnt_loop && aspath_loop_check (as, sp->doesnt_loop) != 0) || (aspath_private_as_check (as) != sp->private_as) || (aspath_firstas_check (as,sp->first) && sp->first == 0)) { failed++; fails++; printf ("firstas: %d, got %d\n", sp->first, aspath_firstas_check (as,sp->first)); printf ("loop does: %d %d, doesnt: %d %d\n", sp->does_loop, aspath_loop_check (as, sp->does_loop), sp->doesnt_loop, aspath_loop_check (as, sp->doesnt_loop)); printf ("private check: %d %d\n", sp->private_as, aspath_private_as_check (as)); } aspath_unintern (&asinout); aspath_unintern (&as4); aspath_free (asconfeddel); aspath_free (asstr); stream_reset (s); return fails; } static void empty_get_test () { struct aspath *as = aspath_empty_get (); struct test_spec sp = { "", "", 0, 0, 0, 0, 0, 0 }; printf ("empty_get_test, as: %s\n",aspath_print (as)); if (!validate (as, &sp)) printf ("%s\n", OK); else printf ("%s!\n", FAILED); printf ("\n"); aspath_free (as); } /* basic parsing test */ static void parse_test (struct test_segment *t) { struct aspath *asp; printf ("%s: %s\n", t->name, t->desc); asp = make_aspath (t->asdata, t->len, 0); printf ("aspath: %s\nvalidating...:\n", aspath_print (asp)); if (!validate (asp, &t->sp)) printf (OK "\n"); else printf (FAILED "\n"); printf ("\n"); if (asp) aspath_unintern (&asp); } /* prepend testing */ static void prepend_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("prepend %s: %s\n", t->test1->name, t->test1->desc); printf ("to %s: %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_dup (asp2); aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); printf ("aspath: %s\n", aspath_print (asp2)); if (!validate (asp2, &t->sp)) printf ("%s\n", OK); else printf ("%s!\n", FAILED); printf ("\n"); aspath_unintern (&asp1); aspath_free (asp2); } /* empty-prepend testing */ static void empty_prepend_test (struct test_segment *t) { struct aspath *asp1, *asp2, *ascratch; printf ("empty prepend %s: %s\n", t->name, t->desc); asp1 = make_aspath (t->asdata, t->len, 0); asp2 = aspath_empty (); ascratch = aspath_dup (asp2); aspath_unintern (&asp2); asp2 = aspath_prepend (asp1, ascratch); printf ("aspath: %s\n", aspath_print (asp2)); if (!validate (asp2, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); if (asp1) aspath_unintern (&asp1); aspath_free (asp2); } /* as2+as4 reconciliation testing */ static void as4_reconcile_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("reconciling %s:\n %s\n", t->test1->name, t->test1->desc); printf ("with %s:\n %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_reconcile_as4 (asp1, asp2); if (!validate (ascratch, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); aspath_free (ascratch); } /* aggregation testing */ static void aggregate_test (struct tests *t) { struct aspath *asp1, *asp2, *ascratch; printf ("aggregate %s: %s\n", t->test1->name, t->test1->desc); printf ("with %s: %s\n", t->test2->name, t->test2->desc); asp1 = make_aspath (t->test1->asdata, t->test1->len, 0); asp2 = make_aspath (t->test2->asdata, t->test2->len, 0); ascratch = aspath_aggregate (asp1, asp2); if (!validate (ascratch, &t->sp)) printf (OK "\n"); else printf (FAILED "!\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); aspath_free (ascratch); /* aspath_unintern (ascratch);*/ } /* cmp_left tests */ static void cmp_test () { unsigned int i; #define CMP_TESTS_MAX \ (sizeof(left_compare) / sizeof (struct compare_tests)) for (i = 0; i < CMP_TESTS_MAX; i++) { struct test_segment *t1 = &test_segments[left_compare[i].test_index1]; struct test_segment *t2 = &test_segments[left_compare[i].test_index2]; struct aspath *asp1, *asp2; printf ("left cmp %s: %s\n", t1->name, t1->desc); printf ("and %s: %s\n", t2->name, t2->desc); asp1 = make_aspath (t1->asdata, t1->len, 0); asp2 = make_aspath (t2->asdata, t2->len, 0); if (aspath_cmp_left (asp1, asp2) != left_compare[i].shouldbe_cmp || aspath_cmp_left (asp2, asp1) != left_compare[i].shouldbe_cmp || aspath_cmp_left_confed (asp1, asp2) != left_compare[i].shouldbe_confed || aspath_cmp_left_confed (asp2, asp1) != left_compare[i].shouldbe_confed) { failed++; printf (FAILED "\n"); printf ("result should be: cmp: %d, confed: %d\n", left_compare[i].shouldbe_cmp, left_compare[i].shouldbe_confed); printf ("got: cmp %d, cmp_confed: %d\n", aspath_cmp_left (asp1, asp2), aspath_cmp_left_confed (asp1, asp2)); printf("path1: %s\npath2: %s\n", aspath_print (asp1), aspath_print (asp2)); } else printf (OK "\n"); printf ("\n"); aspath_unintern (&asp1); aspath_unintern (&asp2); } } static int handle_attr_test (struct aspath_tests *t) { struct bgp bgp = { 0 }; struct peer peer = { 0 }; struct attr attr = { 0 }; int ret; int initfail = failed; struct aspath *asp; size_t datalen; asp = make_aspath (t->segment->asdata, t->segment->len, 0); peer.ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer.obuf = stream_fifo_new (); peer.bgp = &bgp; peer.host = (char *)"none"; peer.fd = -1; peer.cap = t->cap; stream_write (peer.ibuf, t->attrheader, t->len); datalen = aspath_put (peer.ibuf, asp, t->as4 == AS4_DATA); if (t->old_segment) { char dummyaspath[] = { BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, t->old_segment->len }; stream_write (peer.ibuf, dummyaspath, sizeof (dummyaspath)); stream_write (peer.ibuf, t->old_segment->asdata, t->old_segment->len); datalen += sizeof (dummyaspath) + t->old_segment->len; } ret = bgp_attr_parse (&peer, &attr, t->len + datalen, NULL, NULL); if (ret != t->result) { printf ("bgp_attr_parse returned %d, expected %d\n", ret, t->result); printf ("datalen %zd\n", datalen); failed++; } if (ret != 0) goto out; if (t->shouldbe && attr.aspath == NULL) { printf ("aspath is NULL, but should be: %s\n", t->shouldbe); failed++; } if (t->shouldbe && attr.aspath && strcmp (attr.aspath->str, t->shouldbe)) { printf ("attr str and 'shouldbe' mismatched!\n" "attr str: %s\n" "shouldbe: %s\n", attr.aspath->str, t->shouldbe); failed++; } if (!t->shouldbe && attr.aspath) { printf ("aspath should be NULL, but is: %s\n", attr.aspath->str); failed++; } out: if (attr.aspath) aspath_unintern (&attr.aspath); if (asp) aspath_unintern (&asp); return failed - initfail; } static void attr_test (struct aspath_tests *t) { printf ("%s\n", t->desc); printf ("%s\n\n", handle_attr_test (t) ? FAILED : OK); } int main (void) { int i = 0; bgp_master_init (); master = bm->master; bgp_option_set (BGP_OPT_NO_LISTEN); bgp_attr_init (); while (test_segments[i].name) { printf ("test %u\n", i); parse_test (&test_segments[i]); empty_prepend_test (&test_segments[i++]); } i = 0; while (prepend_tests[i].test1) { printf ("prepend test %u\n", i); prepend_test (&prepend_tests[i++]); } i = 0; while (aggregate_tests[i].test1) { printf ("aggregate test %u\n", i); aggregate_test (&aggregate_tests[i++]); } i = 0; while (reconcile_tests[i].test1) { printf ("reconcile test %u\n", i); as4_reconcile_test (&reconcile_tests[i++]); } i = 0; cmp_test(); i = 0; empty_get_test(); i = 0; while (aspath_tests[i].desc) { printf ("aspath_attr test %d\n", i); attr_test (&aspath_tests[i++]); } printf ("failures: %d\n", failed); printf ("aspath count: %ld\n", aspath_count()); return (failed + aspath_count()); } quagga-0.99.24.1/tests/prng.h0000644000175000017500000000241412476520570012516 00000000000000/* * Very simple prng to allow for randomized tests with reproducable * results. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _PRNG_H #define _PRNG_H struct prng; struct prng* prng_new(unsigned long long seed); unsigned int prng_rand(struct prng*); const char * prng_fuzz(struct prng*, const char *string, const char *charset, unsigned int operations); void prng_free(struct prng *); #endif quagga-0.99.24.1/tests/Makefile.am0000644000175000017500000000567512476520570013447 00000000000000AUTOMAKE_OPTIONS = dejagnu DEJATOOL = libzebra SUBDIRS = \ bgpd.tests \ libzebra.tests EXTRA_DIST = \ config/unix.exp \ lib/bgpd.exp \ lib/libzebra.exp \ global-conf.exp \ testcommands.in \ testcommands.refout AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) if BGPD TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath DEJATOOL += bgpd else TESTS_BGPD = endif check_PROGRAMS = testsig testsegv testbuffer testmemory heavy heavywq heavythread \ testprivs teststream testchecksum tabletest testnexthopiter \ testcommands test-timer-correctness test-timer-performance \ $(TESTS_BGPD) ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c test-commands-defun.c: ../vtysh/vtysh_cmd.c sed \ -e '/"vtysh.h"/d' \ -e 's/vtysh_init_cmd/test_init_cmd/' \ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ < ../vtysh/vtysh_cmd.c \ > test-commands-defun.c BUILT_SOURCES = test-commands-defun.c noinst_HEADERS = prng.h testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c testprivs_SOURCES = test-privs.c teststream_SOURCES = test-stream.c heavy_SOURCES = heavy.c main.c heavywq_SOURCES = heavy-wq.c main.c heavythread_SOURCES = heavy-thread.c main.c aspathtest_SOURCES = aspath_test.c testbgpcap_SOURCES = bgp_capability_test.c ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c test_timer_correctness_SOURCES = test-timer-correctness.c prng.c test_timer_performance_SOURCES = test-timer-performance.c prng.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ testprivs_LDADD = ../lib/libzebra.la @LIBCAP@ teststream_LDADD = ../lib/libzebra.la @LIBCAP@ heavy_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm aspathtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpcap_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm ecommtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_correctness_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_performance_LDADD = ../lib/libzebra.la @LIBCAP@ quagga-0.99.24.1/tests/Makefile.in0000644000175000017500000011214612476521251013445 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @BGPD_TRUE@am__append_1 = bgpd check_PROGRAMS = testsig$(EXEEXT) testsegv$(EXEEXT) \ testbuffer$(EXEEXT) testmemory$(EXEEXT) heavy$(EXEEXT) \ heavywq$(EXEEXT) heavythread$(EXEEXT) testprivs$(EXEEXT) \ teststream$(EXEEXT) testchecksum$(EXEEXT) tabletest$(EXEEXT) \ testnexthopiter$(EXEEXT) testcommands$(EXEEXT) \ test-timer-correctness$(EXEEXT) \ test-timer-performance$(EXEEXT) $(am__EXEEXT_1) subdir = tests DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @BGPD_TRUE@am__EXEEXT_1 = aspathtest$(EXEEXT) testbgpcap$(EXEEXT) \ @BGPD_TRUE@ ecommtest$(EXEEXT) testbgpmpattr$(EXEEXT) \ @BGPD_TRUE@ testbgpmpath$(EXEEXT) am_aspathtest_OBJECTS = aspath_test.$(OBJEXT) aspathtest_OBJECTS = $(am_aspathtest_OBJECTS) aspathtest_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_ecommtest_OBJECTS = ecommunity_test.$(OBJEXT) ecommtest_OBJECTS = $(am_ecommtest_OBJECTS) ecommtest_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_heavy_OBJECTS = heavy.$(OBJEXT) main.$(OBJEXT) heavy_OBJECTS = $(am_heavy_OBJECTS) heavy_DEPENDENCIES = ../lib/libzebra.la am_heavythread_OBJECTS = heavy-thread.$(OBJEXT) main.$(OBJEXT) heavythread_OBJECTS = $(am_heavythread_OBJECTS) heavythread_DEPENDENCIES = ../lib/libzebra.la am_heavywq_OBJECTS = heavy-wq.$(OBJEXT) main.$(OBJEXT) heavywq_OBJECTS = $(am_heavywq_OBJECTS) heavywq_DEPENDENCIES = ../lib/libzebra.la am_tabletest_OBJECTS = table_test.$(OBJEXT) tabletest_OBJECTS = $(am_tabletest_OBJECTS) tabletest_DEPENDENCIES = ../lib/libzebra.la am_test_timer_correctness_OBJECTS = test-timer-correctness.$(OBJEXT) \ prng.$(OBJEXT) test_timer_correctness_OBJECTS = $(am_test_timer_correctness_OBJECTS) test_timer_correctness_DEPENDENCIES = ../lib/libzebra.la am_test_timer_performance_OBJECTS = test-timer-performance.$(OBJEXT) \ prng.$(OBJEXT) test_timer_performance_OBJECTS = $(am_test_timer_performance_OBJECTS) test_timer_performance_DEPENDENCIES = ../lib/libzebra.la am_testbgpcap_OBJECTS = bgp_capability_test.$(OBJEXT) testbgpcap_OBJECTS = $(am_testbgpcap_OBJECTS) testbgpcap_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbgpmpath_OBJECTS = bgp_mpath_test.$(OBJEXT) testbgpmpath_OBJECTS = $(am_testbgpmpath_OBJECTS) testbgpmpath_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbgpmpattr_OBJECTS = bgp_mp_attr_test.$(OBJEXT) testbgpmpattr_OBJECTS = $(am_testbgpmpattr_OBJECTS) testbgpmpattr_DEPENDENCIES = ../bgpd/libbgp.a ../lib/libzebra.la am_testbuffer_OBJECTS = test-buffer.$(OBJEXT) testbuffer_OBJECTS = $(am_testbuffer_OBJECTS) testbuffer_DEPENDENCIES = ../lib/libzebra.la am_testchecksum_OBJECTS = test-checksum.$(OBJEXT) testchecksum_OBJECTS = $(am_testchecksum_OBJECTS) testchecksum_DEPENDENCIES = ../lib/libzebra.la am_testcommands_OBJECTS = test-commands-defun.$(OBJEXT) \ test-commands.$(OBJEXT) prng.$(OBJEXT) testcommands_OBJECTS = $(am_testcommands_OBJECTS) testcommands_DEPENDENCIES = ../lib/libzebra.la am_testmemory_OBJECTS = test-memory.$(OBJEXT) testmemory_OBJECTS = $(am_testmemory_OBJECTS) testmemory_DEPENDENCIES = ../lib/libzebra.la am_testnexthopiter_OBJECTS = test-nexthop-iter.$(OBJEXT) \ prng.$(OBJEXT) testnexthopiter_OBJECTS = $(am_testnexthopiter_OBJECTS) testnexthopiter_DEPENDENCIES = ../lib/libzebra.la am_testprivs_OBJECTS = test-privs.$(OBJEXT) testprivs_OBJECTS = $(am_testprivs_OBJECTS) testprivs_DEPENDENCIES = ../lib/libzebra.la am_testsegv_OBJECTS = test-segv.$(OBJEXT) testsegv_OBJECTS = $(am_testsegv_OBJECTS) testsegv_DEPENDENCIES = ../lib/libzebra.la am_testsig_OBJECTS = test-sig.$(OBJEXT) testsig_OBJECTS = $(am_testsig_OBJECTS) testsig_DEPENDENCIES = ../lib/libzebra.la am_teststream_OBJECTS = test-stream.$(OBJEXT) teststream_OBJECTS = $(am_teststream_OBJECTS) teststream_DEPENDENCIES = ../lib/libzebra.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) $(heavy_SOURCES) \ $(heavythread_SOURCES) $(heavywq_SOURCES) $(tabletest_SOURCES) \ $(test_timer_correctness_SOURCES) \ $(test_timer_performance_SOURCES) $(testbgpcap_SOURCES) \ $(testbgpmpath_SOURCES) $(testbgpmpattr_SOURCES) \ $(testbuffer_SOURCES) $(testchecksum_SOURCES) \ $(testcommands_SOURCES) $(testmemory_SOURCES) \ $(testnexthopiter_SOURCES) $(testprivs_SOURCES) \ $(testsegv_SOURCES) $(testsig_SOURCES) $(teststream_SOURCES) DIST_SOURCES = $(aspathtest_SOURCES) $(ecommtest_SOURCES) \ $(heavy_SOURCES) $(heavythread_SOURCES) $(heavywq_SOURCES) \ $(tabletest_SOURCES) $(test_timer_correctness_SOURCES) \ $(test_timer_performance_SOURCES) $(testbgpcap_SOURCES) \ $(testbgpmpath_SOURCES) $(testbgpmpattr_SOURCES) \ $(testbuffer_SOURCES) $(testchecksum_SOURCES) \ $(testcommands_SOURCES) $(testmemory_SOURCES) \ $(testnexthopiter_SOURCES) $(testprivs_SOURCES) \ $(testsegv_SOURCES) $(testsig_SOURCES) $(teststream_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags EXPECT = expect RUNTEST = runtest DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = dejagnu DEJATOOL = libzebra $(am__append_1) SUBDIRS = \ bgpd.tests \ libzebra.tests EXTRA_DIST = \ config/unix.exp \ lib/bgpd.exp \ lib/libzebra.exp \ global-conf.exp \ testcommands.in \ testcommands.refout AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) @BGPD_FALSE@TESTS_BGPD = @BGPD_TRUE@TESTS_BGPD = aspathtest testbgpcap ecommtest testbgpmpattr testbgpmpath BUILT_SOURCES = test-commands-defun.c noinst_HEADERS = prng.h testsig_SOURCES = test-sig.c testsegv_SOURCES = test-segv.c testbuffer_SOURCES = test-buffer.c testmemory_SOURCES = test-memory.c testprivs_SOURCES = test-privs.c teststream_SOURCES = test-stream.c heavy_SOURCES = heavy.c main.c heavywq_SOURCES = heavy-wq.c main.c heavythread_SOURCES = heavy-thread.c main.c aspathtest_SOURCES = aspath_test.c testbgpcap_SOURCES = bgp_capability_test.c ecommtest_SOURCES = ecommunity_test.c testbgpmpattr_SOURCES = bgp_mp_attr_test.c testchecksum_SOURCES = test-checksum.c testbgpmpath_SOURCES = bgp_mpath_test.c tabletest_SOURCES = table_test.c testnexthopiter_SOURCES = test-nexthop-iter.c prng.c testcommands_SOURCES = test-commands-defun.c test-commands.c prng.c test_timer_correctness_SOURCES = test-timer-correctness.c prng.c test_timer_performance_SOURCES = test-timer-performance.c prng.c testsig_LDADD = ../lib/libzebra.la @LIBCAP@ testsegv_LDADD = ../lib/libzebra.la @LIBCAP@ testbuffer_LDADD = ../lib/libzebra.la @LIBCAP@ testmemory_LDADD = ../lib/libzebra.la @LIBCAP@ testprivs_LDADD = ../lib/libzebra.la @LIBCAP@ teststream_LDADD = ../lib/libzebra.la @LIBCAP@ heavy_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavywq_LDADD = ../lib/libzebra.la @LIBCAP@ -lm heavythread_LDADD = ../lib/libzebra.la @LIBCAP@ -lm aspathtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpcap_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm ecommtest_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testbgpmpattr_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm testchecksum_LDADD = ../lib/libzebra.la @LIBCAP@ testbgpmpath_LDADD = ../bgpd/libbgp.a ../lib/libzebra.la @LIBCAP@ -lm tabletest_LDADD = ../lib/libzebra.la @LIBCAP@ -lm testnexthopiter_LDADD = ../lib/libzebra.la @LIBCAP@ testcommands_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_correctness_LDADD = ../lib/libzebra.la @LIBCAP@ test_timer_performance_LDADD = ../lib/libzebra.la @LIBCAP@ all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-checkPROGRAMS: @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list aspathtest$(EXEEXT): $(aspathtest_OBJECTS) $(aspathtest_DEPENDENCIES) $(EXTRA_aspathtest_DEPENDENCIES) @rm -f aspathtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(aspathtest_OBJECTS) $(aspathtest_LDADD) $(LIBS) ecommtest$(EXEEXT): $(ecommtest_OBJECTS) $(ecommtest_DEPENDENCIES) $(EXTRA_ecommtest_DEPENDENCIES) @rm -f ecommtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ecommtest_OBJECTS) $(ecommtest_LDADD) $(LIBS) heavy$(EXEEXT): $(heavy_OBJECTS) $(heavy_DEPENDENCIES) $(EXTRA_heavy_DEPENDENCIES) @rm -f heavy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavy_OBJECTS) $(heavy_LDADD) $(LIBS) heavythread$(EXEEXT): $(heavythread_OBJECTS) $(heavythread_DEPENDENCIES) $(EXTRA_heavythread_DEPENDENCIES) @rm -f heavythread$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavythread_OBJECTS) $(heavythread_LDADD) $(LIBS) heavywq$(EXEEXT): $(heavywq_OBJECTS) $(heavywq_DEPENDENCIES) $(EXTRA_heavywq_DEPENDENCIES) @rm -f heavywq$(EXEEXT) $(AM_V_CCLD)$(LINK) $(heavywq_OBJECTS) $(heavywq_LDADD) $(LIBS) tabletest$(EXEEXT): $(tabletest_OBJECTS) $(tabletest_DEPENDENCIES) $(EXTRA_tabletest_DEPENDENCIES) @rm -f tabletest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tabletest_OBJECTS) $(tabletest_LDADD) $(LIBS) test-timer-correctness$(EXEEXT): $(test_timer_correctness_OBJECTS) $(test_timer_correctness_DEPENDENCIES) $(EXTRA_test_timer_correctness_DEPENDENCIES) @rm -f test-timer-correctness$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_timer_correctness_OBJECTS) $(test_timer_correctness_LDADD) $(LIBS) test-timer-performance$(EXEEXT): $(test_timer_performance_OBJECTS) $(test_timer_performance_DEPENDENCIES) $(EXTRA_test_timer_performance_DEPENDENCIES) @rm -f test-timer-performance$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_timer_performance_OBJECTS) $(test_timer_performance_LDADD) $(LIBS) testbgpcap$(EXEEXT): $(testbgpcap_OBJECTS) $(testbgpcap_DEPENDENCIES) $(EXTRA_testbgpcap_DEPENDENCIES) @rm -f testbgpcap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpcap_OBJECTS) $(testbgpcap_LDADD) $(LIBS) testbgpmpath$(EXEEXT): $(testbgpmpath_OBJECTS) $(testbgpmpath_DEPENDENCIES) $(EXTRA_testbgpmpath_DEPENDENCIES) @rm -f testbgpmpath$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpmpath_OBJECTS) $(testbgpmpath_LDADD) $(LIBS) testbgpmpattr$(EXEEXT): $(testbgpmpattr_OBJECTS) $(testbgpmpattr_DEPENDENCIES) $(EXTRA_testbgpmpattr_DEPENDENCIES) @rm -f testbgpmpattr$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbgpmpattr_OBJECTS) $(testbgpmpattr_LDADD) $(LIBS) testbuffer$(EXEEXT): $(testbuffer_OBJECTS) $(testbuffer_DEPENDENCIES) $(EXTRA_testbuffer_DEPENDENCIES) @rm -f testbuffer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testbuffer_OBJECTS) $(testbuffer_LDADD) $(LIBS) testchecksum$(EXEEXT): $(testchecksum_OBJECTS) $(testchecksum_DEPENDENCIES) $(EXTRA_testchecksum_DEPENDENCIES) @rm -f testchecksum$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testchecksum_OBJECTS) $(testchecksum_LDADD) $(LIBS) testcommands$(EXEEXT): $(testcommands_OBJECTS) $(testcommands_DEPENDENCIES) $(EXTRA_testcommands_DEPENDENCIES) @rm -f testcommands$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testcommands_OBJECTS) $(testcommands_LDADD) $(LIBS) testmemory$(EXEEXT): $(testmemory_OBJECTS) $(testmemory_DEPENDENCIES) $(EXTRA_testmemory_DEPENDENCIES) @rm -f testmemory$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testmemory_OBJECTS) $(testmemory_LDADD) $(LIBS) testnexthopiter$(EXEEXT): $(testnexthopiter_OBJECTS) $(testnexthopiter_DEPENDENCIES) $(EXTRA_testnexthopiter_DEPENDENCIES) @rm -f testnexthopiter$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testnexthopiter_OBJECTS) $(testnexthopiter_LDADD) $(LIBS) testprivs$(EXEEXT): $(testprivs_OBJECTS) $(testprivs_DEPENDENCIES) $(EXTRA_testprivs_DEPENDENCIES) @rm -f testprivs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testprivs_OBJECTS) $(testprivs_LDADD) $(LIBS) testsegv$(EXEEXT): $(testsegv_OBJECTS) $(testsegv_DEPENDENCIES) $(EXTRA_testsegv_DEPENDENCIES) @rm -f testsegv$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testsegv_OBJECTS) $(testsegv_LDADD) $(LIBS) testsig$(EXEEXT): $(testsig_OBJECTS) $(testsig_DEPENDENCIES) $(EXTRA_testsig_DEPENDENCIES) @rm -f testsig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(testsig_OBJECTS) $(testsig_LDADD) $(LIBS) teststream$(EXEEXT): $(teststream_OBJECTS) $(teststream_DEPENDENCIES) $(EXTRA_teststream_DEPENDENCIES) @rm -f teststream$(EXEEXT) $(AM_V_CCLD)$(LINK) $(teststream_OBJECTS) $(teststream_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aspath_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_capability_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mp_attr_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mpath_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ecommunity_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy-thread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy-wq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heavy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prng.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-checksum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-commands-defun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-commands.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nexthop-iter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-privs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-segv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-stream.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-timer-correctness.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-timer-performance.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-DEJAGNU: site.exp srcdir='$(srcdir)'; export srcdir; \ EXPECT=$(EXPECT); export EXPECT; \ if $(SHELL) -c "$(RUNTEST) --version" > /dev/null 2>&1; then \ exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \ if $(RUNTEST) $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \ then :; else exit_status=1; fi; \ done; \ else echo "WARNING: could not find '$(RUNTEST)'" 1>&2; :;\ fi; \ exit $$exit_status site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG) @echo 'Making a new site.exp file ...' @echo '## these variables are automatically generated by make ##' >site.tmp @echo '# Do not edit here. If you wish to override these values' >>site.tmp @echo '# edit the last section' >>site.tmp @echo 'set srcdir "$(srcdir)"' >>site.tmp @echo "set objdir `pwd`" >>site.tmp @echo 'set build_alias "$(build_alias)"' >>site.tmp @echo 'set build_triplet $(build_triplet)' >>site.tmp @echo 'set host_alias "$(host_alias)"' >>site.tmp @echo 'set host_triplet $(host_triplet)' >>site.tmp @echo 'set target_alias "$(target_alias)"' >>site.tmp @echo 'set target_triplet $(target_triplet)' >>site.tmp @list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \ echo "## Begin content included from file $$f. Do not modify. ##" \ && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \ && echo "## End content included from file $$f. ##" \ || exit 1; \ done >> site.tmp @echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp @if test -f site.exp; then \ sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \ fi @-rm -f site.bak @test ! -f site.exp || mv site.exp site.bak @mv site.tmp site.exp distclean-DEJAGNU: -rm -f site.exp site.bak -l='$(DEJATOOL)'; for tool in $$l; do \ rm -f $$tool.sum $$tool.log; \ done distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive all-am: Makefile $(HEADERS) installdirs: installdirs-recursive installdirs-am: install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-DEJAGNU distclean-compile \ distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all check check-am install install-am \ install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-DEJAGNU check-am clean clean-checkPROGRAMS clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-DEJAGNU distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am ../vtysh/vtysh_cmd.c: $(MAKE) -C ../vtysh vtysh_cmd.c test-commands-defun.c: ../vtysh/vtysh_cmd.c sed \ -e '/"vtysh.h"/d' \ -e 's/vtysh_init_cmd/test_init_cmd/' \ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ < ../vtysh/vtysh_cmd.c \ > test-commands-defun.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/tests/lib/0000755000175000017500000000000012476521377012232 500000000000000quagga-0.99.24.1/tests/lib/libzebra.exp0000644000175000017500000000000012476520570014442 00000000000000quagga-0.99.24.1/tests/lib/bgpd.exp0000644000175000017500000000000012476520570013564 00000000000000quagga-0.99.24.1/tests/config/0000755000175000017500000000000012476521377012731 500000000000000quagga-0.99.24.1/tests/config/unix.exp0000644000175000017500000000436112476520570014350 00000000000000 # every test should always be run and always return some status. # so, if we lose sync with a multi-test program, aborted will be used # to flag the remainder of the tests as untested. #set aborted 0 # only match with color codes since "failed" / "OK" might otherwise # be part of the output... #set color 1 set xfail 0 proc onesimple { test_name match } { global verbose global aborted global testprefix if { $aborted > 0 } { untested "$testprefix$test_name" return } if { $verbose > 0 } { send_user "$testprefix$test_name$note\n" } expect { "$match" { pass "$testprefix$test_name"; } eof { fail "$testprefix$test_name"; set aborted 1; } timeout { unresolved "$testprefix$test_name"; set aborted 1; } } } proc onetest { test_name note start } { global aborted global testprefix global verbose global color global xfail if { $aborted > 0 } { untested "$testprefix$test_name" return } if { $verbose > 0 } { send_user "$testprefix$test_name$note\n" } expect { "$start" { } eof { unresolved "$testprefix$test_name"; set aborted 1; } timeout { unresolved "$testprefix$test_name"; set aborted 1; } } if { $aborted > 0 } { send_user "sync failed: $testprefix$test_name$note -- $testprefix aborted!\n" return } if { $color } { set pat "(32mOK|31mfailed)" } else { set pat "(OK|failed)" } expect { # need this because otherwise expect will skip over a "failed" and # grab the next "OK" (or the other way around) -re "$pat" { if { "$expect_out(0,string)" == "32mOK" || "$expect_out(0,string)" == "OK" } { pass "$testprefix$test_name" } else { if { $xfail } { xfail "$testprefix$test_name" } else { fail "$testprefix$test_name" } } return } eof { unresolved "$testprefix$test_name"; set aborted 1; } timeout { unresolved "$testprefix$test_name"; set aborted 1; } } if { $aborted > 0 } { send_user "failed: $testprefix$test_name$note -- $testprefix aborted!\n" return } } proc headerline { line } { global aborted if { $aborted > 0 } { return; } expect { $line { return; } eof { send_user "numbering mismatch!\n"; set aborted 1; } timeout { send_user "numbering mismatch!\n"; set aborted 1; } } } proc simpletest { start } { onetest "$start" "" "$start" } quagga-0.99.24.1/redhat/0000755000175000017500000000000012476521364011565 500000000000000quagga-0.99.24.1/redhat/zebra.service0000644000175000017500000000053712476520570014175 00000000000000[Unit] Description=GNU Zebra routing manager After=syslog.target network.target ConditionPathExists=/etc/quagga/zebra.conf [Service] Type=forking EnvironmentFile=-/etc/sysconfig/quagga ExecStartPre=/sbin/ip route flush proto zebra ExecStart=/usr/sbin/zebra -d $ZEBRA_OPTS -f /etc/quagga/zebra.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/zebra.init0000644000175000017500000000244312476520570013476 00000000000000#!/bin/bash # chkconfig: - 15 85 # config: /etc/quagga/zebra.conf ### BEGIN INIT INFO # Provides: zebra # Short-Description: GNU Zebra routing manager # Description: GNU Zebra routing manager ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="zebra" cmd=zebra LOCK_FILE=/var/lock/subsys/zebra CONF_FILE=/etc/quagga/zebra.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " /sbin/ip route flush proto zebra daemon $cmd -d $ZEBRA_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/watchquagga.init0000644000175000017500000000223112476520570014662 00000000000000#!/bin/bash # chkconfig: 2345 17 83 ### BEGIN INIT INFO # Provides: watchquagga # Short-Description: Quagga watchdog # Description: Quagga watchdog for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="watchquagga" cmd=watchquagga LOCK_FILE=/var/lock/subsys/watchquagga case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # Check that there are daemons to be monitored. [ -z "$WATCH_DAEMONS" ] && exit 1 echo -n $"Starting $PROG: " daemon $cmd -d $WATCH_OPTS $WATCH_DAEMONS RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/ripngd.service0000644000175000017500000000053112476520570014347 00000000000000[Unit] Description=RIP routing daemon for IPv6 BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ripngd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ripngd -d $RIPNGD_OPTS -f /etc/quagga/ripngd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/ripngd.init0000644000175000017500000000243712476520570013661 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ripngd.conf ### BEGIN INIT INFO # Provides: ripngd # Short-Description: RIP routing engine for IPv6 # Description: RIP routing engine for use with Zebra and IPv6 ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ripngd" cmd=ripngd LOCK_FILE=/var/lock/subsys/ripngd CONF_FILE=/etc/quagga/ripngd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $RIPNGD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/ripd.service0000644000175000017500000000051012476520570014017 00000000000000[Unit] Description=RIP routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ripd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ripd -d $RIPD_OPTS -f /etc/quagga/ripd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/ripd.init0000644000175000017500000000237712476520570013337 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ripd.conf ### BEGIN INIT INFO # Provides: ripd # Short-Description: RIP routing engine # Description: RIP routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ripd" cmd=ripd LOCK_FILE=/var/lock/subsys/ripd CONF_FILE=/etc/quagga/ripd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $RIPD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/quagga.sysconfig0000644000175000017500000000152112476520570014675 00000000000000# # Default: Bind all daemon vtys to the loopback(s) only # BABELD_OPTS="-A 127.0.0.1" BGPD_OPTS="-A 127.0.0.1" ISISD_OPTS="-A ::1" OSPF6D_OPTS="-A ::1" OSPFD_OPTS="-A 127.0.0.1" RIPD_OPTS="-A 127.0.0.1" RIPNGD_OPTS="-A ::1" ZEBRA_OPTS="-A 127.0.0.1" # Watchquagga configuration for LSB initscripts # # (Not needed with systemd: the service files are configured to automatically # restart any daemon on failure. If zebra fails, all running daemons will be # stopped; zebra will be started again; and then the previously running daemons # will be started again.) # # Uncomment and edit this line to reflect the daemons you are actually using: #WATCH_DAEMONS="zebra bgpd ospfd ospf6d ripd ripngd" # # Timer values can be adjusting by editing this line: WATCH_OPTS="-Az -b_ -r/sbin/service_%s_restart -s/sbin/service_%s_start -k/sbin/service_%s_stop" quagga-0.99.24.1/redhat/quagga.spec0000644000175000017500000004220212476521315013622 00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %define with_snmp 1 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_ospf_te: %define with_ospf_te 1 } %{!?with_nssa: %define with_nssa 1 } %{!?with_opaque_lsa: %define with_opaque_lsa 1 } %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } %{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } %{!?vty_group: %define vty_group quaggavty } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{version} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _libexecdir %{_exec_prefix}/libexec/quagga %define _libdir %{_exec_prefix}/%{_lib}/quagga %define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ ####################### distro specific tweaks ############################# # default distro. Override with rpmbuild -D "dist XXX" %{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. %define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. %if "%dist" != "fc2" || "%dist" != "fc3" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif ############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} %define daemonv6_list ripngd babeld ospf6d %else %define daemonv6_list "" %endif %if %{with_isisd} %define daemon_other isisd %else %define daemon_other "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga # allow build dir to be kept %{!?keep_build: %define keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon Name: quagga Version: 0.99.24.1 Release: 20150307%{release_rev} License: GPL Group: System Environment/Daemons Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz URL: http://www.quagga.net %if %{with_snmp} BuildRequires: net-snmp-devel Requires(pre): net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam Requires(pre): /sbin/install-info Provides: routingdaemon BuildRoot: %{_tmppath}/%{name}-%{version}-root Obsoletes: bird gated mrt zebra %description Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. Quagga by design has a process for each protocol. Quagga is a fork of GNU Zebra. %package contrib Summary: contrib tools for quagga Group: System Environment/Daemons %description contrib Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q %build # For standard gcc verbosity, uncomment these lines: #CFLAGS="%{optflags} -Wall -Wsign-compare -Wpointer-arith" #CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" # For ultra gcc verbosity, uncomment these lines also: #CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" #CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" #CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ %if !%{with_shared} --disable-shared \ %endif %if %{with_ipv6} --enable-ipv6 \ %endif %if %{with_snmp} --enable-snmp \ %endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif %if %{with_nssa} --enable-nssa \ %endif %if %{with_opaque_lsa} --enable-opaque-lsa \ %endif %if %{with_ospf_te} --enable-ospf-te \ %endif %if %{with_vtysh} --enable-vtysh \ %endif %if %{with_ospfclient} --enable-ospfclient=yes \ %else --enable-ospfclient=no\ %endif %if %{with_ospfapi} --enable-ospfapi=yes \ %else --enable-ospfapi=no \ %endif %if %{with_irdp} --enable-irdp=yes \ %else --enable-irdp=no \ %endif %if %{with_rtadv} --enable-rtadv=yes \ %else --enable-rtadv=no \ %endif %if %{with_isisd} --enable-isisd \ %else --disable-isisd \ %endif %if %{with_pam} --with-libpam \ %endif %if %quagga_user --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if %vty_group --enable-vty-group=%vty_group \ %endif --enable-netlink --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc texi2html -number quagga.texi popd %install rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} make install \ DESTDIR=$RPM_BUILD_ROOT # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf $RPM_BUILD_ROOT/usr/share/info/dir # install etc sources for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ $RPM_BUILD_ROOT/etc/sysconfig/quagga install -d -m750 $RPM_BUILD_ROOT/var/run/quagga %pre # add vty_group %if %vty_group if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if %quagga_user # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ /usr/sbin/useradd -u %quagga_uid -g %quagga_gid \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi %endif %post # zebra_spec_add_service # e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service () { # Add port /etc/services entry if it isn't already there if [ -f /etc/services ] && \ ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; then echo "$1 $2 # $3" >> /etc/services fi } zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service zebra 2601/tcp "zebra vty" zebra_spec_add_service ripd 2602/tcp "RIPd vty" %if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" %endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" %if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %endif %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif %if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif %if %{with_pimd} zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif for daemon in %daemon_list ; do /sbin/chkconfig --add ${daemon} done /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf %if %{quagga_user} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf %endif chmod 640 %{_sysconfdir}/zebra.conf fi if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do if [ -f /var/lock/subsys/$daemon ]; then eval restart_$daemon=yes else eval restart_$daemon=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no running_watchquagga="$restart_watchquagga" restart_watchquagga=no # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 # Stop all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/$daemon stop >/dev/null 2>&1 done # Restart zebra. [ "$running_zebra" = yes ] && \ /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 # Start all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/$daemon start >/dev/null 2>&1 done # Start watchquagga last. # Avoid postun scriptlet error if watchquagga is not running. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : fi /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun if [ "$1" = "0" ]; then for daemon in %all_daemons ; do /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 /sbin/chkconfig --del ${daemon} done /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir fi %clean %if !%{keep_build} rm -rf $RPM_BUILD_ROOT %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if %{quagga_user} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga %dir %attr(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif %if %{vty_group} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/*info* %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d %{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd %endif %dir %attr(755,root,root) %{_libdir} %if %{with_shared} %dir %{_libdir} %{_libdir}/lib*.so %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %config /etc/rc.d/init.d/* %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %files contrib %defattr(-,root,root) %doc tools %files devel %defattr(-,root,root) %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %{_libdir}/*.a %{_libdir}/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd %{_includedir}/%name/ospfd/*.h %if %{with_ospfapi} %dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi %{_includedir}/%name/ospfapi/*.h %endif %changelog * Thu Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding - Readline need not be an explicit prerequisite - install-info delete should be postun, not preun * Wed Jan 12 2005 Andrew J. Schorr - on package upgrade, implement careful, phased restart logic - use gcc -rdynamic flag when linking for better backtraces * Wed Dec 22 2004 Andrew J. Schorr - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr - watchquagga added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped * Mon Nov 08 2004 Paul Jakma - Use makeinfo --html to generate quagga.html * Sun Nov 07 2004 Paul Jakma - Fix with_ipv6 set to 0 build * Sat Oct 23 2004 Paul Jakma - Update to 0.97.2 * Sat Oct 23 2004 Andrew J. Schorr - Make directories be owned by the packages concerned - Update logrotate scripts to use correct path to killall and use pid files * Fri Oct 08 2004 Paul Jakma - Update to 0.97.0 * Wed Sep 15 2004 Paul Jakma - build snmp support by default - build irdp support - build with shared libs - devel subpackage for archives and headers * Thu Jan 08 2004 Paul Jakma - updated sysconfig files to specify local dir - added ospf_dump.c crash quick fix patch - added ospfd persistent interface configuration patch * Tue Dec 30 2003 Paul Jakma - sync to CVS - integrate RH sysconfig patch to specify daemon options (RH) - default to have vty listen only to 127.1 (RH) - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) - delete info file on %preun, not %postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon * Sun Nov 2 2003 Paul Jakma - Fix -devel package to include all files - Sync to 0.96.4 * Tue Aug 12 2003 Paul Jakma - Renamed to Quagga - Sync to Quagga release 0.96 * Tue Mar 20 2003 Paul Jakma - zebra privileges support * Mon Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp * Sat Mar 1 2003 Paul Jakma - ospfd IOS prefix to interface matching for 'network' statement - temporary fix for PtP and IPv6 - sync to zebra.org CVS * Mon Jan 20 2003 Paul Jakma - update to latest cvs - Yon's "show thread cpu" patch - 17217 - walk up tree - 17218 - ospfd NSSA fixes - 16681 - ospfd nsm fixes - 16824 - ospfd OLSA fixes and new feature - 16823 - KAME and ifindex fixes - 16525 - spec file changes to allow redhat files to be in tree * Sat Dec 28 2002 Alexander Hoogerhuis - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp - Added conditional to %files for %_bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS - add Greg Troxel's md5 buffer copy/dup fix - add RIPv1 fix - add Frank's multicast flag fix * Wed Oct 09 2002 Paul Jakma - update to latest CVS - timestamped crypt_seqnum patch - oi->on_write_q fix * Mon Sep 30 2002 Paul Jakma - update to latest CVS - add vtysh 'write-config (integrated|daemon)' patch - always 'make rebuild' in vtysh/ to catch new commands * Fri Sep 13 2002 Paul Jakma - update to 0.93b * Wed Sep 11 2002 Paul Jakma - update to latest CVS - add "/sbin/ip route flush proto zebra" to zebra RH init on startup * Sat Aug 24 2002 Paul Jakma - update to current CVS - add OSPF point to multipoint patch - add OSPF bugfixes - add BGP hash optimisation patch * Fri Jun 14 2002 Paul Jakma - update to 0.93-pre1 / CVS - add link state detection support - add generic PtP and RFC3021 support - various bug fixes * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 * Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) * Fri Jul 27 2001 Elliot Lee 0.91a-4 - Bump the release when rebuilding into the dist. * Tue Feb 6 2001 Tim Powers - built for Powertools * Sun Feb 4 2001 Pekka Savola - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. - Update to 0.91a - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. - Should be quite Red Hat'isque now. quagga-0.99.24.1/redhat/quagga.pam.stack0000644000175000017500000000234112476520570014553 00000000000000#%PAM-1.0 # ##### if running quagga as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. auth sufficient /lib/security/$ISA/pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient /lib/security/$ISA/pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. #auth required /lib/security/$ISA/pam_wheel.so use_uid ########################################################### # If using quagga privileges and with a seperate group for vty access, then # access can be controlled via the vty access group, and pam can simply # check for valid user/password, eg: # # only allow local users. #auth required /lib/security/$ISA/pam_securetty.so #auth required /lib/security/$ISA/pam_stack.so service=system-auth #auth required /lib/security/$ISA/pam_nologin.so #account required /lib/security/$ISA/pam_stack.so service=system-auth #password required /lib/security/$ISA/pam_stack.so service=system-auth #session required /lib/security/$ISA/pam_stack.so service=system-auth #session optional /lib/security/$ISA/pam_console.so quagga-0.99.24.1/redhat/quagga.pam0000644000175000017500000000171712476520570013455 00000000000000#%PAM-1.0 # ##### if running quagga as root: # Only allow root (and possibly wheel) to use this because enable access # is unrestricted. auth sufficient pam_rootok.so # Uncomment the following line to implicitly trust users in the "wheel" group. #auth sufficient pam_wheel.so trust use_uid # Uncomment the following line to require a user to be in the "wheel" group. #auth required pam_wheel.so use_uid ########################################################### # If using quagga privileges and with a seperate group for vty access, then # access can be controlled via the vty access group, and pam can simply # check for valid user/password, eg: # # only allow local users. #auth required pam_securetty.so #auth include system-auth #auth required pam_nologin.so #account include system-auth #password include system-auth #session include system-auth #session optional pam_console.so quagga-0.99.24.1/redhat/quagga.logrotate0000644000175000017500000000254112476520570014674 00000000000000/var/log/quagga/zebra.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/zebra.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/babeld.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/babeld.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/bgpd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/bgpd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/isisd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/isisd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ospfd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ospfd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ospf6d.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ospf6d.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ripd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ripd.pid 2> /dev/null` 2> /dev/null || true endscript } /var/log/quagga/ripngd.log { notifempty missingok postrotate /bin/kill -USR1 `cat /var/run/quagga/ripngd.pid 2> /dev/null` 2> /dev/null || true endscript } quagga-0.99.24.1/redhat/ospfd.service0000644000175000017500000000051512476520570014201 00000000000000[Unit] Description=OSPF routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ospfd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ospfd -d $OSPFD_OPTS -f /etc/quagga/ospfd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/ospfd.init0000644000175000017500000000241012476520570013500 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ospfd.conf ### BEGIN INIT INFO # Provides: ospfd # Short-Description: OSPF routing engine # Description: OSPF routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ospfd" cmd=ospfd LOCK_FILE=/var/lock/subsys/ospfd CONF_FILE=/etc/quagga/ospfd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $OSPFD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/ospf6d.service0000644000175000017500000000053212476520570014266 00000000000000[Unit] Description=OSPF routing daemon for IPv6 BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/ospf6d.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/ospf6d -d $OSPF6D_OPTS -f /etc/quagga/ospf6d.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/ospf6d.init0000644000175000017500000000244112476520570013572 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/ospf6d.conf ### BEGIN INIT INFO # Provides: ospf6d # Short-Description: OSPF routing engine for IPv6 # Description: OSPF routing engine for use with Zebra and IPv6 ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="ospf6d" cmd=ospf6d LOCK_FILE=/var/lock/subsys/ospf6d CONF_FILE=/etc/quagga/ospf6d.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $OSPF6D_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/isisd.service0000644000175000017500000000051612476520570014202 00000000000000[Unit] Description=IS-IS routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/isisd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/isisd -d $ISISD_OPTS -f /etc/quagga/isisd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/isisd.init0000644000175000017500000000241212476520570013502 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/isisd.conf ### BEGIN INIT INFO # Provides: isisd # Short-Description: IS-IS routing engine # Description: IS-IS routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="isisd" cmd=isisd LOCK_FILE=/var/lock/subsys/isisd CONF_FILE=/etc/quagga/isisd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $ISISD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/bgpd.service0000644000175000017500000000051012476520570013775 00000000000000[Unit] Description=BGP routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/bgpd.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/bgpd -d $BGPD_OPTS -f /etc/quagga/bgpd.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/bgpd.init0000644000175000017500000000237712476520570013315 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/bgpd.conf ### BEGIN INIT INFO # Provides: bgpd # Short-Description: BGP routing engine # Description: BGP routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="bgpd" cmd=bgpd LOCK_FILE=/var/lock/subsys/bgpd CONF_FILE=/etc/quagga/bgpd.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $BGPD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/babeld.service0000644000175000017500000000052212476520570014275 00000000000000[Unit] Description=Babel routing daemon BindTo=zebra.service After=syslog.target network.target zebra.service ConditionPathExists=/etc/quagga/babeld.conf [Service] Type=forking EnvironmentFile=/etc/sysconfig/quagga ExecStart=/usr/sbin/babeld -d $BABELD_OPTS -f /etc/quagga/babeld.conf Restart=on-abort [Install] WantedBy=network.target quagga-0.99.24.1/redhat/babeld.init0000644000175000017500000000242112476520570013600 00000000000000#!/bin/bash # chkconfig: - 16 84 # config: /etc/quagga/babeld.conf ### BEGIN INIT INFO # Provides: babeld # Short-Description: Babel routing engine # Description: Babel routing engine for use with Zebra ### END INIT INFO # source function library . /etc/rc.d/init.d/functions # Get network config . /etc/sysconfig/network # quagga command line options . /etc/sysconfig/quagga RETVAL=0 PROG="babeld" cmd=babeld LOCK_FILE=/var/lock/subsys/babeld CONF_FILE=/etc/quagga/babeld.conf case "$1" in start) # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 # The process must be configured first. [ -f $CONF_FILE ] || exit 6 if [ `id -u` -ne 0 ]; then echo $"Insufficient privilege" 1>&2 exit 4 fi echo -n $"Starting $PROG: " daemon $cmd -d $BABELD_OPTS -f $CONF_FILE RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK_FILE echo ;; stop) echo -n $"Shutting down $PROG: " killproc $cmd RETVAL=$? [ $RETVAL -eq 0 ] && rm -f $LOCK_FILE echo ;; restart|reload|force-reload) $0 stop $0 start RETVAL=$? ;; condrestart|try-restart) if [ -f $LOCK_FILE ]; then $0 stop $0 start fi RETVAL=$? ;; status) status $cmd RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" exit 2 esac exit $RETVAL quagga-0.99.24.1/redhat/quagga.spec.in0000644000175000017500000004220412476520570014233 00000000000000# configure options # # Some can be overriden on rpmbuild commandline with: # rpmbuild --define 'variable value' # ####################### Quagga configure options ######################### # with-feature options %{!?with_snmp: %define with_snmp 1 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_ospf_te: %define with_ospf_te 1 } %{!?with_nssa: %define with_nssa 1 } %{!?with_opaque_lsa: %define with_opaque_lsa 1 } %{!?with_tcp_zebra: %define with_tcp_zebra 0 } %{!?with_vtysh: %define with_vtysh 1 } %{!?with_pam: %define with_pam 1 } %{!?with_ipv6: %define with_ipv6 1 } %{!?with_ospfclient: %define with_ospfclient 1 } %{!?with_ospfapi: %define with_ospfapi 1 } %{!?with_irdp: %define with_irdp 1 } %{!?with_rtadv: %define with_rtadv 1 } %{!?with_isisd: %define with_isisd 1 } %{!?with_shared: %define with_shared 1 } %{!?with_multipath: %define with_multipath 64 } %{!?quagga_user: %define quagga_user quagga } %{!?vty_group: %define vty_group quaggavty } # path defines %define _sysconfdir /etc/quagga %define zeb_src %{_builddir}/%{name}-%{version} %define zeb_rh_src %{zeb_src}/redhat %define zeb_docs %{zeb_src}/doc # defines for configure %define _libexecdir %{_exec_prefix}/libexec/quagga %define _libdir %{_exec_prefix}/%{_lib}/quagga %define _includedir %{_prefix}/include %define _localstatedir /var/run/quagga ############################################################################ ####################### distro specific tweaks ############################# # default distro. Override with rpmbuild -D "dist XXX" %{expand: %%define default_dist %(rpm -q --qf 'fc%%{VERSION}' fedora-release | grep -v 'not installed')} %{!?dist: %define dist %{default_dist}} # as distros change packages we depend on, our Requires have to change, sadly. %define quagga_buildreqs texi2html texinfo tetex autoconf pam-devel %define quagga_buildreqs %{quagga_buildreqs} patch libcap-devel # FC4 and 5 split texi2html out of tetex package. %if "%dist" != "fc2" || "%dist" != "fc3" %define quagga_buildreqs %{quagga_buildreqs} texi2html %endif # pam_stack is deprecated in FC5 # default to pam_stack, default should be changed later. %if "%dist" == "fc4" || "%dist" == "fc3" %define quagga_pam_source quagga.pam.stack %else %define quagga_pam_source quagga.pam %endif ############################################################################ # misc internal defines %{!?quagga_uid: %define quagga_uid 92 } %{!?quagga_gid: %define quagga_gid 92 } %define daemon_list zebra ripd ospfd bgpd %if %{with_ipv6} %define daemonv6_list ripngd babeld ospf6d %else %define daemonv6_list "" %endif %if %{with_isisd} %define daemon_other isisd %else %define daemon_other "" %endif %define all_daemons %{daemon_list} %{daemonv6_list} %{daemon_other} watchquagga # allow build dir to be kept %{!?keep_build: %define keep_build 0 } #release sub-revision (the two digits after the CONFDATE) %{!?release_rev: %define release_rev 01 } Summary: Routing daemon Name: quagga Version: @VERSION@ Release: @CONFDATE@%{release_rev} License: GPL Group: System Environment/Daemons Source0: http://www.quagga.net/snapshots/cvs/%{name}-%{version}.tar.gz URL: http://www.quagga.net %if %{with_snmp} BuildRequires: net-snmp-devel Requires(pre): net-snmp %endif %if %{with_vtysh} BuildRequires: readline readline-devel ncurses ncurses-devel Requires(pre): ncurses %endif BuildRequires: texinfo tetex autoconf pam-devel patch libcap-devel tetex # Initscripts > 5.60 is required for IPv6 support Requires(pre): initscripts >= 5.60 Requires(pre): ncurses pam Requires(pre): /sbin/install-info Provides: routingdaemon BuildRoot: %{_tmppath}/%{name}-%{version}-root Obsoletes: bird gated mrt zebra %description Quagga is a free software that manages TCP/IP based routing protocol. It takes multi-server and multi-thread approach to resolve the current complexity of the Internet. Quagga supports BGP4, BGP4+, OSPFv2, OSPFv3, RIPv1, RIPv2, and RIPng. Quagga is intended to be used as a Route Server and a Route Reflector. It is not a toolkit, it provides full routing power under a new architecture. Quagga by design has a process for each protocol. Quagga is a fork of GNU Zebra. %package contrib Summary: contrib tools for quagga Group: System Environment/Daemons %description contrib Contributed/3rd party tools which may be of use with quagga. %package devel Summary: Header and object files for quagga development Group: System Environment/Daemons %description devel The quagga-devel package contains the header and object files neccessary for developing OSPF-API and quagga applications. %prep %setup -q %build # For standard gcc verbosity, uncomment these lines: #CFLAGS="%{optflags} -Wall -Wsign-compare -Wpointer-arith" #CFLAGS="${CFLAGS} -Wbad-function-cast -Wwrite-strings" # For ultra gcc verbosity, uncomment these lines also: #CFLAGS="${CFLAGS} -W -Wcast-qual -Wstrict-prototypes" #CFLAGS="${CFLAGS} -Wmissing-declarations -Wmissing-noreturn" #CFLAGS="${CFLAGS} -Wmissing-format-attribute -Wunreachable-code" #CFLAGS="${CFLAGS} -Wpacked -Wpadded" %configure \ %if !%{with_shared} --disable-shared \ %endif %if %{with_ipv6} --enable-ipv6 \ %endif %if %{with_snmp} --enable-snmp \ %endif %if %{with_multipath} --enable-multipath=%{with_multipath} \ %endif %if %{with_tcp_zebra} --enable-tcp-zebra \ %endif %if %{with_nssa} --enable-nssa \ %endif %if %{with_opaque_lsa} --enable-opaque-lsa \ %endif %if %{with_ospf_te} --enable-ospf-te \ %endif %if %{with_vtysh} --enable-vtysh \ %endif %if %{with_ospfclient} --enable-ospfclient=yes \ %else --enable-ospfclient=no\ %endif %if %{with_ospfapi} --enable-ospfapi=yes \ %else --enable-ospfapi=no \ %endif %if %{with_irdp} --enable-irdp=yes \ %else --enable-irdp=no \ %endif %if %{with_rtadv} --enable-rtadv=yes \ %else --enable-rtadv=no \ %endif %if %{with_isisd} --enable-isisd \ %else --disable-isisd \ %endif %if %{with_pam} --with-libpam \ %endif %if %quagga_user --enable-user=%quagga_user \ --enable-group=%quagga_user \ %endif %if %vty_group --enable-vty-group=%vty_group \ %endif --enable-netlink --enable-gcc-rdynamic make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" pushd doc texi2html -number quagga.texi popd %install rm -rf $RPM_BUILD_ROOT install -d $RPM_BUILD_ROOT/etc/{rc.d/init.d,sysconfig,logrotate.d,pam.d} \ $RPM_BUILD_ROOT/var/log/quagga $RPM_BUILD_ROOT%{_infodir} make install \ DESTDIR=$RPM_BUILD_ROOT # Remove this file, as it is uninstalled and causes errors when building on RH9 rm -rf $RPM_BUILD_ROOT/usr/share/info/dir # install etc sources for daemon in %{all_daemons} ; do if [ x"${daemon}" != x"" ] ; then install %{zeb_rh_src}/${daemon}.init \ $RPM_BUILD_ROOT/etc/rc.d/init.d/${daemon} fi done install -m644 %{zeb_rh_src}/%{quagga_pam_source} \ $RPM_BUILD_ROOT/etc/pam.d/quagga install -m644 %{zeb_rh_src}/quagga.logrotate \ $RPM_BUILD_ROOT/etc/logrotate.d/quagga install -m644 %{zeb_rh_src}/quagga.sysconfig \ $RPM_BUILD_ROOT/etc/sysconfig/quagga install -d -m750 $RPM_BUILD_ROOT/var/run/quagga %pre # add vty_group %if %vty_group if getent group %vty_group > /dev/null ; then : ; else \ /usr/sbin/groupadd -r %vty_group > /dev/null || : ; fi %endif # add quagga user and group %if %quagga_user # Ensure that quagga_gid gets correctly allocated if getent group %quagga_user >/dev/null; then : ; else \ /usr/sbin/groupadd -g %quagga_gid %quagga_user > /dev/null || : ; \ fi if getent passwd %quagga_user >/dev/null ; then : ; else \ /usr/sbin/useradd -u %quagga_uid -g %quagga_gid \ -M -r -s /sbin/nologin -c "Quagga routing suite" \ -d %_localstatedir %quagga_user 2> /dev/null || : ; \ fi %endif %post # zebra_spec_add_service # e.g. zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service () { # Add port /etc/services entry if it isn't already there if [ -f /etc/services ] && \ ! %__sed -e 's/#.*$//' /etc/services | %__grep -wq $1 ; then echo "$1 $2 # $3" >> /etc/services fi } zebra_spec_add_service zebrasrv 2600/tcp "zebra service" zebra_spec_add_service zebra 2601/tcp "zebra vty" zebra_spec_add_service ripd 2602/tcp "RIPd vty" %if %{with_ipv6} zebra_spec_add_service ripngd 2603/tcp "RIPngd vty" %endif zebra_spec_add_service ospfd 2604/tcp "OSPFd vty" zebra_spec_add_service bgpd 2605/tcp "BGPd vty" %if %{with_ipv6} zebra_spec_add_service ospf6d 2606/tcp "OSPF6d vty" %endif %if %{with_ospfapi} zebra_spec_add_service ospfapi 2607/tcp "OSPF-API" %endif %if %{with_isisd} zebra_spec_add_service isisd 2608/tcp "ISISd vty" %endif %if %{with_pimd} zebra_spec_add_service pimd 2611/tcp "PIMd vty" %endif for daemon in %daemon_list ; do /sbin/chkconfig --add ${daemon} done /sbin/install-info %{_infodir}/quagga.info.gz %{_infodir}/dir # Create dummy files if they don't exist so basic functions can be used. if [ ! -e %{_sysconfdir}/zebra.conf ]; then echo "hostname `hostname`" > %{_sysconfdir}/zebra.conf %if %{quagga_user} chown %quagga_user:%quagga_user %{_sysconfdir}/zebra.conf %endif chmod 640 %{_sysconfdir}/zebra.conf fi if [ ! -e %{_sysconfdir}/vtysh.conf ]; then touch %{_sysconfdir}/vtysh.conf chmod 640 %{_sysconfdir}/vtysh.conf fi %postun if [ "$1" -ge 1 ]; then # Find out which daemons need to be restarted. for daemon in %all_daemons ; do if [ -f /var/lock/subsys/$daemon ]; then eval restart_$daemon=yes else eval restart_$daemon=no fi done # Rename restart flags for daemons handled specially. running_zebra="$restart_zebra" restart_zebra=no running_watchquagga="$restart_watchquagga" restart_watchquagga=no # Stop watchquagga first. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga stop >/dev/null 2>&1 # Stop all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/$daemon stop >/dev/null 2>&1 done # Restart zebra. [ "$running_zebra" = yes ] && \ /etc/rc.d/init.d/zebra restart >/dev/null 2>&1 # Start all daemons other than zebra and watchquagga. for daemon in %all_daemons ; do eval restart=\$restart_${daemon} [ "$restart" = yes ] && \ /etc/rc.d/init.d/$daemon start >/dev/null 2>&1 done # Start watchquagga last. # Avoid postun scriptlet error if watchquagga is not running. [ "$running_watchquagga" = yes ] && \ /etc/rc.d/init.d/watchquagga start >/dev/null 2>&1 || : fi /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir %preun if [ "$1" = "0" ]; then for daemon in %all_daemons ; do /etc/rc.d/init.d/${daemon} stop >/dev/null 2>&1 /sbin/chkconfig --del ${daemon} done /sbin/install-info --delete %{_infodir}/quagga.info.gz %{_infodir}/dir fi %clean %if !%{keep_build} rm -rf $RPM_BUILD_ROOT %endif %files %defattr(-,root,root) %doc */*.sample* AUTHORS COPYING %doc doc/quagga.html %doc doc/mpls %doc ChangeLog INSTALL NEWS README REPORTING-BUGS SERVICES TODO %if %{quagga_user} %dir %attr(751,%quagga_user,%quagga_user) %{_sysconfdir} %dir %attr(750,%quagga_user,%quagga_user) /var/log/quagga %dir %attr(751,%quagga_user,%quagga_user) /var/run/quagga %else %dir %attr(750,root,root) %{_sysconfdir} %dir %attr(750,root,root) /var/log/quagga %dir %attr(755,root,root) /usr/share/info %dir %attr(750,root,root) /var/run/quagga %endif %if %{vty_group} %attr(750,%quagga_user,%vty_group) %{_sysconfdir}/vtysh.conf.sample %endif %{_infodir}/*info* %{_mandir}/man*/* %{_sbindir}/zebra %{_sbindir}/ospfd %{_sbindir}/ripd %{_sbindir}/bgpd %{_sbindir}/watchquagga %if %{with_ipv6} %{_sbindir}/ripngd %{_sbindir}/ospf6d %{_sbindir}/babeld %endif %if %{with_isisd} %{_sbindir}/isisd %endif %dir %attr(755,root,root) %{_libdir} %if %{with_shared} %dir %{_libdir} %{_libdir}/lib*.so %{_libdir}/lib*.so.* %endif %if %{with_vtysh} %{_bindir}/* %endif %config /etc/quagga/[!v]* %config /etc/rc.d/init.d/* %config(noreplace) /etc/sysconfig/quagga %config(noreplace) /etc/pam.d/quagga %config(noreplace) %attr(640,root,root) /etc/logrotate.d/* %files contrib %defattr(-,root,root) %doc tools %files devel %defattr(-,root,root) %if %{with_ospfclient} %{_sbindir}/ospfclient %endif %{_libdir}/*.a %{_libdir}/*.la %dir %attr(755,root,root) %{_includedir}/%{name} %{_includedir}/%name/*.h %dir %attr(755,root,root) %{_includedir}/%{name}/ospfd %{_includedir}/%name/ospfd/*.h %if %{with_ospfapi} %dir %attr(755,root,root) %{_includedir}/%{name}/ospfapi %{_includedir}/%name/ospfapi/*.h %endif %changelog * Thu Sep 12 2005 Paul Jakma - Steal some changes from Fedora spec file: - Add with_rtadv variable - Test for groups/users with getent before group/user adding - Readline need not be an explicit prerequisite - install-info delete should be postun, not preun * Wed Jan 12 2005 Andrew J. Schorr - on package upgrade, implement careful, phased restart logic - use gcc -rdynamic flag when linking for better backtraces * Wed Dec 22 2004 Andrew J. Schorr - daemonv6_list should contain only IPv6 daemons * Wed Dec 22 2004 Andrew J. Schorr - watchquagga added - on upgrade, all daemons should be condrestart'ed - on removal, all daemons should be stopped * Mon Nov 08 2004 Paul Jakma - Use makeinfo --html to generate quagga.html * Sun Nov 07 2004 Paul Jakma - Fix with_ipv6 set to 0 build * Sat Oct 23 2004 Paul Jakma - Update to 0.97.2 * Sat Oct 23 2004 Andrew J. Schorr - Make directories be owned by the packages concerned - Update logrotate scripts to use correct path to killall and use pid files * Fri Oct 08 2004 Paul Jakma - Update to 0.97.0 * Wed Sep 15 2004 Paul Jakma - build snmp support by default - build irdp support - build with shared libs - devel subpackage for archives and headers * Thu Jan 08 2004 Paul Jakma - updated sysconfig files to specify local dir - added ospf_dump.c crash quick fix patch - added ospfd persistent interface configuration patch * Tue Dec 30 2003 Paul Jakma - sync to CVS - integrate RH sysconfig patch to specify daemon options (RH) - default to have vty listen only to 127.1 (RH) - add user with fixed UID/GID (RH) - create user with shell /sbin/nologin rather than /bin/false (RH) - stop daemons on uninstall (RH) - delete info file on %preun, not %postun to avoid deletion on upgrade. (RH) - isisd added - cleanup tasks carried out for every daemon * Sun Nov 2 2003 Paul Jakma - Fix -devel package to include all files - Sync to 0.96.4 * Tue Aug 12 2003 Paul Jakma - Renamed to Quagga - Sync to Quagga release 0.96 * Tue Mar 20 2003 Paul Jakma - zebra privileges support * Mon Mar 18 2003 Paul Jakma - Fix mem leak in 'show thread cpu' - Ralph Keller's OSPF-API - Amir: Fix configure.ac for net-snmp * Sat Mar 1 2003 Paul Jakma - ospfd IOS prefix to interface matching for 'network' statement - temporary fix for PtP and IPv6 - sync to zebra.org CVS * Mon Jan 20 2003 Paul Jakma - update to latest cvs - Yon's "show thread cpu" patch - 17217 - walk up tree - 17218 - ospfd NSSA fixes - 16681 - ospfd nsm fixes - 16824 - ospfd OLSA fixes and new feature - 16823 - KAME and ifindex fixes - 16525 - spec file changes to allow redhat files to be in tree * Sat Dec 28 2002 Alexander Hoogerhuis - Added conditionals for building with(out) IPv6, vtysh, RIP, BGP - Fixed up some build requirements (patch) - Added conditional build requirements for vtysh / snmp - Added conditional to %files for %_bindir depending on vtysh * Mon Nov 11 2002 Paul Jakma - update to latest CVS - add Greg Troxel's md5 buffer copy/dup fix - add RIPv1 fix - add Frank's multicast flag fix * Wed Oct 09 2002 Paul Jakma - update to latest CVS - timestamped crypt_seqnum patch - oi->on_write_q fix * Mon Sep 30 2002 Paul Jakma - update to latest CVS - add vtysh 'write-config (integrated|daemon)' patch - always 'make rebuild' in vtysh/ to catch new commands * Fri Sep 13 2002 Paul Jakma - update to 0.93b * Wed Sep 11 2002 Paul Jakma - update to latest CVS - add "/sbin/ip route flush proto zebra" to zebra RH init on startup * Sat Aug 24 2002 Paul Jakma - update to current CVS - add OSPF point to multipoint patch - add OSPF bugfixes - add BGP hash optimisation patch * Fri Jun 14 2002 Paul Jakma - update to 0.93-pre1 / CVS - add link state detection support - add generic PtP and RFC3021 support - various bug fixes * Thu Aug 09 2001 Elliot Lee 0.91a-6 - Fix bug #51336 * Wed Aug 1 2001 Trond Eivind Glomsrød 0.91a-5 - Use generic initscript strings instead of initscript specific ( "Starting foo: " -> "Starting $prog:" ) * Fri Jul 27 2001 Elliot Lee 0.91a-4 - Bump the release when rebuilding into the dist. * Tue Feb 6 2001 Tim Powers - built for Powertools * Sun Feb 4 2001 Pekka Savola - Hacked up from PLD Linux 0.90-1, Mandrake 0.90-1mdk and one from zebra.org. - Update to 0.91a - Very heavy modifications to init.d/*, .spec, pam, i18n, logrotate, etc. - Should be quite Red Hat'isque now. quagga-0.99.24.1/redhat/Makefile.am0000644000175000017500000000047712476520570013547 00000000000000 EXTRA_DIST = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init zebra.init zebra.service quagga-0.99.24.1/redhat/Makefile.in0000644000175000017500000003243512476521251013554 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = redhat DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/quagga.spec.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = quagga.spec CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = babeld.init babeld.service bgpd.init bgpd.service isisd.init \ isisd.service ospf6d.init ospf6d.service ospfd.init ospfd.service \ quagga.logrotate quagga.pam quagga.pam.stack quagga.spec \ quagga.sysconfig ripd.init ripd.service ripngd.init ripngd.service \ watchquagga.init zebra.init zebra.service all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu redhat/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu redhat/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): quagga.spec: $(top_builddir)/config.status $(srcdir)/quagga.spec.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/pkgsrc/0000755000175000017500000000000012476521364011607 500000000000000quagga-0.99.24.1/pkgsrc/zebra.sh.in0000644000175000017500000000162112476520570013571 00000000000000#!/bin/sh # # zebra is the head of the quagga routing beast # # PROVIDE: zebra # REQUIRE: NETWORKING ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="zebra" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" stop_postcmd="zebra_postcmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { mkdir -p "${socket_dir}" chown quagga.quagga "${socket_dir}" chmod 750 "${socket_dir}" rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } zebra_postcmd() { if [ -d "${socketdir}" ]; then rmdir ${socketdir} fi } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/ripngd.sh.in0000644000175000017500000000126112476520570013751 00000000000000#!/bin/sh # # ripngd is part of the quagga routing beast # # PROVIDE: ripngd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ripngd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/ripd.sh.in0000644000175000017500000000125312476520570013425 00000000000000#!/bin/sh # # ripd is part of the quagga routing beast # # PROVIDE: ripd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ripd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/ospfd.sh.in0000644000175000017500000000125612476520570013605 00000000000000#!/bin/sh # # ospfd is part of the quagga routing beast # # PROVIDE: ospfd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ospfd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/ospf6d.sh.in0000644000175000017500000000126112476520570013667 00000000000000#!/bin/sh # # ospf6d is part of the quagga routing beast # # PROVIDE: ospf6d # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="ospf6d" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/bgpd.sh.in0000644000175000017500000000125312476520570013403 00000000000000#!/bin/sh # # bgpd is part of the quagga routing beast # # PROVIDE: bgpd # REQUIRE: zebra ## PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin export PATH if [ -f /etc/rc.subr ] then . /etc/rc.subr fi name="bgpd" rcvar=$name required_files="@sysconfdir@/${name}.conf" command="@prefix@/sbin/${name}" command_args="-d" start_precmd="zebra_precmd" socket_dir=@localstatedir@ pidfile="${socket_dir}/${name}.pid" zebra_precmd() { rc_flags="$( set -- $rc_flags while [ $# -ne 0 ]; do if [ X"$1" = X-P -o X"$1" = X-A ]; then break fi shift done if [ $# -eq 0 ]; then echo "-P 0" fi ) $rc_flags" } load_rc_config $name run_rc_command "$1" quagga-0.99.24.1/pkgsrc/Makefile.am0000644000175000017500000000013012476520570013553 00000000000000rcdir=@pkgsrcrcdir@ rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh quagga-0.99.24.1/pkgsrc/Makefile.in0000644000175000017500000004113112476521251013567 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = pkgsrc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/bgpd.sh.in $(srcdir)/ospf6d.sh.in \ $(srcdir)/ospfd.sh.in $(srcdir)/ripd.sh.in \ $(srcdir)/ripngd.sh.in $(srcdir)/zebra.sh.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh \ zebra.sh CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(rcdir)" SCRIPTS = $(rc_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ rcdir = @pkgsrcrcdir@ rc_SCRIPTS = bgpd.sh ospf6d.sh ospfd.sh ripd.sh ripngd.sh zebra.sh all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu pkgsrc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu pkgsrc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): bgpd.sh: $(top_builddir)/config.status $(srcdir)/bgpd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ospf6d.sh: $(top_builddir)/config.status $(srcdir)/ospf6d.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ospfd.sh: $(top_builddir)/config.status $(srcdir)/ospfd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ripd.sh: $(top_builddir)/config.status $(srcdir)/ripd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ ripngd.sh: $(top_builddir)/config.status $(srcdir)/ripngd.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ zebra.sh: $(top_builddir)/config.status $(srcdir)/zebra.sh.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-rcSCRIPTS: $(rc_SCRIPTS) @$(NORMAL_INSTALL) @list='$(rc_SCRIPTS)'; test -n "$(rcdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(rcdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(rcdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(rcdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(rcdir)$$dir" || exit $$?; \ } \ ; done uninstall-rcSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(rc_SCRIPTS)'; test -n "$(rcdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(rcdir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(rcdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-rcSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-rcSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-rcSCRIPTS install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags-am uninstall uninstall-am uninstall-rcSCRIPTS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/doc/0000755000175000017500000000000012476521364011063 500000000000000quagga-0.99.24.1/doc/quagga.info-20000644000175000017500000002042312476521364013265 00000000000000This is quagga.info, produced by makeinfo version 5.2 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 0.99.24.1, last updated 7 March 2015 of 'The Quagga Manual', for Quagga Version 0.99.24.1. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro.  File: quagga.info, Node: VTY Key Index, Next: Index, Prev: Command Index, Up: Top VTY Key Index ************* [index] * Menu: * : CLI Advanced Commands. (line 27) * C-a: CLI Movement Commands. (line 24) * C-b: CLI Movement Commands. (line 15) * C-c: CLI Advanced Commands. (line 10) * C-d: CLI Editing Commands. (line 14) * C-e: CLI Movement Commands. (line 27) * C-f: CLI Movement Commands. (line 11) * C-h: CLI Editing Commands. (line 11) * C-k: CLI Editing Commands. (line 23) * C-n: CLI Advanced Commands. (line 17) * C-p: CLI Advanced Commands. (line 21) * C-t: CLI Editing Commands. (line 29) * C-u: CLI Editing Commands. (line 26) * C-w: CLI Editing Commands. (line 20) * C-z: CLI Advanced Commands. (line 13) * : CLI Editing Commands. (line 11) * : CLI Advanced Commands. (line 17) * : CLI Movement Commands. (line 15) * M-b: CLI Movement Commands. (line 21) * M-d: CLI Editing Commands. (line 17) * M-f: CLI Movement Commands. (line 18) * : CLI Movement Commands. (line 11) * : CLI Advanced Commands. (line 24) * : CLI Advanced Commands. (line 21)  File: quagga.info, Node: Index, Prev: VTY Key Index, Up: Top Index ***** [index] * Menu: * About Quagga: About Quagga. (line 6) * Bug hunting: Bug Reports. (line 6) * Bug Reports: Bug Reports. (line 6) * Build options: The Configure script and its options. (line 6) * Building on Linux boxes: Linux notes. (line 6) * Building the system: Installation. (line 6) * Compatibility with other systems: Supported Platforms. (line 6) * Configuration files for running the software: Config Commands. (line 6) * Configuration options: The Configure script and its options. (line 6) * Configuring Quagga: Linux notes. (line 6) * Contact information: Mailing List. (line 6) * Distribution configuration: The Configure script and its options. (line 6) * Errors in the software: Bug Reports. (line 6) * Files for running configurations: Config Commands. (line 6) * Found a bug?: Bug Reports. (line 6) * Getting the herd running: Config Commands. (line 6) * How to get in touch with Quagga: Mailing List. (line 6) * How to install Quagga: Installation. (line 6) * Installation: Installation. (line 6) * Installing Quagga: Installation. (line 6) * Linux configurations: Linux notes. (line 6) * Mailing lists: Mailing List. (line 6) * Mailing Quagga: Mailing List. (line 6) * Making Quagga: Installation. (line 6) * Modifying the herd's behavior: Config Commands. (line 6) * Operating systems that support Quagga: Supported Platforms. (line 6) * Options for configuring: The Configure script and its options. (line 6) * Options to './configure': The Configure script and its options. (line 6) * OSPFv2: ripngd Filtering Commands. (line 12) * Overview: Overview. (line 6) * Quagga Least-Privileges: Least-Privilege support. (line 6) * Quagga on other systems: Supported Platforms. (line 6) * Quagga Privileges: Least-Privilege support. (line 6) * Reporting bugs: Bug Reports. (line 6) * Reporting software errors: Bug Reports. (line 6) * Software architecture: System Architecture. (line 6) * Software internals: System Architecture. (line 6) * Supported platforms: Supported Platforms. (line 6) * System architecture: System Architecture. (line 6) quagga-0.99.24.1/doc/quagga.info-10000644000175000017500000116741712476521364013304 00000000000000This is quagga.info, produced by makeinfo version 5.2 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 0.99.24.1, last updated 7 March 2015 of 'The Quagga Manual', for Quagga Version 0.99.24.1. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro.  File: quagga.info, Node: Top, Next: Overview, Up: (dir) Quagga ****** Quagga is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual for Quagga 0.99.24.1. Quagga is a fork of GNU Zebra. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro. * Menu: * Overview:: * Installation:: * Basic commands:: * Zebra:: * RIP:: * RIPng:: * OSPFv2:: * OSPFv3:: * Babel:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: * Filtering:: * Route Map:: * IPv6 Support:: * Kernel Interface:: * SNMP Support:: * Zebra Protocol:: * Packet Binary Dump Format:: * Command Index:: * VTY Key Index:: * Index::  File: quagga.info, Node: Overview, Next: Installation, Prev: Top, Up: Top 1 Overview ********** Quagga is a routing software package that provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (*note Supported RFCs::). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX protocol, Quagga provides routing protocol MIBs (*note SNMP Support::). Quagga uses an advanced software architecture to provide you with a high quality, multi server routing engine. Quagga has an interactive user interface for each routing protocol and supports common client commands. Due to this design, you can add new protocol daemons to Quagga easily. You can use Quagga library as your program's client user interface. Quagga is distributed under the GNU General Public License. * Menu: * About Quagga:: Basic information about Quagga * System Architecture:: The Quagga system architecture * Supported Platforms:: Supported platforms and future plans * Supported RFCs:: Supported RFCs * How to get Quagga:: * Mailing List:: Mailing list information * Bug Reports:: Mail address for bug data  File: quagga.info, Node: About Quagga, Next: System Architecture, Up: Overview 1.1 About Quagga ================ Today, TCP/IP networks are covering all of the world. The Internet has been deployed in many countries, companies, and to the home. When you connect to the Internet your packet will pass many routers which have TCP/IP routing functionality. A system with Quagga installed acts as a dedicated router. With Quagga, your machine exchanges routing information with other routers using routing protocols. Quagga uses this information to update the kernel routing table so that the right data goes to the right place. You can dynamically change the configuration and you may view routing table information from the Quagga terminal interface. Adding to routing protocol support, Quagga can setup interface's flags, interface's address, static routes and so on. If you have a small network, or a stub network, or xDSL connection, configuring the Quagga routing software is very easy. The only thing you have to do is to set up the interfaces and put a few commands about static routes and/or default routes. If the network is rather large, or if the network structure changes frequently, you will want to take advantage of Quagga's dynamic routing protocol support for protocols such as RIP, OSPF, IS-IS or BGP. Traditionally, UNIX based router configuration is done by 'ifconfig' and 'route' commands. Status of routing table is displayed by 'netstat' utility. Almost of these commands work only if the user has root privileges. Quagga has a different system administration method. There are two user modes in Quagga. One is normal mode, the other is enable mode. Normal mode user can only view system status, enable mode user can change system configuration. This UNIX account independent feature will be great help to the router administrator. Currently, Quagga supports common unicast routing protocols, that is BGP, OSPF, RIP and IS-IS. Upcoming for MPLS support, an implementation of LDP is currently being prepared for merging. Implementations of BFD and PIM-SSM (IPv4) also exist, but are not actively being worked on. The ultimate goal of the Quagga project is making a productive, quality, free TCP/IP routing software package.  File: quagga.info, Node: System Architecture, Next: Supported Platforms, Prev: About Quagga, Up: Overview 1.2 System Architecture ======================= Traditional routing software is made as a one process program which provides all of the routing protocol functionalities. Quagga takes a different approach. It is made from a collection of several daemons that work together to build the routing table. There may be several protocol-specific routing daemons and zebra the kernel routing manager. The 'ripd' daemon handles the RIP protocol, while 'ospfd' is a daemon which supports OSPF version 2. 'bgpd' supports the BGP-4 protocol. For changing the kernel routing table and for redistribution of routes between different routing protocols, there is a kernel routing table manager 'zebra' daemon. It is easy to add a new routing protocol daemons to the entire routing system without affecting any other software. You need to run only the protocol daemon associated with routing protocols in use. Thus, user may run a specific daemon and send routing reports to a central routing console. There is no need for these daemons to be running on the same machine. You can even run several same protocol daemons on the same machine. This architecture creates new possibilities for the routing system. +----+ +----+ +-----+ +-----+ |bgpd| |ripd| |ospfd| |zebra| +----+ +----+ +-----+ +-----+ | +---------------------------|--+ | v | | UNIX Kernel routing table | | | +------------------------------+ Quagga System Architecture Multi-process architecture brings extensibility, modularity and maintainability. At the same time it also brings many configuration files and terminal interfaces. Each daemon has it's own configuration file and terminal interface. When you configure a static route, it must be done in 'zebra' configuration file. When you configure BGP network it must be done in 'bgpd' configuration file. This can be a very annoying thing. To resolve the problem, Quagga provides integrated user interface shell called 'vtysh'. 'vtysh' connects to each daemon with UNIX domain socket and then works as a proxy for user input. Quagga was planned to use multi-threaded mechanism when it runs with a kernel that supports multi-threads. But at the moment, the thread library which comes with GNU/Linux or FreeBSD has some problems with running reliable services such as routing software, so we don't use threads at all. Instead we use the 'select(2)' system call for multiplexing the events.  File: quagga.info, Node: Supported Platforms, Next: Supported RFCs, Prev: System Architecture, Up: Overview 1.3 Supported Platforms ======================= Currently Quagga supports GNU/Linux and BSD. Porting Quagga to other platforms is not too difficult as platform dependent code should most be limited to the 'zebra' daemon. Protocol daemons are mostly platform independent. Please let us know when you find out Quagga runs on a platform which is not listed below. The list of officially supported platforms are listed below. Note that Quagga may run correctly on other platforms, and may run with partial functionality on further platforms. * GNU/Linux * FreeBSD * NetBSD * OpenBSD Versions of these platforms that are older than around 2 years from the point of their original release (in case of GNU/Linux, this is since the kernel's release on kernel.org) may need some work. Similarly, the following platforms may work with some effort: * Solaris * Mac OSX Also note that, in particular regarding proprietary platforms, compiler and C library choice will affect Quagga. Only recent versions of the following C compilers are well-tested: * GNU's GCC * LLVM's clang * Intel's ICC  File: quagga.info, Node: Supported RFCs, Next: How to get Quagga, Prev: Supported Platforms, Up: Overview 1.4 Supported RFCs ================== Below is the list of currently supported RFC's. RFC1058 'Routing Information Protocol. C.L. Hedrick. Jun-01-1988.' RF2082 'RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.' RFC2453 'RIP Version 2. G. Malkin. November 1998.' RFC2080 'RIPng for IPv6. G. Malkin, R. Minnear. January 1997.' RFC2328 'OSPF Version 2. J. Moy. April 1998.' RFC2370 'The OSPF Opaque LSA Option R. Coltun. July 1998.' RFC3101 'The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.' RFC2740 'OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.' RFC1771 'A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.' RFC1965 'Autonomous System Confederations for BGP. P. Traina. June 1996.' RFC1997 'BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.' RFC2545 'Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.' RFC2796 'BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.' RFC2858 'Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.' RFC2842 'Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.' RFC3137 'OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001' When SNMP support is enabled, below RFC is also supported. RFC1227 'SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.' RFC1657 'Definitions of Managed Objects for the Fourth Version of the Border Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss, J. Chu, Editor. July 1994.' RFC1724 'RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.' RFC1850 'OSPF Version 2 Management Information Base. F. Baker, R. Coltun. November 1995.' RFC2741 'Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.'  File: quagga.info, Node: How to get Quagga, Next: Mailing List, Prev: Supported RFCs, Up: Overview 1.5 How to get Quagga ===================== The official Quagga web-site is located at: and contains further information, as well as links to additional resources. Quagga (http://www.quagga.net/) is a fork of GNU Zebra, whose web-site is located at: .  File: quagga.info, Node: Mailing List, Next: Bug Reports, Prev: How to get Quagga, Up: Overview 1.6 Mailing List ================ There is a mailing list for discussions about Quagga. If you have any comments or suggestions to Quagga, please subscribe to: . The Quagga site has further information on the available mailing lists, see:  File: quagga.info, Node: Bug Reports, Prev: Mailing List, Up: Overview 1.7 Bug Reports =============== If you think you have found a bug, please send a bug report to: When you send a bug report, please be careful about the points below. * Please note what kind of OS you are using. If you use the IPv6 stack please note that as well. * Please show us the results of 'netstat -rn' and 'ifconfig -a'. Information from zebra's VTY command 'show ip route' will also be helpful. * Please send your configuration file with the report. If you specify arguments to the configure script please note that too. Bug reports are very important for us to improve the quality of Quagga. Quagga is still in the development stage, but please don't hesitate to send a bug report to .  File: quagga.info, Node: Installation, Next: Basic commands, Prev: Overview, Up: Top 2 Installation ************** There are three steps for installing the software: configuration, compilation, and installation. * Menu: * Configure the Software:: * Build the Software:: * Install the Software:: The easiest way to get Quagga running is to issue the following commands: % configure % make % make install  File: quagga.info, Node: Configure the Software, Next: Build the Software, Up: Installation 2.1 Configure the Software ========================== * Menu: * The Configure script and its options:: * Least-Privilege support:: * Linux notes::  File: quagga.info, Node: The Configure script and its options, Next: Least-Privilege support, Up: Configure the Software 2.1.1 The Configure script and its options ------------------------------------------ Quagga has an excellent configure script which automatically detects most host configurations. There are several additional configure options you can use to turn off IPv6 support, to disable the compilation of specific daemons, and to enable SNMP support. '--disable-ipv6' Turn off IPv6 related features and daemons. Quagga configure script automatically detects IPv6 stack. But sometimes you might want to disable IPv6 support of Quagga. '--disable-zebra' Do not build zebra daemon. '--disable-ripd' Do not build ripd. '--disable-ripngd' Do not build ripngd. '--disable-ospfd' Do not build ospfd. '--disable-ospf6d' Do not build ospf6d. '--disable-bgpd' Do not build bgpd. '--disable-bgp-announce' Make 'bgpd' which does not make bgp announcements at all. This feature is good for using 'bgpd' as a BGP announcement listener. '--enable-netlink' Force to enable GNU/Linux netlink interface. Quagga configure script detects netlink interface by checking a header file. When the header file does not match to the current running kernel, configure script will not turn on netlink support. '--enable-snmp' Enable SNMP support. By default, SNMP support is disabled. '--disable-opaque-lsa' Disable support for Opaque LSAs (RFC2370) in ospfd. '--disable-ospfapi' Disable support for OSPF-API, an API to interface directly with ospfd. OSPF-API is enabled if -enable-opaque-lsa is set. '--disable-ospfclient' Disable building of the example OSPF-API client. '--disable-ospf-te' Disable support for OSPF Traffic Engineering Extension (internet-draft) this requires support for Opaque LSAs. '--enable-multipath=ARG' Enable support for Equal Cost Multipath. ARG is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. '--disable-rtadv' Disable support IPV6 router advertisement in zebra. '--enable-gcc-rdynamic' Pass the '-rdynamic' option to the linker driver. This is in most cases neccessary for getting usable backtraces. This option defaults to on if the compiler is detected as gcc, but giving an explicit enable/disable is suggested. '--enable-backtrace' Controls backtrace support for the crash handlers. This is autodetected by default. Using the switch will enforce the requested behaviour, failing with an error if support is requested but not available. On BSD systems, this needs libexecinfo, while on glibc support for this is part of libc itself. You may specify any combination of the above options to the configure script. By default, the executables are placed in '/usr/local/sbin' and the configuration files in '/usr/local/etc'. The '/usr/local/' installation prefix and other directories may be changed using the following options to the configuration script. '--prefix=PREFIX' Install architecture-independent files in PREFIX [/usr/local]. '--sysconfdir=DIR' Look for configuration files in DIR [PREFIX/etc]. Note that sample configuration files will be installed here. '--localstatedir=DIR' Configure zebra to use DIR for local state files, such as pid files and unix sockets. % ./configure --disable-ipv6 This command will configure zebra and the routing daemons.  File: quagga.info, Node: Least-Privilege support, Next: Linux notes, Prev: The Configure script and its options, Up: Configure the Software 2.1.2 Least-Privilege support ----------------------------- Additionally, you may configure zebra to drop its elevated privileges shortly after startup and switch to another user. The configure script will automatically try to configure this support. There are three configure options to control the behaviour of Quagga daemons. '--enable-user=USER' Switch to user ARG shortly after startup, and run as user ARG in normal operation. '--enable-group=GROUP' Switch real and effective group to GROUP shortly after startup. '--enable-vty-group=GROUP' Create Unix Vty sockets (for use with vtysh) with group owndership set to GROUP. This allows one to create a seperate group which is restricted to accessing only the Vty sockets, hence allowing one to delegate this group to individual users, or to run vtysh setgid to this group. The default user and group which will be configured is 'quagga' if no user or group is specified. Note that this user or group requires write access to the local state directory (see -localstatedir) and requires at least read access, and write access if you wish to allow daemons to write out their configuration, to the configuration directory (see -sysconfdir). On systems which have the 'libcap' capabilities manipulation library (currently only linux), the quagga system will retain only minimal capabilities required, further it will only raise these capabilities for brief periods. On systems without libcap, quagga will run as the user specified and only raise its uid back to uid 0 for brief periods.  File: quagga.info, Node: Linux notes, Prev: Least-Privilege support, Up: Configure the Software 2.1.3 Linux Notes ----------------- There are several options available only to GNU/Linux systems: (1). If you use GNU/Linux, make sure that the current kernel configuration is what you want. Quagga will run with any kernel configuration but some recommendations do exist. CONFIG_NETLINK Kernel/User netlink socket. This is a brand new feature which enables an advanced interface between the Linux kernel and zebra (*note Kernel Interface::). CONFIG_RTNETLINK Routing messages. This makes it possible to receive netlink routing messages. If you specify this option, 'zebra' can detect routing information updates directly from the kernel (*note Kernel Interface::). CONFIG_IP_MULTICAST IP: multicasting. This option should be specified when you use 'ripd' (*note RIP::) or 'ospfd' (*note OSPFv2::) because these protocols use multicast. IPv6 support has been added in GNU/Linux kernel version 2.2. If you try to use the Quagga IPv6 feature on a GNU/Linux kernel, please make sure the following libraries have been installed. Please note that these libraries will not be needed when you uses GNU C library 2.1 or upper. 'inet6-apps' The 'inet6-apps' package includes basic IPv6 related libraries such as 'inet_ntop' and 'inet_pton'. Some basic IPv6 programs such as 'ping', 'ftp', and 'inetd' are also included. The 'inet-apps' can be found at . 'net-tools' The 'net-tools' package provides an IPv6 enabled interface and routing utility. It contains 'ifconfig', 'route', 'netstat', and other tools. 'net-tools' may be found at . ---------- Footnotes ---------- (1) GNU/Linux has very flexible kernel configuration features  File: quagga.info, Node: Build the Software, Next: Install the Software, Prev: Configure the Software, Up: Installation 2.2 Build the Software ====================== After configuring the software, you will need to compile it for your system. Simply issue the command 'make' in the root of the source directory and the software will be compiled. If you have *any* problems at this stage, be certain to send a bug report *Note Bug Reports::. % ./configure . . . ./configure output . . . % make  File: quagga.info, Node: Install the Software, Prev: Build the Software, Up: Installation 2.3 Install the Software ======================== Installing the software to your system consists of copying the compiled programs and supporting files to a standard location. After the installation process has completed, these files have been copied from your work directory to '/usr/local/bin', and '/usr/local/etc'. To install the Quagga suite, issue the following command at your shell prompt: 'make install'. % % make install % Quagga daemons have their own terminal interface or VTY. After installation, you have to setup each beast's port number to connect to them. Please add the following entries to '/etc/services'. zebrasrv 2600/tcp # zebra service zebra 2601/tcp # zebra vty ripd 2602/tcp # RIPd vty ripngd 2603/tcp # RIPngd vty ospfd 2604/tcp # OSPFd vty bgpd 2605/tcp # BGPd vty ospf6d 2606/tcp # OSPF6d vty ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty pimd 2611/tcp # PIMd vty If you use a FreeBSD newer than 2.2.8, the above entries are already added to '/etc/services' so there is no need to add it. If you specify a port number when starting the daemon, these entries may not be needed. You may need to make changes to the config files in '/etc/quagga/*.conf'. *Note Config Commands::.  File: quagga.info, Node: Basic commands, Next: Zebra, Prev: Installation, Up: Top 3 Basic commands **************** There are five routing daemons in use, and there is one manager daemon. These daemons may be located on separate machines from the manager daemon. Each of these daemons will listen on a particular port for incoming VTY connections. The routing daemons are: * 'ripd', 'ripngd', 'ospfd', 'ospf6d', 'bgpd' * 'zebra' The following sections discuss commands common to all the routing daemons. * Menu: * Config Commands:: Commands used in config files * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons  File: quagga.info, Node: Config Commands, Next: Terminal Mode Commands, Up: Basic commands 3.1 Config Commands =================== * Menu: * Basic Config Commands:: Some of the generic config commands * Sample Config File:: An example config file In a config file, you can write the debugging options, a vty's password, routing daemon configurations, a log file name, and so forth. This information forms the initial command set for a routing beast as it is starting. Config files are generally found in: '/etc/quagga/*.conf' Each of the daemons has its own config file. For example, zebra's default config file name is: '/etc/quagga/zebra.conf' The daemon name plus '.conf' is the default config file name. You can specify a config file using the '-f' or '--config-file' options when starting the daemon.  File: quagga.info, Node: Basic Config Commands, Next: Sample Config File, Up: Config Commands 3.1.1 Basic Config Commands --------------------------- -- Command: hostname HOSTNAME Set hostname of the router. -- Command: password PASSWORD Set password for vty interface. If there is no password, a vty won't accept connections. -- Command: enable password PASSWORD Set enable password. -- Command: log trap LEVEL -- Command: no log trap These commands are deprecated and are present only for historical compatibility. The log trap command sets the current logging level for all enabled logging destinations, and it sets the default for all future logging commands that do not specify a level. The normal default logging level is debugging. The 'no' form of the command resets the default level for future logging commands to debugging, but it does not change the logging level of existing logging destinations. -- Command: log stdout -- Command: log stdout LEVEL -- Command: no log stdout Enable logging output to stdout. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to stdout. The 'level' argument must have one of these values: emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages with severity 'errors'. -- Command: log file FILENAME -- Command: log file FILENAME LEVEL -- Command: no log file If you want to log into a file, please specify 'filename' as in this example: log file /var/log/quagga/bgpd.log informational If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to a file. Note: if you do not configure any file logging, and a daemon crashes due to a signal or an assertion failure, it will attempt to save the crash information in a file named /var/tmp/quagga..crashlog. For security reasons, this will not happen if the file exists already, so it is important to delete the file after reporting the crash information. -- Command: log syslog -- Command: log syslog LEVEL -- Command: no log syslog Enable logging output to syslog. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to syslog. -- Command: log monitor -- Command: log monitor LEVEL -- Command: no log monitor Enable logging output to vty terminals that have enabled logging using the 'terminal monitor' command. By default, monitor logging is enabled at the debugging level, but this command (or the deprecated 'log trap' command) can be used to change the monitor logging level. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated 'log trap' command) will be used. The 'no' form of the command disables logging to terminal monitors. -- Command: log facility FACILITY -- Command: no log facility This command changes the facility used in syslog messages. The default facility is 'daemon'. The 'no' form of the command resets the facility to the default 'daemon' facility. -- Command: log record-priority -- Command: no log record-priority To include the severity in all messages logged to a file, to stdout, or to a terminal monitor (i.e. anything except syslog), use the 'log record-priority' global configuration command. To disable this option, use the 'no' form of the command. By default, the severity level is not included in logged messages. Note: some versions of syslogd (including Solaris) can be configured to include the facility and level in the messages emitted. -- Command: log timestamp precision <0-6> -- Command: no log timestamp precision This command sets the precision of log message timestamps to the given number of digits after the decimal point. Currently, the value must be in the range 0 to 6 (i.e. the maximum precision is microseconds). To restore the default behavior (1-second accuracy), use the 'no' form of the command, or set the precision explicitly to 0. log timestamp precision 3 In this example, the precision is set to provide timestamps with millisecond accuracy. -- Command: service password-encryption Encrypt password. -- Command: service advanced-vty Enable advanced mode VTY. -- Command: service terminal-length <0-512> Set system wide line configuration. This configuration command applies to all VTY interfaces. -- Command: line vty Enter vty configuration mode. -- Command: banner motd default Set default motd string. -- Command: no banner motd No motd banner string will be printed. -- Line Command: exec-timeout MINUTE -- Line Command: exec-timeout MINUTE SECOND Set VTY connection timeout value. When only one argument is specified it is used for timeout value in minutes. Optional second argument is used for timeout value in seconds. Default timeout value is 10 minutes. When timeout value is zero, it means no timeout. -- Line Command: no exec-timeout Do not perform timeout at all. This command is as same as 'exec-timeout 0 0'. -- Line Command: access-class ACCESS-LIST Restrict vty connections with an access list.  File: quagga.info, Node: Sample Config File, Prev: Basic Config Commands, Up: Config Commands 3.1.2 Sample Config File ------------------------ Below is a sample configuration file for the zebra daemon. ! ! Zebra configuration file ! hostname Router password zebra enable password zebra ! log stdout ! ! '!' and '#' are comment characters. If the first character of the word is one of the comment characters then from the rest of the line forward will be ignored as a comment. password zebra!password If a comment character is not the first character of the word, it's a normal character. So in the above example '!' will not be regarded as a comment and the password is set to 'zebra!password'.  File: quagga.info, Node: Terminal Mode Commands, Next: Common Invocation Options, Prev: Config Commands, Up: Basic commands 3.2 Terminal Mode Commands ========================== -- Command: write terminal Displays the current configuration to the vty interface. -- Command: write file Write current configuration to configuration file. -- Command: configure terminal Change to configuration mode. This command is the first step to configuration. -- Command: terminal length <0-512> Set terminal display length to <0-512>. If length is 0, no display control is performed. -- Command: who Show a list of currently connected vty sessions. -- Command: list List all available commands. -- Command: show version Show the current version of Quagga and its build host information. -- Command: show logging Shows the current configuration of the logging system. This includes the status of all logging destinations. -- Command: logmsg LEVEL MESSAGE Send a message to all logging destinations that are enabled for messages of the given severity.  File: quagga.info, Node: Common Invocation Options, Next: Virtual Terminal Interfaces, Prev: Terminal Mode Commands, Up: Basic commands 3.3 Common Invocation Options ============================= These options apply to all Quagga daemons. '-d' '--daemon' Runs in daemon mode. '-f FILE' '--config_file=FILE' Set configuration file name. '-h' '--help' Display this help and exit. '-i FILE' '--pid_file=FILE' Upon startup the process identifier of the daemon is written to a file, typically in '/var/run'. This file can be used by the init system to implement commands such as '.../init.d/zebra status', '.../init.d/zebra restart' or '.../init.d/zebra stop'. The file name is an run-time option rather than a configure-time option so that multiple routing daemons can be run simultaneously. This is useful when using Quagga to implement a routing looking glass. One machine can be used to collect differing routing views from differing points in the network. '-A ADDRESS' '--vty_addr=ADDRESS' Set the VTY local address to bind to. If set, the VTY socket will only be bound to this address. '-P PORT' '--vty_port=PORT' Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not be opened. '-u USER' '--vty_addr=USER' Set the user and group to run as. '-v' '--version' Print program version.  File: quagga.info, Node: Virtual Terminal Interfaces, Prev: Common Invocation Options, Up: Basic commands 3.4 Virtual Terminal Interfaces =============================== VTY - Virtual Terminal [aka TeletYpe] Interface is a command line interface (CLI) for user interaction with the routing daemon. * Menu: * VTY Overview:: Basics about VTYs * VTY Modes:: View, Enable, and Other VTY modes * VTY CLI Commands:: Commands for movement, edition, and management  File: quagga.info, Node: VTY Overview, Next: VTY Modes, Up: Virtual Terminal Interfaces 3.4.1 VTY Overview ------------------ VTY stands for Virtual TeletYpe interface. It means you can connect to the daemon via the telnet protocol. To enable a VTY interface, you have to setup a VTY password. If there is no VTY password, one cannot connect to the VTY interface at all. % telnet localhost 2601 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello, this is Quagga (version 0.99.24.1) Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. User Access Verification Password: XXXXX Router> ? enable Turn on privileged commands exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list show Show running system information who Display who is on a vty Router> enable Password: XXXXX Router# configure terminal Router(config)# interface eth0 Router(config-if)# ip address 10.0.0.1/8 Router(config-if)# ^Z Router# '?' is very useful for looking up commands.  File: quagga.info, Node: VTY Modes, Next: VTY CLI Commands, Prev: VTY Overview, Up: Virtual Terminal Interfaces 3.4.2 VTY Modes --------------- There are three basic VTY modes: * Menu: * VTY View Mode:: Mode for read-only interaction * VTY Enable Mode:: Mode for read-write interaction * VTY Other Modes:: Special modes (tftp, etc) There are commands that may be restricted to specific VTY modes.  File: quagga.info, Node: VTY View Mode, Next: VTY Enable Mode, Up: VTY Modes 3.4.2.1 VTY View Mode ..................... This mode is for read-only access to the CLI. One may exit the mode by leaving the system, or by entering 'enable' mode.  File: quagga.info, Node: VTY Enable Mode, Next: VTY Other Modes, Prev: VTY View Mode, Up: VTY Modes 3.4.2.2 VTY Enable Mode ....................... This mode is for read-write access to the CLI. One may exit the mode by leaving the system, or by escaping to view mode.  File: quagga.info, Node: VTY Other Modes, Prev: VTY Enable Mode, Up: VTY Modes 3.4.2.3 VTY Other Modes ....................... This page is for describing other modes.  File: quagga.info, Node: VTY CLI Commands, Prev: VTY Modes, Up: Virtual Terminal Interfaces 3.4.3 VTY CLI Commands ---------------------- Commands that you may use at the command-line are described in the following three subsubsections. * Menu: * CLI Movement Commands:: Commands for moving the cursor about * CLI Editing Commands:: Commands for changing text * CLI Advanced Commands:: Other commands, session management and so on  File: quagga.info, Node: CLI Movement Commands, Next: CLI Editing Commands, Up: VTY CLI Commands 3.4.3.1 CLI Movement Commands ............................. These commands are used for moving the CLI cursor. The character means press the Control Key. 'C-f' '' Move forward one character. 'C-b' '' Move backward one character. 'M-f' Move forward one word. 'M-b' Move backward one word. 'C-a' Move to the beginning of the line. 'C-e' Move to the end of the line.  File: quagga.info, Node: CLI Editing Commands, Next: CLI Advanced Commands, Prev: CLI Movement Commands, Up: VTY CLI Commands 3.4.3.2 CLI Editing Commands ............................ These commands are used for editing text on a line. The character means press the Control Key. 'C-h' '' Delete the character before point. 'C-d' Delete the character after point. 'M-d' Forward kill word. 'C-w' Backward kill word. 'C-k' Kill to the end of the line. 'C-u' Kill line from the beginning, erasing input. 'C-t' Transpose character.  File: quagga.info, Node: CLI Advanced Commands, Prev: CLI Editing Commands, Up: VTY CLI Commands 3.4.3.3 CLI Advanced Commands ............................. There are several additional CLI commands for command line completions, insta-help, and VTY session management. 'C-c' Interrupt current input and moves to the next line. 'C-z' End current configuration session and move to top node. 'C-n' '' Move down to next line in the history buffer. 'C-p' '' Move up to previous line in the history buffer. 'TAB' Use command line completion by typing . '?' You can use command line help by typing 'help' at the beginning of the line. Typing '?' at any point in the line will show possible completions.  File: quagga.info, Node: Zebra, Next: RIP, Prev: Basic commands, Up: Top 4 Zebra ******* 'zebra' is an IP routing manager. It provides kernel routing table updates, interface lookups, and redistribution of routes between different routing protocols. * Menu: * Invoking zebra:: Running the program * Interface Commands:: Commands for zebra interfaces * Static Route Commands:: Commands for adding static routes * Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY  File: quagga.info, Node: Invoking zebra, Next: Interface Commands, Up: Zebra 4.1 Invoking zebra ================== Besides the common invocation options (*note Common Invocation Options::), the 'zebra' specific invocation options are listed below. '-b' '--batch' Runs in batch mode. 'zebra' parses configuration file and terminates immediately. '-k' '--keep_kernel' When zebra starts up, don't delete old self inserted routes. '-r' '--retain' When program terminates, retain routes added by zebra.  File: quagga.info, Node: Interface Commands, Next: Static Route Commands, Prev: Invoking zebra, Up: Zebra 4.2 Interface Commands ====================== -- Command: interface IFNAME -- Interface Command: shutdown -- Interface Command: no shutdown Up or down the current interface. -- Interface Command: ip address ADDRESS/PREFIX -- Interface Command: ipv6 address ADDRESS/PREFIX -- Interface Command: no ip address ADDRESS/PREFIX -- Interface Command: no ipv6 address ADDRESS/PREFIX Set the IPv4 or IPv6 address/prefix for the interface. -- Interface Command: ip address ADDRESS/PREFIX secondary -- Interface Command: no ip address ADDRESS/PREFIX secondary Set the secondary flag for this address. This causes ospfd to not treat the address as a distinct subnet. -- Interface Command: description DESCRIPTION ... Set description for the interface. -- Interface Command: multicast -- Interface Command: no multicast Enable or disables multicast flag for the interface. -- Interface Command: bandwidth <1-10000000> -- Interface Command: no bandwidth <1-10000000> Set bandwidth value of the interface in kilobits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. -- Interface Command: link-detect -- Interface Command: no link-detect Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag.  File: quagga.info, Node: Static Route Commands, Next: Multicast RIB Commands, Prev: Interface Commands, Up: Zebra 4.3 Static Route Commands ========================= Static routing is a very fundamental feature of routing technology. It defines static prefix and gateway. -- Command: ip route NETWORK GATEWAY NETWORK is destination prefix with format of A.B.C.D/M. GATEWAY is gateway for the prefix. When GATEWAY is A.B.C.D format. It is taken as a IPv4 address gateway. Otherwise it is treated as an interface name. If the interface name is NULL0 then zebra installs a blackhole route. ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 ppp0 ip route 10.0.0.0/8 null0 First example defines 10.0.0.0/8 static route with gateway 10.0.0.2. Second one defines the same prefix but with gateway to interface ppp0. The third install a blackhole route. -- Command: ip route NETWORK NETMASK GATEWAY This is alternate version of above command. When NETWORK is A.B.C.D format, user must define NETMASK value with A.B.C.D format. GATEWAY is same option as above command ip route 10.0.0.0 255.255.255.0 10.0.0.2 ip route 10.0.0.0 255.255.255.0 ppp0 ip route 10.0.0.0 255.255.255.0 null0 These statements are equivalent to those in the previous example. -- Command: ip route NETWORK GATEWAY DISTANCE Installs the route with the specified distance. Multiple nexthop static route ip route 10.0.0.1/32 10.0.0.2 ip route 10.0.0.1/32 10.0.0.3 ip route 10.0.0.1/32 eth0 If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0 is reachable, then the last route is installed into the kernel. If zebra has been compiled with multipath support, and both 10.0.0.2 and 10.0.0.3 are reachable, zebra will install a multipath route via both nexthops, if the platform supports this. zebra> show ip route S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive via 10.0.0.3 inactive * is directly connected, eth0 ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 10.0.0.3 ip route 10.0.0.0/8 null0 255 This will install a multihop route via the specified next-hops if they are reachable, as well as a high-metric blackhole route, which can be useful to prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive 10.0.0.3 inactive Routing entry for 10.0.0.0/8 Known via "static", distance 255, metric 0 directly connected, Null0 -- Command: ipv6 route NETWORK GATEWAY -- Command: ipv6 route NETWORK GATEWAY DISTANCE These behave similarly to their ipv4 counterparts. -- Command: table TABLENO Select the primary kernel routing table to be used. This only works for kernels supporting multiple routing tables (like GNU/Linux 2.2.x and later). After setting TABLENO with this command, static routes defined after this are added to the specified table.  File: quagga.info, Node: Multicast RIB Commands, Next: zebra Route Filtering, Prev: Static Route Commands, Up: Zebra 4.4 Multicast RIB Commands ========================== The Multicast RIB provides a separate table of unicast destinations which is used for Multicast Reverse Path Forwarding decisions. It is used with a multicast source's IP address, hence contains not multicast group addresses but unicast addresses. This table is fully separate from the default unicast table. However, RPF lookup can include the unicast table. WARNING: RPF lookup results are non-responsive in this version of Quagga, i.e. multicast routing does not actively react to changes in underlying unicast topology! -- Command: ip multicast rpf-lookup-mode MODE -- Command: no ip multicast rpf-lookup-mode [MODE] MODE sets the method used to perform RPF lookups. Supported modes: 'urib-only' Performs the lookup on the Unicast RIB. The Multicast RIB is never used. 'mrib-only' Performs the lookup on the Multicast RIB. The Unicast RIB is never used. 'mrib-then-urib' Tries to perform the lookup on the Multicast RIB. If any route is found, that route is used. Otherwise, the Unicast RIB is tried. 'lower-distance' Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the lower administrative distance is used; if they're equal, the Multicast RIB takes precedence. 'longer-prefix' Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. The 'mrib-then-urib' setting is the default behavior if nothing is configured. If this is the desired behavior, it should be explicitly configured to make the configuration immune against possible changes in what the default behavior is. WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. -- Command: show ip rpf ADDR Performs a Multicast RPF lookup, as configured with 'ip multicast rpf-lookup-mode MODE'. ADDR specifies the multicast source address to look up. > show ip rpf 192.0.2.1 Routing entry for 192.0.2.0/24 using Unicast RIB Known via "kernel", distance 0, metric 0, best * 198.51.100.1, via eth0 Indicates that a multicast source lookup for 192.0.2.1 would use an Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. -- Command: show ip rpf Prints the entire Multicast RIB. Note that this is independent of the configured RPF lookup mode, the Multicast RIB may be printed yet not used at all. -- Command: ip mroute PREFIX NEXTHOP [DISTANCE] -- Command: no ip mroute PREFIX NEXTHOP [DISTANCE] Adds a static route entry to the Multicast RIB. This performs exactly as the 'ip route' command, except that it inserts the route in the Multicast RIB instead of the Unicast RIB.  File: quagga.info, Node: zebra Route Filtering, Next: zebra FIB push interface, Prev: Multicast RIB Commands, Up: Zebra 4.5 zebra Route Filtering ========================= Zebra supports 'prefix-list' and 'route-map' to match routes received from other quagga components. The 'permit'/'deny' facilities provided by these commands can be used to filter which routes zebra will install in the kernel. -- Command: ip protocol PROTOCOL route-map ROUTEMAP Apply a route-map filter to routes for the specified protocol. PROTOCOL can be any or one of system, kernel, connected, static, rip, ripng, ospf, ospf6, isis, bgp, hsls. -- Route Map: set src ADDRESS Within a route-map, set the preferred source address for matching routes when installing in the kernel. The following creates a prefix-list that matches all addresses, a route-map that sets the preferred source address, and applies the route-map to all rip routes. ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 match ip address prefix-list ANY set src 10.0.0.1 ip protocol rip route-map RM1  File: quagga.info, Node: zebra FIB push interface, Next: zebra Terminal Mode Commands, Prev: zebra Route Filtering, Up: Zebra 4.6 zebra FIB push interface ============================ Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Quagga routing suite. In Quagga, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and zebra computes the best route across protocols for each prefix. This latter information makes up the Forwarding Information Base (FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in the kernel to forward packets according to the routes computed by Quagga. The kernel FIB is updated in an OS-specific way. For example, the 'netlink' interface is used on Linux, and route sockets are used on FreeBSD. The FIB push interface aims to provide a cross-platform mechanism to support scenarios where the router has a forwarding path that is distinct from the kernel, commonly a hardware-based fast path. In these cases, the FIB needs to be maintained reliably in the fast path as well. We refer to the component that programs the forwarding plane (directly or indirectly) as the Forwarding Plane Manager or FPM. The FIB push interface comprises of a TCP connection between zebra and the FPM. The connection is initiated by zebra - that is, the FPM acts as the TCP server. The relevant zebra code kicks in when zebra is configured with the '--enable-fpm' flag. Zebra periodically attempts to connect to the well-known FPM port. Once the connection is up, zebra starts sending messages containing routes over the socket to the FPM. Zebra sends a complete copy of the forwarding table to the FPM, including routes that it may have picked up from the kernel. The existing interaction of zebra with the kernel remains unchanged - that is, the kernel continues to receive FIB updates as before. The format of the messages exchanged with the FPM is defined by the file 'fpm/fpm.h' in the quagga tree. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, the information in the second message is complete by itself, and replaces the information sent in the first message. If the connection to the FPM goes down for some reason, zebra sends the FPM a complete copy of the forwarding table(s) when it reconnects.  File: quagga.info, Node: zebra Terminal Mode Commands, Prev: zebra FIB push interface, Up: Zebra 4.7 zebra Terminal Mode Commands ================================ -- Command: show ip route Display current routes which zebra holds in its database. Router# show ip route Codes: K - kernel route, C - connected, S - static, R - RIP, B - BGP * - FIB route. K* 0.0.0.0/0 203.181.89.241 S 0.0.0.0/0 203.181.89.1 C* 127.0.0.0/8 lo C* 203.181.89.240/28 eth0 -- Command: show ipv6 route -- Command: show interface -- Command: show ip prefix-list [NAME] -- Command: show route-map [NAME] -- Command: show ip protocol -- Command: show ipforward Display whether the host's IP forwarding function is enabled or not. Almost any UNIX kernel can be configured with IP forwarding disabled. If so, the box can't work as a router. -- Command: show ipv6forward Display whether the host's IP v6 forwarding is enabled or not. -- Command: show zebra fpm stats Display statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. -- Command: clear zebra fpm stats Reset statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component.  File: quagga.info, Node: RIP, Next: RIPng, Prev: Zebra, Up: Top 5 RIP ***** RIP - Routing Information Protocol is widely deployed interior gateway protocol. RIP was developed in the 1970s at Xerox Labs as part of the XNS routing protocol. RIP is a "distance-vector" protocol and is based on the "Bellman-Ford" algorithms. As a distance-vector protocol, RIP router send updates to its neighbors periodically, thus allowing the convergence to a known topology. In each update, the distance to any given network will be broadcasted to its neighboring router. 'ripd' supports RIP version 2 as described in RFC2453 and RIP version 1 as described in RFC1058. * Menu: * Starting and Stopping ripd:: * RIP Configuration:: * RIP Version Control:: * How to Announce RIP route:: * Filtering RIP Routes:: * RIP Metric Manipulation:: * RIP distance:: * RIP route-map:: * RIP Authentication:: * RIP Timers:: * Show RIP Information:: * RIP Debug Commands::  File: quagga.info, Node: Starting and Stopping ripd, Next: RIP Configuration, Up: RIP 5.1 Starting and Stopping ripd ============================== The default configuration file name of 'ripd''s is 'ripd.conf'. When invocation 'ripd' searches directory /etc/quagga. If 'ripd.conf' is not there next search current directory. RIP uses UDP port 520 to send and receive RIP packets. So the user must have the capability to bind the port, generally this means that the user must have superuser privileges. RIP protocol requires interface information maintained by 'zebra' daemon. So running 'zebra' is mandatory to run 'ripd'. Thus minimum sequence for running RIP is like below: # zebra -d # ripd -d Please note that 'zebra' must be invoked before 'ripd'. To stop 'ripd'. Please use 'kill `cat /var/run/ripd.pid`'. Certain signals have special meaningss to 'ripd'. 'SIGHUP' Reload configuration file 'ripd.conf'. All configurations are reseted. All routes learned so far are cleared and removed from routing table. 'SIGUSR1' Rotate 'ripd' logfile. 'SIGINT' 'SIGTERM' 'ripd' sweeps all installed RIP routes then terminates properly. 'ripd' invocation options. Common options that can be specified (*note Common Invocation Options::). '-r' '--retain' When the program terminates, retain routes added by 'ripd'. * Menu: * RIP netmask::  File: quagga.info, Node: RIP netmask, Up: Starting and Stopping ripd 5.1.1 RIP netmask ----------------- The netmask features of 'ripd' support both version 1 and version 2 of RIP. Version 1 of RIP originally contained no netmask information. In RIP version 1, network classes were originally used to determine the size of the netmask. Class A networks use 8 bits of mask, Class B networks use 16 bits of masks, while Class C networks use 24 bits of mask. Today, the most widely used method of a network mask is assigned to the packet on the basis of the interface that received the packet. Version 2 of RIP supports a variable length subnet mask (VLSM). By extending the subnet mask, the mask can be divided and reused. Each subnet can be used for different purposes such as large to middle size LANs and WAN links. Quagga 'ripd' does not support the non-sequential netmasks that are included in RIP Version 2. In a case of similar information with the same prefix and metric, the old information will be suppressed. Ripd does not currently support equal cost multipath routing.  File: quagga.info, Node: RIP Configuration, Next: RIP Version Control, Prev: Starting and Stopping ripd, Up: RIP 5.2 RIP Configuration ===================== -- Command: router rip The 'router rip' command is necessary to enable RIP. To disable RIP, use the 'no router rip' command. RIP must be enabled before carrying out any of the RIP commands. -- Command: no router rip Disable RIP. -- RIP Command: network NETWORK -- RIP Command: no network NETWORK Set the RIP enable interface by NETWORK. The interfaces which have addresses matching with NETWORK are enabled. This group of commands either enables or disables RIP interfaces between certain numbers of a specified network address. For example, if the network for 10.0.0.0/24 is RIP enabled, this would result in all the addresses from 10.0.0.0 to 10.0.0.255 being enabled for RIP. The 'no network' command will disable RIP for the specified network. -- RIP Command: network IFNAME -- RIP Command: no network IFNAME Set a RIP enabled interface by IFNAME. Both the sending and receiving of RIP packets will be enabled on the port specified in the 'network ifname' command. The 'no network ifname' command will disable RIP on the specified interface. -- RIP Command: neighbor A.B.C.D -- RIP Command: no neighbor A.B.C.D Specify RIP neighbor. When a neighbor doesn't understand multicast, this command is used to specify neighbors. In some cases, not all routers will be able to understand multicasting, where packets are sent to a network or a group of addresses. In a situation where a neighbor cannot process multicast packets, it is necessary to establish a direct link between routers. The neighbor command allows the network administrator to specify a router as a RIP neighbor. The 'no neighbor a.b.c.d' command will disable the RIP neighbor. Below is very simple RIP configuration. Interface 'eth0' and interface which address match to '10.0.0.0/8' are RIP enabled. ! router rip network 10.0.0.0/8 network eth0 ! Passive interface -- RIP command: passive-interface (IFNAME|default) -- RIP command: no passive-interface IFNAME This command sets the specified interface to passive mode. On passive mode interface, all receiving packets are processed as normal and ripd does not send either multicast or unicast RIP packets except to RIP neighbors specified with 'neighbor' command. The interface may be specified as DEFAULT to make ripd default to passive on all interfaces. The default is to be passive on all interfaces. RIP split-horizon -- Interface command: ip split-horizon -- Interface command: no ip split-horizon Control split-horizon on the interface. Default is 'ip split-horizon'. If you don't perform split-horizon on the interface, please specify 'no ip split-horizon'.  File: quagga.info, Node: RIP Version Control, Next: How to Announce RIP route, Prev: RIP Configuration, Up: RIP 5.3 RIP Version Control ======================= RIP can be configured to send either Version 1 or Version 2 packets. The default is to send RIPv2 while accepting both RIPv1 and RIPv2 (and replying with packets of the appropriate version for REQUESTS / triggered updates). The version to receive and send can be specified globally, and further overriden on a per-interface basis if needs be for send and receive seperately (see below). It is important to note that RIPv1 can not be authenticated. Further, if RIPv1 is enabled then RIP will reply to REQUEST packets, sending the state of its RIP routing table to any remote routers that ask on demand. For a more detailed discussion on the security implications of RIPv1 see *note RIP Authentication::. -- RIP Command: version VERSION Set RIP version to accept for reads and send. VERSION can be either '1" or '2". Disabling RIPv1 by specifying version 2 is STRONGLY encouraged, *Note RIP Authentication::. This may become the default in a future release. Default: Send Version 2, and accept either version. -- RIP Command: no version Reset the global version setting back to the default. -- Interface command: ip rip send version VERSION VERSION can be '1', '2' or '1 2'. This interface command overrides the global rip version setting, and selects which version of RIP to send packets with, for this interface specifically. Choice of RIP Version 1, RIP Version 2, or both versions. In the latter case, where '1 2' is specified, packets will be both broadcast and multicast. Default: Send packets according to the global version (version 2) -- Interface command: ip rip receive version VERSION VERSION can be '1', '2' or '1 2'. This interface command overrides the global rip version setting, and selects which versions of RIP packets will be accepted on this interface. Choice of RIP Version 1, RIP Version 2, or both. Default: Accept packets according to the global setting (both 1 and 2).  File: quagga.info, Node: How to Announce RIP route, Next: Filtering RIP Routes, Prev: RIP Version Control, Up: RIP 5.4 How to Announce RIP route ============================= -- RIP command: redistribute kernel -- RIP command: redistribute kernel metric <0-16> -- RIP command: redistribute kernel route-map ROUTE-MAP -- RIP command: no redistribute kernel 'redistribute kernel' redistributes routing information from kernel route entries into the RIP tables. 'no redistribute kernel' disables the routes. -- RIP command: redistribute static -- RIP command: redistribute static metric <0-16> -- RIP command: redistribute static route-map ROUTE-MAP -- RIP command: no redistribute static 'redistribute static' redistributes routing information from static route entries into the RIP tables. 'no redistribute static' disables the routes. -- RIP command: redistribute connected -- RIP command: redistribute connected metric <0-16> -- RIP command: redistribute connected route-map ROUTE-MAP -- RIP command: no redistribute connected Redistribute connected routes into the RIP tables. 'no redistribute connected' disables the connected routes in the RIP tables. This command redistribute connected of the interface which RIP disabled. The connected route on RIP enabled interface is announced by default. -- RIP command: redistribute ospf -- RIP command: redistribute ospf metric <0-16> -- RIP command: redistribute ospf route-map ROUTE-MAP -- RIP command: no redistribute ospf 'redistribute ospf' redistributes routing information from ospf route entries into the RIP tables. 'no redistribute ospf' disables the routes. -- RIP command: redistribute bgp -- RIP command: redistribute bgp metric <0-16> -- RIP command: redistribute bgp route-map ROUTE-MAP -- RIP command: no redistribute bgp 'redistribute bgp' redistributes routing information from bgp route entries into the RIP tables. 'no redistribute bgp' disables the routes. If you want to specify RIP only static routes: -- RIP command: default-information originate -- RIP command: route A.B.C.D/M -- RIP command: no route A.B.C.D/M This command is specific to Quagga. The 'route' command makes a static route only inside RIP. This command should be used only by advanced users who are particularly knowledgeable about the RIP protocol. In most cases, we recommend creating a static route in Quagga and redistributing it in RIP using 'redistribute static'.  File: quagga.info, Node: Filtering RIP Routes, Next: RIP Metric Manipulation, Prev: How to Announce RIP route, Up: RIP 5.5 Filtering RIP Routes ======================== RIP routes can be filtered by a distribute-list. -- Command: distribute-list ACCESS_LIST DIRECT IFNAME You can apply access lists to the interface with a 'distribute-list' command. ACCESS_LIST is the access list name. DIRECT is 'in' or 'out'. If DIRECT is 'in' the access list is applied to input packets. The 'distribute-list' command can be used to filter the RIP path. 'distribute-list' can apply access-lists to a chosen interface. First, one should specify the access-list. Next, the name of the access-list is used in the distribute-list command. For example, in the following configuration 'eth0' will permit only the paths that match the route 10.0.0.0/8 ! router rip distribute-list private in eth0 ! access-list private permit 10 10.0.0.0/8 access-list private deny any ! 'distribute-list' can be applied to both incoming and outgoing data. -- Command: distribute-list prefix PREFIX_LIST (in|out) IFNAME You can apply prefix lists to the interface with a 'distribute-list' command. PREFIX_LIST is the prefix list name. Next is the direction of 'in' or 'out'. If DIRECT is 'in' the access list is applied to input packets.  File: quagga.info, Node: RIP Metric Manipulation, Next: RIP distance, Prev: Filtering RIP Routes, Up: RIP 5.6 RIP Metric Manipulation =========================== RIP metric is a value for distance for the network. Usually 'ripd' increment the metric when the network information is received. Redistributed routes' metric is set to 1. -- RIP command: default-metric <1-16> -- RIP command: no default-metric <1-16> This command modifies the default metric value for redistributed routes. The default value is 1. This command does not affect connected route even if it is redistributed by 'redistribute connected'. To modify connected route's metric value, please use 'redistribute connected metric' or 'route-map'. 'offset-list' also affects connected routes. -- RIP command: offset-list ACCESS-LIST (in|out) -- RIP command: offset-list ACCESS-LIST (in|out) IFNAME  File: quagga.info, Node: RIP distance, Next: RIP route-map, Prev: RIP Metric Manipulation, Up: RIP 5.7 RIP distance ================ Distance value is used in zebra daemon. Default RIP distance is 120. -- RIP command: distance <1-255> -- RIP command: no distance <1-255> Set default RIP distance to specified value. -- RIP command: distance <1-255> A.B.C.D/M -- RIP command: no distance <1-255> A.B.C.D/M Set default RIP distance to specified value when the route's source IP address matches the specified prefix. -- RIP command: distance <1-255> A.B.C.D/M ACCESS-LIST -- RIP command: no distance <1-255> A.B.C.D/M ACCESS-LIST Set default RIP distance to specified value when the route's source IP address matches the specified prefix and the specified access-list.  File: quagga.info, Node: RIP route-map, Next: RIP Authentication, Prev: RIP distance, Up: RIP 5.8 RIP route-map ================= Usage of 'ripd''s route-map support. Optional argument route-map MAP_NAME can be added to each 'redistribute' statement. redistribute static [route-map MAP_NAME] redistribute connected [route-map MAP_NAME] ..... Cisco applies route-map _before_ routes will exported to rip route table. In current Quagga's test implementation, 'ripd' applies route-map after routes are listed in the route table and before routes will be announced to an interface (something like output filter). I think it is not so clear, but it is draft and it may be changed at future. Route-map statement (*note Route Map::) is needed to use route-map functionality. -- Route Map: match interface WORD This command match to incoming interface. Notation of this match is different from Cisco. Cisco uses a list of interfaces - NAME1 NAME2 ... NAMEN. Ripd allows only one name (maybe will change in the future). Next - Cisco means interface which includes next-hop of routes (it is somewhat similar to "ip next-hop" statement). Ripd means interface where this route will be sent. This difference is because "next-hop" of same routes which sends to different interfaces must be different. Maybe it'd be better to made new matches - say "match interface-out NAME" or something like that. -- Route Map: match ip address WORD -- Route Map: match ip address prefix-list WORD Match if route destination is permitted by access-list. -- Route Map: match ip next-hop WORD -- Route Map: match ip next-hop prefix-list WORD Match if route next-hop (meaning next-hop listed in the rip route-table as displayed by "show ip rip") is permitted by access-list. -- Route Map: match metric <0-4294967295> This command match to the metric value of RIP updates. For other protocol compatibility metric range is shown as <0-4294967295>. But for RIP protocol only the value range <0-16> make sense. -- Route Map: set ip next-hop A.B.C.D This command set next hop value in RIPv2 protocol. This command does not affect RIPv1 because there is no next hop field in the packet. -- Route Map: set metric <0-4294967295> Set a metric for matched route when sending announcement. The metric value range is very large for compatibility with other protocols. For RIP, valid metric values are from 1 to 16.  File: quagga.info, Node: RIP Authentication, Next: RIP Timers, Prev: RIP route-map, Up: RIP 5.9 RIP Authentication ====================== RIPv2 allows packets to be authenticated via either an insecure plain text password, included with the packet, or via a more secure MD5 based HMAC (keyed-Hashing for Message AuthentiCation), RIPv1 can not be authenticated at all, thus when authentication is configured 'ripd' will discard routing updates received via RIPv1 packets. However, unless RIPv1 reception is disabled entirely, *Note RIP Version Control::, RIPv1 REQUEST packets which are received, which query the router for routing information, will still be honoured by 'ripd', and 'ripd' WILL reply to such packets. This allows 'ripd' to honour such REQUESTs (which sometimes is used by old equipment and very simple devices to bootstrap their default route), while still providing security for route updates which are received. In short: Enabling authentication prevents routes being updated by unauthenticated remote routers, but still can allow routes (I.e. the entire RIP routing table) to be queried remotely, potentially by anyone on the internet, via RIPv1. To prevent such unauthenticated querying of routes disable RIPv1, *Note RIP Version Control::. -- Interface command: ip rip authentication mode md5 -- Interface command: no ip rip authentication mode md5 Set the interface with RIPv2 MD5 authentication. -- Interface command: ip rip authentication mode text -- Interface command: no ip rip authentication mode text Set the interface with RIPv2 simple password authentication. -- Interface command: ip rip authentication string STRING -- Interface command: no ip rip authentication string STRING RIP version 2 has simple text authentication. This command sets authentication string. The string must be shorter than 16 characters. -- Interface command: ip rip authentication key-chain KEY-CHAIN -- Interface command: no ip rip authentication key-chain KEY-CHAIN Specifiy Keyed MD5 chain. ! key chain test key 1 key-string test ! interface eth1 ip rip authentication mode md5 ip rip authentication key-chain test !  File: quagga.info, Node: RIP Timers, Next: Show RIP Information, Prev: RIP Authentication, Up: RIP 5.10 RIP Timers =============== -- RIP command: timers basic UPDATE TIMEOUT GARBAGE RIP protocol has several timers. User can configure those timers' values by 'timers basic' command. The default settings for the timers are as follows: * The update timer is 30 seconds. Every update timer seconds, the RIP process is awakened to send an unsolicited Response message containing the complete routing table to all neighboring RIP routers. * The timeout timer is 180 seconds. Upon expiration of the timeout, the route is no longer valid; however, it is retained in the routing table for a short time so that neighbors can be notified that the route has been dropped. * The garbage collect timer is 120 seconds. Upon expiration of the garbage-collection timer, the route is finally removed from the routing table. The 'timers basic' command allows the the default values of the timers listed above to be changed. -- RIP command: no timers basic The 'no timers basic' command will reset the timers to the default settings listed above.  File: quagga.info, Node: Show RIP Information, Next: RIP Debug Commands, Prev: RIP Timers, Up: RIP 5.11 Show RIP Information ========================= To display RIP routes. -- Command: show ip rip Show RIP routes. The command displays all RIP routes. For routes that are received through RIP, this command will display the time the packet was sent and the tag information. This command will also display this information for routes redistributed into RIP. -- Command: show ip rip status The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. ripd> show ip rip status Routing Protocol is "rip" Sending updates every 30 seconds with +/-50%, next due in 35 seconds Timeout after 180 seconds, garbage collect after 120 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 Redistributing: kernel connected Default version control: send version 2, receive version 2 Interface Send Recv Routing for Networks: eth0 eth1 1.1.1.1 203.181.89.241 Routing Information Sources: Gateway BadPackets BadRoutes Distance Last Update  File: quagga.info, Node: RIP Debug Commands, Prev: Show RIP Information, Up: RIP 5.12 RIP Debug Commands ======================= Debug for RIP protocol. -- Command: debug rip events Debug rip events. 'debug rip' will show RIP events. Sending and receiving packets, timers, and changes in interfaces are events shown with 'ripd'. -- Command: debug rip packet Debug rip packet. 'debug rip packet' will display detailed information about the RIP packets. The origin and port number of the packet as well as a packet dump is shown. -- Command: debug rip zebra Debug rip between zebra communication. This command will show the communication between 'ripd' and 'zebra'. The main information will include addition and deletion of paths to the kernel and the sending and receiving of interface information. -- Command: show debugging rip Display 'ripd''s debugging option. 'show debugging rip' will show all information currently set for ripd debug.  File: quagga.info, Node: RIPng, Next: OSPFv2, Prev: RIP, Up: Top 6 RIPng ******* 'ripngd' supports the RIPng protocol as described in RFC2080. It's an IPv6 reincarnation of the RIP protocol. * Menu: * Invoking ripngd:: * ripngd Configuration:: * ripngd Terminal Mode Commands:: * ripngd Filtering Commands::  File: quagga.info, Node: Invoking ripngd, Next: ripngd Configuration, Up: RIPng 6.1 Invoking ripngd =================== There are no 'ripngd' specific invocation options. Common options can be specified (*note Common Invocation Options::).  File: quagga.info, Node: ripngd Configuration, Next: ripngd Terminal Mode Commands, Prev: Invoking ripngd, Up: RIPng 6.2 ripngd Configuration ======================== Currently ripngd supports the following commands: -- Command: router ripng Enable RIPng. -- RIPng Command: flush_timer TIME Set flush timer. -- RIPng Command: network NETWORK Set RIPng enabled interface by NETWORK -- RIPng Command: network IFNAME Set RIPng enabled interface by IFNAME -- RIPng Command: route NETWORK Set RIPng static routing announcement of NETWORK. -- Command: router zebra This command is the default and does not appear in the configuration. With this statement, RIPng routes go to the 'zebra' daemon.  File: quagga.info, Node: ripngd Terminal Mode Commands, Next: ripngd Filtering Commands, Prev: ripngd Configuration, Up: RIPng 6.3 ripngd Terminal Mode Commands ================================= -- Command: show ip ripng -- Command: show debugging ripng -- Command: debug ripng events -- Command: debug ripng packet -- Command: debug ripng zebra  File: quagga.info, Node: ripngd Filtering Commands, Prev: ripngd Terminal Mode Commands, Up: RIPng 6.4 ripngd Filtering Commands ============================= -- Command: distribute-list ACCESS_LIST (in|out) IFNAME You can apply an access-list to the interface using the 'distribute-list' command. ACCESS_LIST is an access-list name. DIRECT is 'in' or 'out'. If DIRECT is 'in', the access-list is applied only to incoming packets. distribute-list local-only out sit1  File: quagga.info, Node: OSPFv2, Next: OSPFv3, Prev: RIPng, Up: Top 7 OSPFv2 ******** OSPF (Open Shortest Path First) version 2 is a routing protocol which is described in 'RFC2328, OSPF Version 2'. OSPF is an IGP (Interior Gateway Protocol). Compared with RIP, OSPF can provide scalable network support and faster convergence times. OSPF is widely used in large networks such as ISP (Internet Service Provider) backbone and enterprise networks. * Menu: * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Debugging OSPF:: * OSPF Configuration Examples::  File: quagga.info, Node: Configuring ospfd, Next: OSPF router, Up: OSPFv2 7.1 Configuring ospfd ===================== There are no 'ospfd' specific options. Common options can be specified (*note Common Invocation Options::) to 'ospfd'. 'ospfd' needs to acquire interface information from 'zebra' in order to function. Therefore 'zebra' must be running before invoking 'ospfd'. Also, if 'zebra' is restarted then 'ospfd' must be too. Like other daemons, 'ospfd' configuration is done in OSPF specific configuration file 'ospfd.conf'.  File: quagga.info, Node: OSPF router, Next: OSPF area, Prev: Configuring ospfd, Up: OSPFv2 7.2 OSPF router =============== To start OSPF process you have to specify the OSPF router. As of this writing, 'ospfd' does not support multiple OSPF processes. -- Command: router ospf -- Command: no router ospf Enable or disable the OSPF process. 'ospfd' does not yet support multiple OSPF processes. So you can not specify an OSPF process number. -- OSPF Command: ospf router-id A.B.C.D -- OSPF Command: no ospf router-id This sets the router-ID of the OSPF process. The router-ID may be an IP address of the router, but need not be - it can be any arbitrary 32bit number. However it MUST be unique within the entire OSPF domain to the OSPF speaker - bad things will happen if multiple OSPF speakers are configured with the same router-ID! If one is not specified then 'ospfd' will obtain a router-ID automatically from 'zebra'. -- OSPF Command: ospf abr-type TYPE -- OSPF Command: no ospf abr-type TYPE TYPE can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types are equivalent. The OSPF standard for ABR behaviour does not allow an ABR to consider routes through non-backbone areas when its links to the backbone are down, even when there are other ABRs in attached non-backbone areas which still can reach the backbone - this restriction exists primarily to ensure routing-loops are avoided. With the "Cisco" or "IBM" ABR type, the default in this release of Quagga, this restriction is lifted, allowing an ABR to consider summaries learnt from other ABRs through non-backbone areas, and hence route via non-backbone areas as a last resort when, and only when, backbone links are down. Note that areas with fully-adjacent virtual-links are considered to be "transit capable" and can always be used to route backbone traffic, and hence are unaffected by this setting (*note OSPF virtual-link::). More information regarding the behaviour controlled by this command can be found in 'RFC 3509, Alternative Implementations of OSPF Area Border Routers', and 'draft-ietf-ospf-shortcut-abr-02.txt'. Quote: "Though the definition of the ABR (Area Border Router) in the OSPF specification does not require a router with multiple attached areas to have a backbone connection, it is actually necessary to provide successful routing to the inter-area and external destinations. If this requirement is not met, all traffic destined for the areas not connected to such an ABR or out of the OSPF domain, is dropped. This document describes alternative ABR behaviors implemented in Cisco and IBM routers." -- OSPF Command: ospf rfc1583compatibility -- OSPF Command: no ospf rfc1583compatibility 'RFC2328', the sucessor to 'RFC1583', suggests according to section G.2 (changes) in section 16.4 a change to the path preference algorithm that prevents possible routing loops that were possible in the old version of OSPFv2. More specifically it demands that inter-area paths and intra-area backbone path are now of equal preference but still both preferred to external paths. This command should NOT be set normally. -- OSPF Command: log-adjacency-changes [detail] -- OSPF Command: no log-adjacency-changes [detail] Configures ospfd to log changes in adjacency. With the optional detail argument, all changes in adjacency status are shown. Without detail, only changes to full or regressions are shown. -- OSPF Command: passive-interface INTERFACE -- OSPF Command: no passive-interface INTERFACE Do not speak OSPF interface on the given interface, but do advertise the interface as a stub link in the router-LSA (Link State Advertisement) for this router. This allows one to advertise addresses on such connected interfaces without having to originate AS-External/Type-5 LSAs (which have global flooding scope) - as would occur if connected addresses were redistributed into OSPF (*note Redistribute routes to OSPF::). This is the only way to advertise non-OSPF links into stub areas. -- OSPF Command: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME -- OSPF Command: no timers throttle spf This command sets the initial DELAY, the INITIAL-HOLDTIME and the MAXIMUM-HOLDTIME between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The DELAY specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the INITIAL-HOLDTIME configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by INITIAL-HOLDTIME, bounded by the MAXIMUM-HOLDTIME configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the INITIAL-HOLDTIME. The current holdtime can be viewed with *note show ip ospf::, where it is expressed as a multiplier of the INITIAL-HOLDTIME. router ospf timers throttle spf 200 400 10000 In this example, the DELAY is set to 200ms, the INITIAL HOLDTIME is set to 400ms and the MAXIMUM HOLDTIME to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. This command supercedes the 'timers spf' command in previous Quagga releases. -- OSPF Command: max-metric router-lsa [on-startup|on-shutdown] <5-86400> -- OSPF Command: max-metric router-lsa administrative -- OSPF Command: no max-metric router-lsa [on-startup|on-shutdown|administrative] This enables 'RFC3137, OSPF Stub Router Advertisement' support, where the OSPF process describes its transit links in its router-LSA as having infinite distance so that other routers will avoid calculating transit paths through the router while still being able to reach networks through the router. This support may be enabled administratively (and indefinitely) or conditionally. Conditional enabling of max-metric router-lsas can be for a period of seconds after startup and/or for a period of seconds prior to shutdown. Enabling this for a period after startup allows OSPF to converge fully first without affecting any existing routes used by other routers, while still allowing any connected stub links and/or redistributed routes to be reachable. Enabling this for a period of time in advance of shutdown allows the router to gracefully excuse itself from the OSPF domain. Enabling this feature administratively allows for administrative intervention for whatever reason, for an indefinite period of time. Note that if the configuration is written to file, this administrative form of the stub-router command will also be written to file. If 'ospfd' is restarted later, the command will then take effect until manually deconfigured. Configured state of this feature as well as current status, such as the number of second remaining till on-startup or on-shutdown ends, can be viewed with the *note show ip ospf:: command. -- OSPF Command: auto-cost reference-bandwidth <1-4294967> -- OSPF Command: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. -- OSPF Command: network A.B.C.D/M area A.B.C.D -- OSPF Command: network A.B.C.D/M area <0-4294967295> -- OSPF Command: no network A.B.C.D/M area A.B.C.D -- OSPF Command: no network A.B.C.D/M area <0-4294967295> This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf on this interface so router can provide network information to the other ospf routers via this interface. router ospf network 192.168.1.0/24 area 0.0.0.0 Prefix length in interface must be equal or bigger (ie. smaller network) than prefix length in network statement. For example statement above doesn't enable ospf on interface with address 192.168.1.1/23, but it does on interface with address 192.168.1.129/25. Note that the behavior when there is a peer address defined on an interface changed after release 0.99.7. Currently, if a peer prefix has been configured, then we test whether the prefix in the network command contains the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface.  File: quagga.info, Node: OSPF area, Next: OSPF interface, Prev: OSPF router, Up: OSPFv2 7.3 OSPF area ============= -- OSPF Command: area A.B.C.D range A.B.C.D/M -- OSPF Command: area <0-4294967295> range A.B.C.D/M -- OSPF Command: no area A.B.C.D range A.B.C.D/M -- OSPF Command: no area <0-4294967295> range A.B.C.D/M Summarize intra area paths from specified area into one Type-3 summary-LSA announced to other areas. This command can be used only in ABR and ONLY router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS. Summarizing Type-7 AS-external-LSAs isn't supported yet by Quagga. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router or network LSA) from this range. -- OSPF Command: area A.B.C.D range IPV4_PREFIX not-advertise -- OSPF Command: no area A.B.C.D range IPV4_PREFIX not-advertise Instead of summarizing intra area paths filter them - ie. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX -- OSPF Command: no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX Substitute summarized prefix with another prefix. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8 One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or network-LSA) from range 10.0.0.0/8. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D virtual-link A.B.C.D -- OSPF Command: area <0-4294967295> virtual-link A.B.C.D -- OSPF Command: no area A.B.C.D virtual-link A.B.C.D -- OSPF Command: no area <0-4294967295> virtual-link A.B.C.D -- OSPF Command: area A.B.C.D shortcut -- OSPF Command: area <0-4294967295> shortcut -- OSPF Command: no area A.B.C.D shortcut -- OSPF Command: no area <0-4294967295> shortcut Configure the area as Shortcut capable. See 'RFC3509'. This requires that the 'abr-type' be set to 'shortcut'. -- OSPF Command: area A.B.C.D stub -- OSPF Command: area <0-4294967295> stub -- OSPF Command: no area A.B.C.D stub -- OSPF Command: no area <0-4294967295> stub Configure the area to be a stub area. That is, an area where no router originates routes external to OSPF and hence an area where all external routes are via the ABR(s). Hence, ABRs for such an area do not need to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the area. They need only pass Network-Summary (type-3) LSAs into such an area, along with a default-route summary. -- OSPF Command: area A.B.C.D stub no-summary -- OSPF Command: area <0-4294967295> stub no-summary -- OSPF Command: no area A.B.C.D stub no-summary -- OSPF Command: no area <0-4294967295> stub no-summary Prevents an 'ospfd' ABR from injecting inter-area summaries into the specified stub area. -- OSPF Command: area A.B.C.D default-cost <0-16777215> -- OSPF Command: no area A.B.C.D default-cost <0-16777215> Set the cost of default-summary LSAs announced to stubby areas. -- OSPF Command: area A.B.C.D export-list NAME -- OSPF Command: area <0-4294967295> export-list NAME -- OSPF Command: no area A.B.C.D export-list NAME -- OSPF Command: no area <0-4294967295> export-list NAME Filter Type-3 summary-LSAs announced to other areas originated from intra- area paths from specified area. router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 export-list foo ! access-list foo permit 10.10.0.0/16 access-list foo deny any With example above any intra-area paths from area 0.0.0.10 and from range 10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16 or 10.128.30.16/30) aren't. This command is only relevant if the router is an ABR for the specified area. -- OSPF Command: area A.B.C.D import-list NAME -- OSPF Command: area <0-4294967295> import-list NAME -- OSPF Command: no area A.B.C.D import-list NAME -- OSPF Command: no area <0-4294967295> import-list NAME Same as export-list, but it applies to paths announced into specified area as Type-3 summary-LSAs. -- OSPF Command: area A.B.C.D filter-list prefix NAME in -- OSPF Command: area A.B.C.D filter-list prefix NAME out -- OSPF Command: area <0-4294967295> filter-list prefix NAME in -- OSPF Command: area <0-4294967295> filter-list prefix NAME out -- OSPF Command: no area A.B.C.D filter-list prefix NAME in -- OSPF Command: no area A.B.C.D filter-list prefix NAME out -- OSPF Command: no area <0-4294967295> filter-list prefix NAME in -- OSPF Command: no area <0-4294967295> filter-list prefix NAME out Filtering Type-3 summary-LSAs to/from area using prefix lists. This command makes sense in ABR only. -- OSPF Command: area A.B.C.D authentication -- OSPF Command: area <0-4294967295> authentication -- OSPF Command: no area A.B.C.D authentication -- OSPF Command: no area <0-4294967295> authentication Specify that simple password authentication should be used for the given area. -- OSPF Command: area A.B.C.D authentication message-digest -- OSPF Command: area <0-4294967295> authentication message-digest Specify that OSPF packets must be authenticated with MD5 HMACs within the given area. Keying material must also be configured on a per-interface basis (*note ip ospf message-digest-key::). MD5 authentication may also be configured on a per-interface basis (*note ip ospf authentication message-digest::). Such per-interface settings will override any per-area authentication setting.  File: quagga.info, Node: OSPF interface, Next: Redistribute routes to OSPF, Prev: OSPF area, Up: OSPFv2 7.4 OSPF interface ================== -- Interface Command: ip ospf authentication-key AUTH_KEY -- Interface Command: no ip ospf authentication-key Set OSPF authentication key to a simple password. After setting AUTH_KEY, all OSPF packets are authenticated. AUTH_KEY has length up to 8 chars. Simple text password authentication is insecure and deprecated in favour of MD5 HMAC authentication (*note ip ospf authentication message-digest::). -- Interface Command: ip ospf authentication message-digest Specify that MD5 HMAC authentication must be used on this interface. MD5 keying material must also be configured (*note ip ospf message-digest-key::). Overrides any authentication enabled on a per-area basis (*note area authentication message-digest::). Note that OSPF MD5 authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestabish adjacencies with its neighbours after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (eg battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volative storage and restored at boot if MD5 authentication is to be expected to work reliably. -- Interface Command: ip ospf message-digest-key KEYID md5 KEY -- Interface Command: no ip ospf message-digest-key Set OSPF authentication key to a cryptographic password. The cryptographic algorithm is MD5. KEYID identifies secret key used to create the message digest. This ID is part of the protocol and must be consistent across routers on a link. KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. -- Interface Command: ip ospf cost <1-65535> -- Interface Command: no ip ospf cost Set link cost for the specified interface. The cost value is set to router-LSA's metric field and used for SPF calculation. -- Interface Command: ip ospf dead-interval <1-65535> -- Interface Command: ip ospf dead-interval minimal hello-multiplier <2-20> -- Interface Command: no ip ospf dead-interval Set number of seconds for RouterDeadInterval timer value used for Wait Timer and Inactivity Timer. This value must be the same for all routers attached to a common network. The default value is 40 seconds. If 'minimal' is specified instead, then the dead-interval is set to 1 second and one must specify a hello-multiplier. The hello-multiplier specifies how many Hellos to send per second, from 2 (every 500ms) to 20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form is specified, then the hello-interval advertised in Hello packets is set to 0 and the hello-interval on received Hello packets is not checked, thus the hello-multiplier need NOT be the same across multiple routers on a common link. -- Interface Command: ip ospf hello-interval <1-65535> -- Interface Command: no ip ospf hello-interval Set number of seconds for HelloInterval timer value. Setting this value, Hello packet will be sent every timer value seconds on the specified interface. This value must be the same for all routers attached to a common network. The default value is 10 seconds. This command has no effect if *note ip ospf dead-interval minimal:: is also specified for the interface. -- Interface Command: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) -- Interface Command: no ip ospf network Set explicitly network type for specifed interface. -- Interface Command: ip ospf priority <0-255> -- Interface Command: no ip ospf priority Set RouterPriority integer value. The router with the highest priority will be more eligible to become Designated Router. Setting the value to 0, makes the router ineligible to become Designated Router. The default value is 1. -- Interface Command: ip ospf retransmit-interval <1-65535> -- Interface Command: no ip ospf retransmit interval Set number of seconds for RxmtInterval timer value. This value is used when retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -- Interface Command: ip ospf transmit-delay -- Interface Command: no ip ospf transmit-delay Set number of seconds for InfTransDelay value. LSAs' age should be incremented by this value when transmitting. The default value is 1 seconds.  File: quagga.info, Node: Redistribute routes to OSPF, Next: Showing OSPF information, Prev: OSPF interface, Up: OSPFv2 7.5 Redistribute routes to OSPF =============================== -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> -- OSPF Command: redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD -- OSPF Command: no redistribute (kernel|connected|static|rip|bgp) Redistribute routes of the specified protocol or kind into OSPF, with the metric type and metric set if specified, filtering the routes using the given route-map if specified. Redistributed routes may also be filtered with distribute-lists, see *note ospf distribute-list::. Redistributed routes are distributed as into OSPF as Type-5 External LSAs into links to areas that accept external routes, Type-7 External LSAs for NSSA areas and are not redistributed at all into Stub areas, where external routes are not permitted. Note that for connected routes, one may instead use "passive-interface", see *note OSPF passive-interface::. -- OSPF Command: default-information originate -- OSPF Command: default-information originate metric <0-16777214> -- OSPF Command: default-information originate metric <0-16777214> metric-type (1|2) -- OSPF Command: default-information originate metric <0-16777214> metric-type (1|2) route-map WORD -- OSPF Command: default-information originate always -- OSPF Command: default-information originate always metric <0-16777214> -- OSPF Command: default-information originate always metric <0-16777214> metric-type (1|2) -- OSPF Command: default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD -- OSPF Command: no default-information originate Originate an AS-External (type-5) LSA describing a default route into all external-routing capable areas, of the specified metric and metric type. If the 'always' keyword is given then the default is always advertised, even when there is no default present in the routing table. -- OSPF Command: distribute-list NAME out (kernel|connected|static|rip|ospf -- OSPF Command: no distribute-list NAME out (kernel|connected|static|rip|ospf Apply the access-list filter, NAME, to redistributed routes of the given type before allowing the routes to redistributed into OSPF (*note OSPF redistribute::). -- OSPF Command: default-metric <0-16777214> -- OSPF Command: no default-metric -- OSPF Command: distance <1-255> -- OSPF Command: no distance <1-255> -- OSPF Command: distance ospf (intra-area|inter-area|external) <1-255> -- OSPF Command: no distance ospf  File: quagga.info, Node: Showing OSPF information, Next: Debugging OSPF, Prev: Redistribute routes to OSPF, Up: OSPFv2 7.6 Showing OSPF information ============================ -- Command: show ip ospf Show information on a variety of general OSPF and area state and configuration information. -- Command: show ip ospf interface [INTERFACE] Show state and configuration of OSPF the specified interface, or all interfaces if no interface is given. -- Command: show ip ospf neighbor -- Command: show ip ospf neighbor INTERFACE -- Command: show ip ospf neighbor detail -- Command: show ip ospf neighbor INTERFACE detail -- Command: show ip ospf database -- Command: show ip ospf database (asbr-summary|external|network|router|summary) -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER -- Command: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER -- Command: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate -- Command: show ip ospf database (asbr-summary|external|network|router|summary) self-originate -- Command: show ip ospf database max-age -- Command: show ip ospf database self-originate -- Command: show ip ospf route Show the OSPF routing table, as determined by the most recent SPF calculation.  File: quagga.info, Node: Debugging OSPF, Next: OSPF Configuration Examples, Prev: Showing OSPF information, Up: OSPFv2 7.7 Debugging OSPF ================== -- Command: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] -- Command: no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail] -- Command: debug ospf ism -- Command: debug ospf ism (status|events|timers) -- Command: no debug ospf ism -- Command: no debug ospf ism (status|events|timers) -- Command: debug ospf nsm -- Command: debug ospf nsm (status|events|timers) -- Command: no debug ospf nsm -- Command: no debug ospf nsm (status|events|timers) -- Command: debug ospf lsa -- Command: debug ospf lsa (generate|flooding|refresh) -- Command: no debug ospf lsa -- Command: no debug ospf lsa (generate|flooding|refresh) -- Command: debug ospf zebra -- Command: debug ospf zebra (interface|redistribute) -- Command: no debug ospf zebra -- Command: no debug ospf zebra (interface|redistribute) -- Command: show debugging ospf  File: quagga.info, Node: OSPF Configuration Examples, Prev: Debugging OSPF, Up: OSPFv2 7.8 OSPF Configuration Examples =============================== A simple example, with MD5 authentication enabled: ! interface bge0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! router ospf network 192.168.0.0/16 area 0.0.0.1 area 0.0.0.1 authentication message-digest An ABR router, with MD5 authentication and performing summarisation of networks between the areas: ! password ABCDEF log file /var/log/quagga/ospfd.log service advanced-vty ! interface eth0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! interface ppp0 ! interface br0 ip ospf authentication message-digest ip ospf message-digest-key 2 md5 XYZ12345 ! router ospf ospf router-id 192.168.0.1 redistribute connected passive interface ppp0 network 192.168.0.0/24 area 0.0.0.0 network 10.0.0.0/16 area 0.0.0.0 network 192.168.1.0/24 area 0.0.0.1 area 0.0.0.0 authentication message-digest area 0.0.0.0 range 10.0.0.0/16 area 0.0.0.0 range 192.168.0.0/24 area 0.0.0.1 authentication message-digest area 0.0.0.1 range 10.2.0.0/16 !  File: quagga.info, Node: OSPFv3, Next: Babel, Prev: OSPFv2, Up: Top 8 OSPFv3 ******** 'ospf6d' is a daemon support OSPF version 3 for IPv6 network. OSPF for IPv6 is described in RFC2740. * Menu: * OSPF6 router:: * OSPF6 area:: * OSPF6 interface:: * Redistribute routes to OSPF6:: * Showing OSPF6 information:: * OSPF6 Configuration Examples::  File: quagga.info, Node: OSPF6 router, Next: OSPF6 area, Up: OSPFv3 8.1 OSPF6 router ================ -- Command: router ospf6 -- OSPF6 Command: router-id A.B.C.D Set router's Router-ID. -- OSPF6 Command: interface IFNAME area AREA Bind interface to specified area, and start sending OSPF packets. AREA can be specified as 0. -- OSPF6 Command: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME -- OSPF6 Command: no timers throttle spf This command sets the initial DELAY, the INITIAL-HOLDTIME and the MAXIMUM-HOLDTIME between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The DELAY specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the INITIAL-HOLDTIME configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by INITIAL-HOLDTIME, bounded by the MAXIMUM-HOLDTIME configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the INITIAL-HOLDTIME. router ospf6 timers throttle spf 200 400 10000 In this example, the DELAY is set to 200ms, the INITIAL HOLDTIME is set to 400ms and the MAXIMUM HOLDTIME to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. -- OSPF6 Command: auto-cost reference-bandwidth COST -- OSPF6 Command: no auto-cost reference-bandwidth This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain.  File: quagga.info, Node: OSPF6 area, Next: OSPF6 interface, Prev: OSPF6 router, Up: OSPFv3 8.2 OSPF6 area ============== Area support for OSPFv3 is not yet implemented.  File: quagga.info, Node: OSPF6 interface, Next: Redistribute routes to OSPF6, Prev: OSPF6 area, Up: OSPFv3 8.3 OSPF6 interface =================== -- Interface Command: ipv6 ospf6 cost COST Sets interface's output cost. Default value depends on the interface bandwidth and on the auto-cost reference bandwidth. -- Interface Command: ipv6 ospf6 hello-interval HELLOINTERVAL Sets interface's Hello Interval. Default 40 -- Interface Command: ipv6 ospf6 dead-interval DEADINTERVAL Sets interface's Router Dead Interval. Default value is 40. -- Interface Command: ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL Sets interface's Rxmt Interval. Default value is 5. -- Interface Command: ipv6 ospf6 priority PRIORITY Sets interface's Router Priority. Default value is 1. -- Interface Command: ipv6 ospf6 transmit-delay TRANSMITDELAY Sets interface's Inf-Trans-Delay. Default value is 1. -- Interface Command: ipv6 ospf6 network (broadcast|point-to-point) Set explicitly network type for specifed interface.  File: quagga.info, Node: Redistribute routes to OSPF6, Next: Showing OSPF6 information, Prev: OSPF6 interface, Up: OSPFv3 8.4 Redistribute routes to OSPF6 ================================ -- OSPF6 Command: redistribute static -- OSPF6 Command: redistribute connected -- OSPF6 Command: redistribute ripng  File: quagga.info, Node: Showing OSPF6 information, Next: OSPF6 Configuration Examples, Prev: Redistribute routes to OSPF6, Up: OSPFv3 8.5 Showing OSPF6 information ============================= -- Command: show ipv6 ospf6 [INSTANCE_ID] INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF instance ID, simply type "show ipv6 ospf6 ". -- Command: show ipv6 ospf6 database This command shows LSA database summary. You can specify the type of LSA. -- Command: show ipv6 ospf6 interface To see OSPF interface configuration like costs. -- Command: show ipv6 ospf6 neighbor Shows state and chosen (Backup) DR of neighbor. -- Command: show ipv6 ospf6 request-list A.B.C.D Shows requestlist of neighbor. -- Command: show ipv6 route ospf6 This command shows internal routing table.  File: quagga.info, Node: OSPF6 Configuration Examples, Prev: Showing OSPF6 information, Up: OSPFv3 8.6 OSPF6 Configuration Examples ================================ Example of ospf6d configured on one interface and area: interface eth0 ipv6 ospf6 instance-id 0 ! router ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 !  File: quagga.info, Node: Babel, Next: BGP, Prev: OSPFv3, Up: Top 9 Babel ******* Babel is an interior gateway protocol that is suitable both for wired networks and for wireless mesh networks. Babel has been described as "RIP on speed" -- it is based on the same principles as RIP, but includes a number of refinements that make it react much faster to topology changes without ever counting to infinity, and allow it to perform reliable link quality estimation on wireless links. Babel is a double-stack routing protocol, meaning that a single Babel instance is able to perform routing for both IPv4 and IPv6. Quagga implements Babel as described in RFC6126. * Menu: * Configuring babeld:: * Babel configuration:: * Babel redistribution:: * Show Babel information:: * Babel debugging commands::  File: quagga.info, Node: Configuring babeld, Next: Babel configuration, Prev: Babel, Up: Babel 9.1 Configuring babeld ====================== The 'babeld' daemon can be invoked with any of the common options (*note Common Invocation Options::). The 'zebra' daemon must be running before 'babeld' is invoked. Also, if 'zebra' is restarted then 'babeld' must be too. Configuration of 'babeld' is done in its configuration file 'babeld.conf'.  File: quagga.info, Node: Babel configuration, Next: Babel redistribution, Prev: Configuring babeld, Up: Babel 9.2 Babel configuration ======================= -- Command: router babel -- Command: no router babel Enable or disable Babel routing. -- Babel Command: network IFNAME -- Babel Command: no network IFNAME Enable or disable Babel on the given interface. -- Interface Command: babel wired -- Interface Command: babel wireless Specifies whether this interface is wireless, which disables a number of optimisations that are only correct on wired interfaces. Specifying 'wireless' (the default) is always correct, but may cause slower convergence and extra routing traffic. -- Interface Command: babel split-horizon -- Interface Command: no babel split-horizon Specifies whether to perform split-horizon on the interface. Specifying 'no babel split-horizon' (the default) is always correct, while 'babel split-horizon' is an optimisation that should only be used on symmetric and transitive (wired) networks. -- Interface Command: babel hello-interval <20-655340> Specifies the time in milliseconds between two scheduled hellos. On wired links, Babel notices a link failure within two hello intervals; on wireless links, the link quality value is reestimated at every hello interval. The default is 4000ms. -- Interface Command: babel update-interval <20-655340> Specifies the time in milliseconds between two scheduled updates. Since Babel makes extensive use of triggered updates, this can be set to fairly high values on links with little packet loss. The default is 20000ms. -- Babel Command: babel resend-delay <20-655340> Specifies the time in milliseconds after which an "important" request or update will be resent. The default is 2000ms. You probably don't want to tweak this value.  File: quagga.info, Node: Babel redistribution, Next: Show Babel information, Prev: Babel configuration, Up: Babel 9.3 Babel redistribution ======================== -- Babel command: redistribute KIND -- Babel command: no redistribute KIND Specify which kind of routes should be redistributed into Babel.  File: quagga.info, Node: Show Babel information, Next: Babel debugging commands, Prev: Babel redistribution, Up: Babel 9.4 Show Babel information ========================== -- Command: show babel database -- Command: show babel interface -- Command: show babel neighbour -- Command: show babel parameters These commands dump various parts of 'babeld''s internal state. They are mostly useful for troubleshooting.  File: quagga.info, Node: Babel debugging commands, Prev: Show Babel information, Up: Babel 9.5 Babel debugging commands ============================ -- Babel Command: debug babel KIND -- Babel Command: no debug babel KIND Enable or disable debugging messages of a given kind. KIND can be one of 'common', 'kernel', 'filter', 'timeout', 'interface', 'route' or 'all'. Note that if you have compiled with the NO_DEBUG flag, then these commands aren't available.  File: quagga.info, Node: BGP, Next: Configuring Quagga as a Route Server, Prev: Babel, Up: Top 10 BGP ****** BGP stands for a Border Gateway Protocol. The lastest BGP version is 4. It is referred as BGP-4. BGP-4 is one of the Exterior Gateway Protocols and de-fact standard of Inter Domain routing protocol. BGP-4 is described in 'RFC1771, A Border Gateway Protocol 4 (BGP-4)'. Many extensions have been added to 'RFC1771'. 'RFC2858, Multiprotocol Extensions for BGP-4' provides multiprotocol support to BGP-4. * Menu: * Starting BGP:: * BGP router:: * BGP network:: * BGP Peer:: * BGP Peer Group:: * BGP Address Family:: * Autonomous System:: * BGP Communities Attribute:: * BGP Extended Communities Attribute:: * Displaying BGP routes:: * Capability Negotiation:: * Route Reflector:: * Route Server:: * How to set up a 6-Bone connection:: * Dump BGP packets and table:: * BGP Configuration Examples::  File: quagga.info, Node: Starting BGP, Next: BGP router, Up: BGP 10.1 Starting BGP ================= Default configuration file of 'bgpd' is 'bgpd.conf'. 'bgpd' searches the current directory first then /etc/quagga/bgpd.conf. All of bgpd's command must be configured in 'bgpd.conf'. 'bgpd' specific invocation options are described below. Common options may also be specified (*note Common Invocation Options::). '-p PORT' '--bgp_port=PORT' Set the bgp protocol's port number. '-r' '--retain' When program terminates, retain BGP routes added by zebra.  File: quagga.info, Node: BGP router, Next: BGP network, Prev: Starting BGP, Up: BGP 10.2 BGP router =============== First of all you must configure BGP router with 'router bgp' command. To configure BGP router, you need AS number. AS number is an identification of autonomous system. BGP protocol uses the AS number for detecting whether the BGP connection is internal one or external one. -- Command: router bgp ASN Enable a BGP protocol process with the specified ASN. After this statement you can input any 'BGP Commands'. You can not create different BGP process under different ASN without specifying 'multiple-instance' (*note Multiple instance::). -- Command: no router bgp ASN Destroy a BGP protocol process with the specified ASN. -- BGP: bgp router-id A.B.C.D This command specifies the router-ID. If 'bgpd' connects to 'zebra' it gets interface and address information. In that case default router ID value is selected as the largest IP Address of the interfaces. When 'router zebra' is not enabled 'bgpd' can't get interface information so 'router-id' is set to 0.0.0.0. So please set router-id by hand. * Menu: * BGP distance:: * BGP decision process:: * BGP route flap dampening::  File: quagga.info, Node: BGP distance, Next: BGP decision process, Up: BGP router 10.2.1 BGP distance ------------------- -- BGP: distance bgp <1-255> <1-255> <1-255> This command change distance value of BGP. Each argument is distance value for external routes, internal routes and local routes. -- BGP: distance <1-255> A.B.C.D/M -- BGP: distance <1-255> A.B.C.D/M WORD This command set distance value to  File: quagga.info, Node: BGP decision process, Next: BGP route flap dampening, Prev: BGP distance, Up: BGP router 10.2.2 BGP decision process --------------------------- 1. Weight check 2. Local preference check. 3. Local route check. 4. AS path length check. 5. Origin check. 6. MED check. -- BGP: bgp bestpath as-path confed This command specifies that the length of confederation path sets and sequences should should be taken into account during the BGP best path decision process. -- BGP: bgp bestpath as-path multipath-relax This command specifies that BGP decision process should consider paths of equal AS_PATH length candidates for multipath computation. Without the knob, the entire AS_PATH must match for multipath computation.  File: quagga.info, Node: BGP route flap dampening, Prev: BGP decision process, Up: BGP router 10.2.3 BGP route flap dampening ------------------------------- -- BGP: bgp dampening <1-45> <1-20000> <1-20000> <1-255> This command enables BGP route-flap dampening and specifies dampening parameters. half-life Half-life time for the penalty reuse-threshold Value to start reusing a route suppress-threshold Value to start suppressing a route max-suppress Maximum duration to suppress a stable route The route-flap damping algorithm is compatible with 'RFC2439'. The use of this command is not recommended nowadays, see RIPE-378.  File: quagga.info, Node: BGP network, Next: BGP Peer, Prev: BGP router, Up: BGP 10.3 BGP network ================ * Menu: * BGP route:: * Route Aggregation:: * Redistribute to BGP::  File: quagga.info, Node: BGP route, Next: Route Aggregation, Up: BGP network 10.3.1 BGP route ---------------- -- BGP: network A.B.C.D/M This command adds the announcement network. router bgp 1 network 10.0.0.0/8 This configuration example says that network 10.0.0.0/8 will be announced to all neighbors. Some vendors' routers don't advertise routes if they aren't present in their IGP routing tables; 'bgpd' doesn't care about IGP routes when announcing its routes. -- BGP: no network A.B.C.D/M  File: quagga.info, Node: Route Aggregation, Next: Redistribute to BGP, Prev: BGP route, Up: BGP network 10.3.2 Route Aggregation ------------------------ -- BGP: aggregate-address A.B.C.D/M This command specifies an aggregate address. -- BGP: aggregate-address A.B.C.D/M as-set This command specifies an aggregate address. Resulting routes inlucde AS set. -- BGP: aggregate-address A.B.C.D/M summary-only This command specifies an aggregate address. Aggreated routes will not be announce. -- BGP: no aggregate-address A.B.C.D/M  File: quagga.info, Node: Redistribute to BGP, Prev: Route Aggregation, Up: BGP network 10.3.3 Redistribute to BGP -------------------------- -- BGP: redistribute kernel Redistribute kernel route to BGP process. -- BGP: redistribute static Redistribute static route to BGP process. -- BGP: redistribute connected Redistribute connected route to BGP process. -- BGP: redistribute rip Redistribute RIP route to BGP process. -- BGP: redistribute ospf Redistribute OSPF route to BGP process.  File: quagga.info, Node: BGP Peer, Next: BGP Peer Group, Prev: BGP network, Up: BGP 10.4 BGP Peer ============= * Menu: * Defining Peer:: * BGP Peer commands:: * Peer filtering::  File: quagga.info, Node: Defining Peer, Next: BGP Peer commands, Up: BGP Peer 10.4.1 Defining Peer -------------------- -- BGP: neighbor PEER remote-as ASN Creates a new neighbor whose remote-as is ASN. PEER can be an IPv4 address or an IPv6 address. router bgp 1 neighbor 10.0.0.1 remote-as 2 In this case my router, in AS-1, is trying to peer with AS-2 at 10.0.0.1. This command must be the first command used when configuring a neighbor. If the remote-as is not specified, 'bgpd' will complain like this: can't find neighbor 10.0.0.1  File: quagga.info, Node: BGP Peer commands, Next: Peer filtering, Prev: Defining Peer, Up: BGP Peer 10.4.2 BGP Peer commands ------------------------ In a 'router bgp' clause there are neighbor specific configurations required. -- BGP: neighbor PEER shutdown -- BGP: no neighbor PEER shutdown Shutdown the peer. We can delete the neighbor's configuration by 'no neighbor PEER remote-as AS-NUMBER' but all configuration of the neighbor will be deleted. When you want to preserve the configuration, but want to drop the BGP peer, use this syntax. -- BGP: neighbor PEER ebgp-multihop -- BGP: no neighbor PEER ebgp-multihop -- BGP: neighbor PEER description ... -- BGP: no neighbor PEER description ... Set description of the peer. -- BGP: neighbor PEER version VERSION Set up the neighbor's BGP version. VERSION can be 4, 4+ or 4-. BGP version 4 is the default value used for BGP peering. BGP version 4+ means that the neighbor supports Multiprotocol Extensions for BGP-4. BGP version 4- is similar but the neighbor speaks the old Internet-Draft revision 00's Multiprotocol Extensions for BGP-4. Some routing software is still using this version. -- BGP: neighbor PEER interface IFNAME -- BGP: no neighbor PEER interface IFNAME When you connect to a BGP peer over an IPv6 link-local address, you have to specify the IFNAME of the interface used for the connection. To specify IPv4 session addresses, see the 'neighbor PEER update-source' command below. This command is deprecated and may be removed in a future release. Its use should be avoided. -- BGP: neighbor PEER next-hop-self [all] -- BGP: no neighbor PEER next-hop-self [all] This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword 'all' is specified the modifiation is done also for routes learned via iBGP. -- BGP: neighbor PEER update-source -- BGP: no neighbor PEER update-source Specify the IPv4 source address to use for the BGP session to this neighbour, may be specified as either an IPv4 address directly or as an interface name (in which case the 'zebra' daemon MUST be running in order for 'bgpd' to be able to retrieve interface state). router bgp 64555 neighbor foo update-source 192.168.0.1 neighbor bar update-source lo0 -- BGP: neighbor PEER default-originate -- BGP: no neighbor PEER default-originate 'bgpd''s default is to not announce the default route (0.0.0.0/0) even it is in routing table. When you want to announce default routes to the peer, use this command. -- BGP: neighbor PEER port PORT -- BGP: neighbor PEER port PORT -- BGP: neighbor PEER send-community -- BGP: neighbor PEER send-community -- BGP: neighbor PEER weight WEIGHT -- BGP: no neighbor PEER weight WEIGHT This command specifies a default WEIGHT value for the neighbor's routes. -- BGP: neighbor PEER maximum-prefix NUMBER -- BGP: no neighbor PEER maximum-prefix NUMBER -- BGP: neighbor PEER local-as AS-NUMBER -- BGP: neighbor PEER local-as AS-NUMBER no-prepend -- BGP: neighbor PEER local-as AS-NUMBER no-prepend replace-as -- BGP: no neighbor PEER local-as Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to the received AS_PATH when receiving routing updates from the peer, and prepended to the outgoing AS_PATH (after the process local AS) when transmitting local routes to the peer. If the no-prepend attribute is specified, then the supplied local-as is not prepended to the received AS_PATH. If the replace-as attribute is specified, then only the supplied local-as is prepended to the AS_PATH when transmitting local-route updates to this peer. Note that replace-as can only be specified if no-prepend is. This command is only allowed for eBGP peers. -- BGP: neighbor PEER ttl-security hops NUMBER -- BGP: no neighbor PEER ttl-security hops NUMBER This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the specified number of hops away will be allowed to become neighbors. This command is mututally exclusive with 'ebgp-multihop'.  File: quagga.info, Node: Peer filtering, Prev: BGP Peer commands, Up: BGP Peer 10.4.3 Peer filtering --------------------- -- BGP: neighbor PEER distribute-list NAME [in|out] This command specifies a distribute-list for the peer. DIRECT is 'in' or 'out'. -- BGP command: neighbor PEER prefix-list NAME [in|out] -- BGP command: neighbor PEER filter-list NAME [in|out] -- BGP: neighbor PEER route-map NAME [in|out] Apply a route-map on the neighbor. DIRECT must be 'in' or 'out'.  File: quagga.info, Node: BGP Peer Group, Next: BGP Address Family, Prev: BGP Peer, Up: BGP 10.5 BGP Peer Group =================== -- BGP: neighbor WORD peer-group This command defines a new peer group. -- BGP: neighbor PEER peer-group WORD This command bind specific peer to peer group WORD.  File: quagga.info, Node: BGP Address Family, Next: Autonomous System, Prev: BGP Peer Group, Up: BGP 10.6 BGP Address Family =======================  File: quagga.info, Node: Autonomous System, Next: BGP Communities Attribute, Prev: BGP Address Family, Up: BGP 10.7 Autonomous System ====================== The AS (Autonomous System) number is one of the essential element of BGP. BGP is a distance vector routing protocol, and the AS-Path framework provides distance vector metric and loop detection to BGP. 'RFC1930, Guidelines for creation, selection, and registration of an Autonomous System (AS)' provides some background on the concepts of an AS. The AS number is a two octet value, ranging in value from 1 to 65535. The AS numbers 64512 through 65535 are defined as private AS numbers. Private AS numbers must not to be advertised in the global Internet. * Menu: * AS Path Regular Expression:: * Display BGP Routes by AS Path:: * AS Path Access List:: * Using AS Path in Route Map:: * Private AS Numbers::  File: quagga.info, Node: AS Path Regular Expression, Next: Display BGP Routes by AS Path, Up: Autonomous System 10.7.1 AS Path Regular Expression --------------------------------- AS path regular expression can be used for displaying BGP routes and AS path access list. AS path regular expression is based on 'POSIX 1003.2' regular expressions. Following description is just a subset of 'POSIX' regular expression. User can use full 'POSIX' regular expression. Adding to that special character '_' is added for AS path regular expression. '.' Matches any single character. '*' Matches 0 or more occurrences of pattern. '+' Matches 1 or more occurrences of pattern. '?' Match 0 or 1 occurrences of pattern. '^' Matches the beginning of the line. '$' Matches the end of the line. '_' Character '_' has special meanings in AS path regular expression. It matches to space and comma , and AS set delimiter { and } and AS confederation delimiter '(' and ')'. And it also matches to the beginning of the line and the end of the line. So '_' can be used for AS value boundaries match. 'show ip bgp regexp _7675_' matches to all of BGP routes which as AS number include 7675.  File: quagga.info, Node: Display BGP Routes by AS Path, Next: AS Path Access List, Prev: AS Path Regular Expression, Up: Autonomous System 10.7.2 Display BGP Routes by AS Path ------------------------------------ To show BGP routes which has specific AS path information 'show ip bgp' command can be used. -- Command: show ip bgp regexp LINE This commands display BGP routes that matches AS path regular expression LINE.  File: quagga.info, Node: AS Path Access List, Next: Using AS Path in Route Map, Prev: Display BGP Routes by AS Path, Up: Autonomous System 10.7.3 AS Path Access List -------------------------- AS path access list is user defined AS path. -- Command: ip as-path access-list WORD {permit|deny} LINE This command defines a new AS path access list. -- Command: no ip as-path access-list WORD -- Command: no ip as-path access-list WORD {permit|deny} LINE  File: quagga.info, Node: Using AS Path in Route Map, Next: Private AS Numbers, Prev: AS Path Access List, Up: Autonomous System 10.7.4 Using AS Path in Route Map --------------------------------- -- Route Map: match as-path WORD -- Route Map: set as-path prepend AS-PATH Prepend the given string of AS numbers to the AS_PATH. -- Route Map: set as-path prepend last-as NUM Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.  File: quagga.info, Node: Private AS Numbers, Prev: Using AS Path in Route Map, Up: Autonomous System 10.7.5 Private AS Numbers -------------------------  File: quagga.info, Node: BGP Communities Attribute, Next: BGP Extended Communities Attribute, Prev: Autonomous System, Up: BGP 10.8 BGP Communities Attribute ============================== BGP communities attribute is widely used for implementing policy routing. Network operators can manipulate BGP communities attribute based on their network policy. BGP communities attribute is defined in 'RFC1997, BGP Communities Attribute' and 'RFC1998, An Application of the BGP Community Attribute in Multi-home Routing'. It is an optional transitive attribute, therefore local policy can travel through different autonomous system. Communities attribute is a set of communities values. Each communities value is 4 octet long. The following format is used to define communities value. 'AS:VAL' This format represents 4 octet communities value. 'AS' is high order 2 octet in digit format. 'VAL' is low order 2 octet in digit format. This format is useful to define AS oriented policy value. For example, '7675:80' can be used when AS 7675 wants to pass local policy value 80 to neighboring peer. 'internet' 'internet' represents well-known communities value 0. 'no-export' 'no-export' represents well-known communities value 'NO_EXPORT' (0xFFFFFF01). All routes carry this value must not be advertised to outside a BGP confederation boundary. If neighboring BGP peer is part of BGP confederation, the peer is considered as inside a BGP confederation boundary, so the route will be announced to the peer. 'no-advertise' 'no-advertise' represents well-known communities value 'NO_ADVERTISE' (0xFFFFFF02). All routes carry this value must not be advertise to other BGP peers. 'local-AS' 'local-AS' represents well-known communities value 'NO_EXPORT_SUBCONFED' (0xFFFFFF03). All routes carry this value must not be advertised to external BGP peers. Even if the neighboring router is part of confederation, it is considered as external BGP peer, so the route will not be announced to the peer. When BGP communities attribute is received, duplicated communities value in the communities attribute is ignored and each communities values are sorted in numerical order. * Menu: * BGP Community Lists:: * Numbered BGP Community Lists:: * BGP Community in Route Map:: * Display BGP Routes by Community:: * Using BGP Communities Attribute::  File: quagga.info, Node: BGP Community Lists, Next: Numbered BGP Community Lists, Up: BGP Communities Attribute 10.8.1 BGP Community Lists -------------------------- BGP community list is a user defined BGP communites attribute list. BGP community list can be used for matching or manipulating BGP communities attribute in updates. There are two types of community list. One is standard community list and another is expanded community list. Standard community list defines communities attribute. Expanded community list defines communities attribute string with regular expression. Standard community list is compiled into binary format when user define it. Standard community list will be directly compared to BGP communities attribute in BGP updates. Therefore the comparison is faster than expanded community list. -- Command: ip community-list standard NAME {permit|deny} COMMUNITY This command defines a new standard community list. COMMUNITY is communities value. The COMMUNITY is compiled into community structure. We can define multiple community list under same name. In that case match will happen user defined order. Once the community list matches to communities attribute in BGP updates it return permit or deny by the community list definition. When there is no matched entry, deny will be returned. When COMMUNITY is empty it matches to any routes. -- Command: ip community-list expanded NAME {permit|deny} LINE This command defines a new expanded community list. LINE is a string expression of communities attribute. LINE can include regular expression to match communities attribute in BGP updates. -- Command: no ip community-list NAME -- Command: no ip community-list standard NAME -- Command: no ip community-list expanded NAME These commands delete community lists specified by NAME. All of community lists shares a single name space. So community lists can be removed simpley specifying community lists name. -- Command: show ip community-list -- Command: show ip community-list NAME This command display current community list information. When NAME is specified the specified community list's information is shown. # show ip community-list Named Community standard list CLIST permit 7675:80 7675:100 no-export deny internet Named Community expanded list EXPAND permit : # show ip community-list CLIST Named Community standard list CLIST permit 7675:80 7675:100 no-export deny internet  File: quagga.info, Node: Numbered BGP Community Lists, Next: BGP Community in Route Map, Prev: BGP Community Lists, Up: BGP Communities Attribute 10.8.2 Numbered BGP Community Lists ----------------------------------- When number is used for BGP community list name, the number has special meanings. Community list number in the range from 1 and 99 is standard community list. Community list number in the range from 100 to 199 is expanded community list. These community lists are called as numbered community lists. On the other hand normal community lists is called as named community lists. -- Command: ip community-list <1-99> {permit|deny} COMMUNITY This command defines a new community list. <1-99> is standard community list number. Community list name within this range defines standard community list. When COMMUNITY is empty it matches to any routes. -- Command: ip community-list <100-199> {permit|deny} COMMUNITY This command defines a new community list. <100-199> is expanded community list number. Community list name within this range defines expanded community list. -- Command: ip community-list NAME {permit|deny} COMMUNITY When community list type is not specifed, the community list type is automatically detected. If COMMUNITY can be compiled into communities attribute, the community list is defined as a standard community list. Otherwise it is defined as an expanded community list. This feature is left for backward compability. Use of this feature is not recommended.  File: quagga.info, Node: BGP Community in Route Map, Next: Display BGP Routes by Community, Prev: Numbered BGP Community Lists, Up: BGP Communities Attribute 10.8.3 BGP Community in Route Map --------------------------------- In Route Map (*note Route Map::), we can match or set BGP communities attribute. Using this feature network operator can implement their network policy based on BGP communities attribute. Following commands can be used in Route Map. -- Route Map: match community WORD -- Route Map: match community WORD exact-match This command perform match to BGP updates using community list WORD. When the one of BGP communities value match to the one of communities value in community list, it is match. When 'exact-match' keyword is spcified, match happen only when BGP updates have completely same communities value specified in the community list. -- Route Map: set community none -- Route Map: set community COMMUNITY -- Route Map: set community COMMUNITY additive This command manipulate communities value in BGP updates. When 'none' is specified as communities value, it removes entire communities attribute from BGP updates. When COMMUNITY is not 'none', specified communities value is set to BGP updates. If BGP updates already has BGP communities value, the existing BGP communities value is replaced with specified COMMUNITY value. When 'additive' keyword is specified, COMMUNITY is appended to the existing communities value. -- Route Map: set comm-list WORD delete This command remove communities value from BGP communities attribute. The WORD is community list name. When BGP route's communities value matches to the community list WORD, the communities value is removed. When all of communities value is removed eventually, the BGP update's communities attribute is completely removed.  File: quagga.info, Node: Display BGP Routes by Community, Next: Using BGP Communities Attribute, Prev: BGP Community in Route Map, Up: BGP Communities Attribute 10.8.4 Display BGP Routes by Community -------------------------------------- To show BGP routes which has specific BGP communities attribute, 'show ip bgp' command can be used. The COMMUNITY value and community list can be used for 'show ip bgp' command. -- Command: show ip bgp community -- Command: show ip bgp community COMMUNITY -- Command: show ip bgp community COMMUNITY exact-match 'show ip bgp community' displays BGP routes which has communities attribute. When COMMUNITY is specified, BGP routes that matches COMMUNITY value is displayed. For this command, 'internet' keyword can't be used for COMMUNITY value. When 'exact-match' is specified, it display only routes that have an exact match. -- Command: show ip bgp community-list WORD -- Command: show ip bgp community-list WORD exact-match This commands display BGP routes that matches community list WORD. When 'exact-match' is specified, display only routes that have an exact match.  File: quagga.info, Node: Using BGP Communities Attribute, Prev: Display BGP Routes by Community, Up: BGP Communities Attribute 10.8.5 Using BGP Communities Attribute -------------------------------------- Following configuration is the most typical usage of BGP communities attribute. AS 7675 provides upstream Internet connection to AS 100. When following configuration exists in AS 7675, AS 100 networks operator can set local preference in AS 7675 network by setting BGP communities attribute to the updates. router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list 70 permit 7675:70 ip community-list 70 deny ip community-list 80 permit 7675:80 ip community-list 80 deny ip community-list 90 permit 7675:90 ip community-list 90 deny ! route-map RMAP permit 10 match community 70 set local-preference 70 ! route-map RMAP permit 20 match community 80 set local-preference 80 ! route-map RMAP permit 30 match community 90 set local-preference 90 Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675. The route has communities value 7675:80 so when above configuration exists in AS 7675, announced route's local preference will be set to value 80. router bgp 100 network 10.0.0.0/8 neighbor 192.168.0.2 remote-as 7675 neighbor 192.168.0.2 route-map RMAP out ! ip prefix-list PLIST permit 10.0.0.0/8 ! route-map RMAP permit 10 match ip address prefix-list PLIST set community 7675:80 Following configuration is an example of BGP route filtering using communities attribute. This configuration only permit BGP routes which has BGP communities value 0:80 or 0:90. Network operator can put special internal communities value at BGP border router, then limit the BGP routes announcement into the internal network. router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list 1 permit 0:80 0:90 ! route-map RMAP permit in match community 1 Following exmaple filter BGP routes which has communities value 1:1. When there is no match community-list returns deny. To avoid filtering all of routes, we need to define permit any at last. router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard FILTER deny 1:1 ip community-list standard FILTER permit ! route-map RMAP permit 10 match community FILTER Communities value keyword 'internet' has special meanings in standard community lists. In below example 'internet' act as match any. It matches all of BGP routes even if the route does not have communities attribute at all. So community list 'INTERNET' is same as above example's 'FILTER'. ip community-list standard INTERNET deny 1:1 ip community-list standard INTERNET permit internet Following configuration is an example of communities value deletion. With this configuration communities value 100:1 and 100:2 is removed from BGP updates. For communities value deletion, only 'permit' community-list is used. 'deny' community-list is ignored. router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard DEL permit 100:1 100:2 ! route-map RMAP permit 10 set comm-list DEL delete  File: quagga.info, Node: BGP Extended Communities Attribute, Next: Displaying BGP routes, Prev: BGP Communities Attribute, Up: BGP 10.9 BGP Extended Communities Attribute ======================================= BGP extended communities attribute is introduced with MPLS VPN/BGP technology. MPLS VPN/BGP expands capability of network infrastructure to provide VPN functionality. At the same time it requires a new framework for policy routing. With BGP Extended Communities Attribute we can use Route Target or Site of Origin for implementing network policy for MPLS VPN/BGP. BGP Extended Communities Attribute is similar to BGP Communities Attribute. It is an optional transitive attribute. BGP Extended Communities Attribute can carry multiple Extended Community value. Each Extended Community value is eight octet length. BGP Extended Communities Attribute provides an extended range compared with BGP Communities Attribute. Adding to that there is a type field in each value to provides community space structure. There are two format to define Extended Community value. One is AS based format the other is IP address based format. 'AS:VAL' This is a format to define AS based Extended Community value. 'AS' part is 2 octets Global Administrator subfield in Extended Community value. 'VAL' part is 4 octets Local Administrator subfield. '7675:100' represents AS 7675 policy value 100. 'IP-Address:VAL' This is a format to define IP address based Extended Community value. 'IP-Address' part is 4 octets Global Administrator subfield. 'VAL' part is 2 octets Local Administrator subfield. '10.0.0.1:100' represents * Menu: * BGP Extended Community Lists:: * BGP Extended Communities in Route Map::  File: quagga.info, Node: BGP Extended Community Lists, Next: BGP Extended Communities in Route Map, Up: BGP Extended Communities Attribute 10.9.1 BGP Extended Community Lists ----------------------------------- Expanded Community Lists is a user defined BGP Expanded Community Lists. -- Command: ip extcommunity-list standard NAME {permit|deny} EXTCOMMUNITY This command defines a new standard extcommunity-list. EXTCOMMUNITY is extended communities value. The EXTCOMMUNITY is compiled into extended community structure. We can define multiple extcommunity-list under same name. In that case match will happen user defined order. Once the extcommunity-list matches to extended communities attribute in BGP updates it return permit or deny based upon the extcommunity-list definition. When there is no matched entry, deny will be returned. When EXTCOMMUNITY is empty it matches to any routes. -- Command: ip extcommunity-list expanded NAME {permit|deny} LINE This command defines a new expanded extcommunity-list. LINE is a string expression of extended communities attribute. LINE can include regular expression to match extended communities attribute in BGP updates. -- Command: no ip extcommunity-list NAME -- Command: no ip extcommunity-list standard NAME -- Command: no ip extcommunity-list expanded NAME These commands delete extended community lists specified by NAME. All of extended community lists shares a single name space. So extended community lists can be removed simpley specifying the name. -- Command: show ip extcommunity-list -- Command: show ip extcommunity-list NAME This command display current extcommunity-list information. When NAME is specified the community list's information is shown. # show ip extcommunity-list  File: quagga.info, Node: BGP Extended Communities in Route Map, Prev: BGP Extended Community Lists, Up: BGP Extended Communities Attribute 10.9.2 BGP Extended Communities in Route Map -------------------------------------------- -- Route Map: match extcommunity WORD -- Route Map: set extcommunity rt EXTCOMMUNITY This command set Route Target value. -- Route Map: set extcommunity soo EXTCOMMUNITY This command set Site of Origin value.  File: quagga.info, Node: Displaying BGP routes, Next: Capability Negotiation, Prev: BGP Extended Communities Attribute, Up: BGP 10.10 Displaying BGP Routes =========================== * Menu: * Show IP BGP:: * More Show IP BGP::  File: quagga.info, Node: Show IP BGP, Next: More Show IP BGP, Up: Displaying BGP routes 10.10.1 Show IP BGP ------------------- -- Command: show ip bgp -- Command: show ip bgp A.B.C.D -- Command: show ip bgp X:X::X:X This command displays BGP routes. When no route is specified it display all of IPv4 BGP routes. BGP table version is 0, local router ID is 10.1.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, i - internal Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.1/32 0.0.0.0 0 32768 i Total number of prefixes 1  File: quagga.info, Node: More Show IP BGP, Prev: Show IP BGP, Up: Displaying BGP routes 10.10.2 More Show IP BGP ------------------------ -- Command: show ip bgp regexp LINE This command display BGP routes using AS path regular expression (*note Display BGP Routes by AS Path::). -- Command: show ip bgp community COMMUNITY -- Command: show ip bgp community COMMUNITY exact-match This command display BGP routes using COMMUNITY (*note Display BGP Routes by Community::). -- Command: show ip bgp community-list WORD -- Command: show ip bgp community-list WORD exact-match This command display BGP routes using community list (*note Display BGP Routes by Community::). -- Command: show ip bgp summary -- Command: show ip bgp neighbor [PEER] -- Command: clear ip bgp PEER Clear peers which have addresses of X.X.X.X -- Command: clear ip bgp PEER soft in Clear peer using soft reconfiguration. -- Command: show ip bgp dampened-paths Display paths suppressed due to dampening -- Command: show ip bgp flap-statistics Display flap statistics of routes -- Command: show debug -- Command: debug event -- Command: debug update -- Command: debug keepalive -- Command: no debug event -- Command: no debug update -- Command: no debug keepalive  File: quagga.info, Node: Capability Negotiation, Next: Route Reflector, Prev: Displaying BGP routes, Up: BGP 10.11 Capability Negotiation ============================ When adding IPv6 routing information exchange feature to BGP. There were some proposals. IETF (Internet Engineering Task Force) IDR (Inter Domain Routing) WG (Working group) adopted a proposal called Multiprotocol Extension for BGP. The specification is described in 'RFC2283'. The protocol does not define new protocols. It defines new attributes to existing BGP. When it is used exchanging IPv6 routing information it is called BGP-4+. When it is used for exchanging multicast routing information it is called MBGP. 'bgpd' supports Multiprotocol Extension for BGP. So if remote peer supports the protocol, 'bgpd' can exchange IPv6 and/or multicast routing information. Traditional BGP did not have the feature to detect remote peer's capabilities, e.g. whether it can handle prefix types other than IPv4 unicast routes. This was a big problem using Multiprotocol Extension for BGP to operational network. 'RFC2842, Capabilities Advertisement with BGP-4' adopted a feature called Capability Negotiation. 'bgpd' use this Capability Negotiation to detect the remote peer's capabilities. If the peer is only configured as IPv4 unicast neighbor, 'bgpd' does not send these Capability Negotiation packets (at least not unless other optional BGP features require capability negotation). By default, Quagga will bring up peering with minimal common capability for the both sides. For example, local router has unicast and multicast capabilitie and remote router has unicast capability. In this case, the local router will establish the connection with unicast only capability. When there are no common capabilities, Quagga sends Unsupported Capability error and then resets the connection. If you want to completely match capabilities with remote peer. Please use 'strict-capability-match' command. -- BGP: neighbor PEER strict-capability-match -- BGP: no neighbor PEER strict-capability-match Strictly compares remote capabilities and local capabilities. If capabilities are different, send Unsupported Capability error then reset connection. You may want to disable sending Capability Negotiation OPEN message optional parameter to the peer when remote peer does not implement Capability Negotiation. Please use 'dont-capability-negotiate' command to disable the feature. -- BGP: neighbor PEER dont-capability-negotiate -- BGP: no neighbor PEER dont-capability-negotiate Suppress sending Capability Negotiation as OPEN message optional parameter to the peer. This command only affects the peer is configured other than IPv4 unicast configuration. When remote peer does not have capability negotiation feature, remote peer will not send any capabilities at all. In that case, bgp configures the peer with configured capabilities. You may prefer locally configured capabilities more than the negotiated capabilities even though remote peer sends capabilities. If the peer is configured by 'override-capability', 'bgpd' ignores received capabilities then override negotiated capabilities with configured values. -- BGP: neighbor PEER override-capability -- BGP: no neighbor PEER override-capability Override the result of Capability Negotiation with local configuration. Ignore remote peer's capability value.  File: quagga.info, Node: Route Reflector, Next: Route Server, Prev: Capability Negotiation, Up: BGP 10.12 Route Reflector ===================== -- BGP: bgp cluster-id A.B.C.D -- BGP: neighbor PEER route-reflector-client -- BGP: no neighbor PEER route-reflector-client  File: quagga.info, Node: Route Server, Next: How to set up a 6-Bone connection, Prev: Route Reflector, Up: BGP 10.13 Route Server ================== At an Internet Exchange point, many ISPs are connected to each other by external BGP peering. Normally these external BGP connection are done by 'full mesh' method. As with internal BGP full mesh formation, this method has a scaling problem. This scaling problem is well known. Route Server is a method to resolve the problem. Each ISP's BGP router only peers to Route Server. Route Server serves as BGP information exchange to other BGP routers. By applying this method, numbers of BGP connections is reduced from O(n*(n-1)/2) to O(n). Unlike normal BGP router, Route Server must have several routing tables for managing different routing policies for each BGP speaker. We call the routing tables as different 'view's. 'bgpd' can work as normal BGP router or Route Server or both at the same time. * Menu: * Multiple instance:: * BGP instance and view:: * Routing policy:: * Viewing the view::  File: quagga.info, Node: Multiple instance, Next: BGP instance and view, Up: Route Server 10.13.1 Multiple instance ------------------------- To enable multiple view function of 'bgpd', you must turn on multiple instance feature beforehand. -- Command: bgp multiple-instance Enable BGP multiple instance feature. After this feature is enabled, you can make multiple BGP instances or multiple BGP views. -- Command: no bgp multiple-instance Disable BGP multiple instance feature. You can not disable this feature when BGP multiple instances or views exist. When you want to make configuration more Cisco like one, -- Command: bgp config-type cisco Cisco compatible BGP configuration output. When bgp config-type cisco is specified, "no synchronization" is displayed. "no auto-summary" is displayed. "network" and "aggregate-address" argument is displayed as "A.B.C.D M.M.M.M" Quagga: network 10.0.0.0/8 Cisco: network 10.0.0.0 Quagga: aggregate-address 192.168.0.0/24 Cisco: aggregate-address 192.168.0.0 255.255.255.0 Community attribute handling is also different. If there is no configuration is specified community attribute and extended community attribute are sent to neighbor. When user manually disable the feature community attribute is not sent to the neighbor. In case of 'bgp config-type cisco' is specified, community attribute is not sent to the neighbor by default. To send community attribute user has to specify 'neighbor A.B.C.D send-community' command. ! router bgp 1 neighbor 10.0.0.1 remote-as 1 no neighbor 10.0.0.1 send-community ! router bgp 1 neighbor 10.0.0.1 remote-as 1 neighbor 10.0.0.1 send-community ! -- Command: bgp config-type zebra Quagga style BGP configuration. This is default.  File: quagga.info, Node: BGP instance and view, Next: Routing policy, Prev: Multiple instance, Up: Route Server 10.13.2 BGP instance and view ----------------------------- BGP instance is a normal BGP process. The result of route selection goes to the kernel routing table. You can setup different AS at the same time when BGP multiple instance feature is enabled. -- Command: router bgp AS-NUMBER Make a new BGP instance. You can use arbitrary word for the NAME. bgp multiple-instance ! router bgp 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.2 remote-as 3 ! router bgp 2 neighbor 10.0.0.3 remote-as 4 neighbor 10.0.0.4 remote-as 5 BGP view is almost same as normal BGP process. The result of route selection does not go to the kernel routing table. BGP view is only for exchanging BGP routing information. -- Command: router bgp AS-NUMBER view NAME Make a new BGP view. You can use arbitrary word for the NAME. This view's route selection result does not go to the kernel routing table. With this command, you can setup Route Server like below. bgp multiple-instance ! router bgp 1 view 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.2 remote-as 3 ! router bgp 2 view 2 neighbor 10.0.0.3 remote-as 4 neighbor 10.0.0.4 remote-as 5  File: quagga.info, Node: Routing policy, Next: Viewing the view, Prev: BGP instance and view, Up: Route Server 10.13.3 Routing policy ---------------------- You can set different routing policy for a peer. For example, you can set different filter for a peer. bgp multiple-instance ! router bgp 1 view 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.1 distribute-list 1 in ! router bgp 1 view 2 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.1 distribute-list 2 in This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view 2. When the update is inserted into view 1, distribute-list 1 is applied. On the other hand, when the update is inserted into view 2, distribute-list 2 is applied.  File: quagga.info, Node: Viewing the view, Prev: Routing policy, Up: Route Server 10.13.4 Viewing the view ------------------------ To display routing table of BGP view, you must specify view name. -- Command: show ip bgp view NAME Display routing table of BGP view NAME.  File: quagga.info, Node: How to set up a 6-Bone connection, Next: Dump BGP packets and table, Prev: Route Server, Up: BGP 10.14 How to set up a 6-Bone connection ======================================= zebra configuration =================== ! ! Actually there is no need to configure zebra ! bgpd configuration ================== ! ! This means that routes go through zebra and into the kernel. ! router zebra ! ! MP-BGP configuration ! router bgp 7675 bgp router-id 10.0.0.1 neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as AS-NUMBER ! address-family ipv6 network 3ffe:506::/32 neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as AS-NUMBER neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out exit-address-family ! ipv6 access-list all permit any ! ! Set output nexthop address. ! route-map set-nexthop permit 10 match ipv6 address all set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225 set ipv6 nexthop local fe80::2c0:4fff:fe68:a225 ! ! logfile FILENAME is obsolete. Please use log file FILENAME log file bgpd.log !  File: quagga.info, Node: Dump BGP packets and table, Next: BGP Configuration Examples, Prev: How to set up a 6-Bone connection, Up: BGP 10.15 Dump BGP packets and table ================================ -- Command: dump bgp all PATH -- Command: dump bgp all PATH INTERVAL Dump all BGP packet and events to PATH file. -- Command: dump bgp updates PATH -- Command: dump bgp updates PATH INTERVAL Dump BGP updates to PATH file. -- Command: dump bgp routes PATH -- Command: dump bgp routes PATH Dump whole BGP routing table to PATH. This is heavy process.  File: quagga.info, Node: BGP Configuration Examples, Prev: Dump BGP packets and table, Up: BGP 10.16 BGP Configuration Examples ================================ Example of a session to an upstream, advertising only one prefix to it. router bgp 64512 bgp router-id 10.236.87.1 network 10.236.87.0/24 neighbor upstream peer-group neighbor upstream remote-as 64515 neighbor upstream capability dynamic neighbor upstream prefix-list pl-allowed-adv out neighbor 10.1.1.1 peer-group upstream neighbor 10.1.1.1 description ACME ISP ! ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25 ip prefix-list pl-allowed-adv seq 10 deny any A more complex example. With upstream, peer and customer sessions. Advertising global prefixes and NO_EXPORT prefixes and providing actions for customer routes based on community values. Extensive use of route-maps and the 'call' feature to support selective advertising of prefixes. This example is intended as guidance only, it has NOT been tested and almost certainly containts silly mistakes, if not serious flaws. router bgp 64512 bgp router-id 10.236.87.1 network 10.123.456.0/24 network 10.123.456.128/25 route-map rm-no-export neighbor upstream capability dynamic neighbor upstream route-map rm-upstream-out out neighbor cust capability dynamic neighbor cust route-map rm-cust-in in neighbor cust route-map rm-cust-out out neighbor cust send-community both neighbor peer capability dynamic neighbor peer route-map rm-peer-in in neighbor peer route-map rm-peer-out out neighbor peer send-community both neighbor 10.1.1.1 remote-as 64515 neighbor 10.1.1.1 peer-group upstream neighbor 10.2.1.1 remote-as 64516 neighbor 10.2.1.1 peer-group upstream neighbor 10.3.1.1 remote-as 64517 neighbor 10.3.1.1 peer-group cust-default neighbor 10.3.1.1 description customer1 neighbor 10.3.1.1 prefix-list pl-cust1-network in neighbor 10.4.1.1 remote-as 64518 neighbor 10.4.1.1 peer-group cust neighbor 10.4.1.1 prefix-list pl-cust2-network in neighbor 10.4.1.1 description customer2 neighbor 10.5.1.1 remote-as 64519 neighbor 10.5.1.1 peer-group peer neighbor 10.5.1.1 prefix-list pl-peer1-network in neighbor 10.5.1.1 description peer AS 1 neighbor 10.6.1.1 remote-as 64520 neighbor 10.6.1.1 peer-group peer neighbor 10.6.1.1 prefix-list pl-peer2-network in neighbor 10.6.1.1 description peer AS 2 ! ip prefix-list pl-default permit 0.0.0.0/0 ! ip prefix-list pl-upstream-peers permit 10.1.1.1/32 ip prefix-list pl-upstream-peers permit 10.2.1.1/32 ! ip prefix-list pl-cust1-network permit 10.3.1.0/24 ip prefix-list pl-cust1-network permit 10.3.2.0/24 ! ip prefix-list pl-cust2-network permit 10.4.1.0/24 ! ip prefix-list pl-peer1-network permit 10.5.1.0/24 ip prefix-list pl-peer1-network permit 10.5.2.0/24 ip prefix-list pl-peer1-network permit 192.168.0.0/24 ! ip prefix-list pl-peer2-network permit 10.6.1.0/24 ip prefix-list pl-peer2-network permit 10.6.2.0/24 ip prefix-list pl-peer2-network permit 192.168.1.0/24 ip prefix-list pl-peer2-network permit 192.168.2.0/24 ip prefix-list pl-peer2-network permit 172.16.1/24 ! ip as-path access-list asp-own-as permit ^$ ip as-path access-list asp-own-as permit _64512_ ! ! ################################################################# ! Match communities we provide actions for, on routes receives from ! customers. Communities values of :X, with X, have actions: ! ! 100 - blackhole the prefix ! 200 - set no_export ! 300 - advertise only to other customers ! 400 - advertise only to upstreams ! 500 - set no_export when advertising to upstreams ! 2X00 - set local_preference to X00 ! ! blackhole the prefix of the route ip community-list standard cm-blackhole permit 64512:100 ! ! set no-export community before advertising ip community-list standard cm-set-no-export permit 64512:200 ! ! advertise only to other customers ip community-list standard cm-cust-only permit 64512:300 ! ! advertise only to upstreams ip community-list standard cm-upstream-only permit 64512:400 ! ! advertise to upstreams with no-export ip community-list standard cm-upstream-noexport permit 64512:500 ! ! set local-pref to least significant 3 digits of the community ip community-list standard cm-prefmod-100 permit 64512:2100 ip community-list standard cm-prefmod-200 permit 64512:2200 ip community-list standard cm-prefmod-300 permit 64512:2300 ip community-list standard cm-prefmod-400 permit 64512:2400 ip community-list expanded cme-prefmod-range permit 64512:2... ! ! Informational communities ! ! 3000 - learned from upstream ! 3100 - learned from customer ! 3200 - learned from peer ! ip community-list standard cm-learnt-upstream permit 64512:3000 ip community-list standard cm-learnt-cust permit 64512:3100 ip community-list standard cm-learnt-peer permit 64512:3200 ! ! ################################################################### ! Utility route-maps ! ! These utility route-maps generally should not used to permit/deny ! routes, i.e. they do not have meaning as filters, and hence probably ! should be used with 'on-match next'. These all finish with an empty ! permit entry so as not interfere with processing in the caller. ! route-map rm-no-export permit 10 set community additive no-export route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 description blackhole, up-pref and ensure it cant escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export route-map rm-blackhole permit 20 ! ! Set local-pref as requested route-map rm-prefmod permit 10 match community cm-prefmod-100 set local-preference 100 route-map rm-prefmod permit 20 match community cm-prefmod-200 set local-preference 200 route-map rm-prefmod permit 30 match community cm-prefmod-300 set local-preference 300 route-map rm-prefmod permit 40 match community cm-prefmod-400 set local-preference 400 route-map rm-prefmod permit 50 ! ! Community actions to take on receipt of route. route-map rm-community-in permit 10 description check for blackholing, no point continuing if it matches. match community cm-blackhole call rm-blackhole route-map rm-community-in permit 20 match community cm-set-no-export call rm-no-export on-match next route-map rm-community-in permit 30 match community cme-prefmod-range call rm-prefmod route-map rm-community-in permit 40 ! ! ##################################################################### ! Community actions to take when advertising a route. ! These are filtering route-maps, ! ! Deny customer routes to upstream with cust-only set. route-map rm-community-filt-to-upstream deny 10 match community cm-learnt-cust match community cm-cust-only route-map rm-community-filt-to-upstream permit 20 ! ! Deny customer routes to other customers with upstream-only set. route-map rm-community-filt-to-cust deny 10 match community cm-learnt-cust match community cm-upstream-only route-map rm-community-filt-to-cust permit 20 ! ! ################################################################### ! The top-level route-maps applied to sessions. Further entries could ! be added obviously.. ! ! Customers route-map rm-cust-in permit 10 call rm-community-in on-match next route-map rm-cust-in permit 20 set community additive 64512:3100 route-map rm-cust-in permit 30 ! route-map rm-cust-out permit 10 call rm-community-filt-to-cust on-match next route-map rm-cust-out permit 20 ! ! Upstream transit ASes route-map rm-upstream-out permit 10 description filter customer prefixes which are marked cust-only call rm-community-filt-to-upstream on-match next route-map rm-upstream-out permit 20 description only customer routes are provided to upstreams/peers match community cm-learnt-cust ! ! Peer ASes ! outbound policy is same as for upstream route-map rm-peer-out permit 10 call rm-upstream-out ! route-map rm-peer-in permit 10 set community additive 64512:3200  File: quagga.info, Node: Configuring Quagga as a Route Server, Next: VTY shell, Prev: BGP, Up: Top 11 Configuring Quagga as a Route Server *************************************** The purpose of a Route Server is to centralize the peerings between BGP speakers. For example if we have an exchange point scenario with four BGP speakers, each of which maintaining a BGP peering with the other three (*note Figure 11.2: fig:full-mesh.), we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server (*note Figure 11.3: fig:route-server.). We will first describe briefly the Route Server model implemented by Quagga. We will explain the commands that have been added for configuring that model. And finally we will show a full example of Quagga configured as Route Server. * Menu: * Description of the Route Server model:: * Commands for configuring a Route Server:: * Example of Route Server Configuration::  File: quagga.info, Node: Description of the Route Server model, Next: Commands for configuring a Route Server, Up: Configuring Quagga as a Route Server 11.1 Description of the Route Server model ========================================== First we are going to describe the normal processing that BGP announcements suffer inside a standard BGP speaker, as shown in *note Figure 11.1: fig:normal-processing, it consists of three steps: * When an announcement is received from some peer, the 'In' filters configured for that peer are applied to the announcement. These filters can reject the announcement, accept it unmodified, or accept it with some of its attributes modified. * The announcements that pass the 'In' filters go into the Best Path Selection process, where they are compared to other announcements referred to the same destination that have been received from different peers (in case such other announcements exist). For each different destination, the announcement which is selected as the best is inserted into the BGP speaker's Loc-RIB. * The routes which are inserted in the Loc-RIB are considered for announcement to all the peers (except the one from which the route came). This is done by passing the routes in the Loc-RIB through the 'Out' filters corresponding to each peer. These filters can reject the route, accept it unmodified, or accept it with some of its attributes modified. Those routes which are accepted by the 'Out' filters of a peer are announced to that peer. [image src="fig-normal-processing.png" alt="Normal announcement processing" text=" _______________________________ / _________ _________ \\ From Peer A --->|(A)-|Best | | |-[A]|--->To Peer A From Peer B --->|(B)-|Path |-->|Local-RIB|-[B]|--->To Peer B From Peer C --->|(C)-|Selection| | |-[C]|--->To Peer C From Peer D --->|(D)-|_________| |_________|-[D]|--->To Peer D \\_______________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements [X] - 'Out' Filter applied to announcements to Peer X"] Figure 11.1: Announcement processing inside a "normal" BGP speaker [image src="fig_topologies_full.png" alt="Full Mesh BGP Topology" text="(RF1)--(RF2) | \\ / | | \\/ | | /\\ | | / \\ | (RF3)--(RF4)"] Figure 11.2: Full Mesh [image src="fig_topologies_rs.png" alt="Route Server BGP Topology" text="(RF1) (RF2) \\ / [RS] / \\ (RF3) (RF4)"] Figure 11.3: Route Server and clients Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as a consequence of having a single BGP peering (against the route server), the BGP speakers can no longer distinguish from/to which peer each announce comes/goes. This means that the routers connected to the route server are not able to apply by themselves the same input/output filters as in the full mesh scenario, so they have to delegate those functions to the route server. Even more, the "best path" selection must be also performed inside the route server on behalf of its clients. The reason is that if, after applying the filters of the announcer and the (potential) receiver, the route server decides to send to some client two or more different announcements referred to the same destination, the client will only retain the last one, considering it as an implicit withdrawal of the previous announcements for the same destination. This is the expected behavior of a BGP speaker as defined in 'RFC1771', and even though there are some proposals of mechanisms that permit multiple paths for the same destination to be sent through a single BGP peering, none are currently supported by most existing BGP implementations. As a consequence a route server must maintain additional information and perform additional tasks for a RS-client that those necessary for common BGP peerings. Essentially a route server must: * Maintain a separated Routing Information Base (Loc-RIB) for each peer configured as RS-client, containing the routes selected as a result of the "Best Path Selection" process that is performed on behalf of that RS-client. * Whenever it receives an announcement from a RS-client, it must consider it for the Loc-RIBs of the other RS-clients. * This means that for each of them the route server must pass the announcement through the appropriate 'Out' filter of the announcer. * Then through the appropriate 'In' filter of the potential receiver. * Only if the announcement is accepted by both filters it will be passed to the "Best Path Selection" process. * Finally, it might go into the Loc-RIB of the receiver. When we talk about the "appropriate" filter, both the announcer and the receiver of the route must be taken into account. Suppose that the route server receives an announcement from client A, and the route server is considering it for the Loc-RIB of client B. The filters that should be applied are the same that would be used in the full mesh scenario, i.e., first the 'Out' filter of router A for announcements going to router B, and then the 'In' filter of router B for announcements coming from router A. We call "Export Policy" of a RS-client to the set of 'Out' filters that the client would use if there was no route server. The same applies for the "Import Policy" of a RS-client and the set of 'In' filters of the client if there was no route server. It is also common to demand from a route server that it does not modify some BGP attributes (next-hop, as-path and MED) that are usually modified by standard BGP speakers before announcing a route. The announcement processing model implemented by Quagga is shown in *note Figure 11.4: fig:rs-processing. The figure shows a mixture of RS-clients (B, C and D) with normal BGP peers (A). There are some details that worth additional comments: * Announcements coming from a normal BGP peer are also considered for the Loc-RIBs of all the RS-clients. But logically they do not pass through any export policy. * Those peers that are configured as RS-clients do not receive any announce from the 'Main' Loc-RIB. * Apart from import and export policies, 'In' and 'Out' filters can also be set for RS-clients. 'In' filters might be useful when the route server has also normal BGP peers. On the other hand, 'Out' filters for RS-clients are probably unnecessary, but we decided not to remove them as they do not hurt anybody (they can always be left empty). [image src="fig-rs-processing.png" alt="Route Server Processing Model" text="From Peer A | From RS-Client B | | From RS-Client C | | | From RS-Client D | | | | | | | | Main / Normal RIB | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->|(D)-|Best | | Main | | | | +--|--->|(C)-|Path |-->|Local-RIB|->[A]|--->To Peer A | +--|--|--->|(B)-|Selection| | | | +--|--|--|--->|(A)-|_________| |_________| | | | | | \\________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->*D*->|{B}-|Best | |RS-Client| | | | +--|--->*C*->|{B}-|Path |-->|Local-RIB|->[B]|--->To RS-Client B | | | | | |Selection| | for B | | +--|--|--|-------->|{B}-|_________| |_________| | | | | | \\________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \\ | | | +--->*D*->|{C}-|Best | |RS-Client| | | | | | | |Path |-->|Local-RIB|->[C]|--->To RS-Client C | +--|--|--->*B*->|{C}-|Selection| | for C | | +--|--|--|-------->|{C}-|_________| |_________| | | | | \\________________________________/ | | | | | | ________________________________ | | | / _________ _________ \\ | | | | |Best | |RS-Client| | | | +------>*C*->|{D}-|Path |-->|Local-RIB|->[D]|--->To RS-Client D | +--------->*B*->|{D}-|Selection| | for D | | +----------------->|{D}-|_________| |_________| | \\________________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements before considering announcement for the normal main Local-RIB [X] - 'Out' Filter applied to announcements to Peer X *X* - 'Export' Filter of RS-Client X, to apply X's policies before its routes may be considered for other RS-Clients RIBs. {X} - 'Import' Filter of RS-Client X, to apply X's policies on routes before allowing them into X's RIB."] Figure 11.4: Announcement processing model implemented by the Route Server  File: quagga.info, Node: Commands for configuring a Route Server, Next: Example of Route Server Configuration, Prev: Description of the Route Server model, Up: Configuring Quagga as a Route Server 11.2 Commands for configuring a Route Server ============================================ Now we will describe the commands that have been added to quagga in order to support the route server features. -- Route-Server: neighbor PEER-GROUP route-server-client -- Route-Server: neighbor A.B.C.D route-server-client -- Route-Server: neighbor X:X::X:X route-server-client This command configures the peer given by PEER, A.B.C.D or X:X::X:X as an RS-client. Actually this command is not new, it already existed in standard Quagga. It enables the transparent mode for the specified peer. This means that some BGP attributes (as-path, next-hop and MED) of the routes announced to that peer are not modified. With the route server patch, this command, apart from setting the transparent mode, creates a new Loc-RIB dedicated to the specified peer (those named 'Loc-RIB for X' in *note Figure 11.4: fig:rs-processing.). Starting from that moment, every announcement received by the route server will be also considered for the new Loc-RIB. -- Route-Server: neigbor {A.B.C.D|X.X::X.X|peer-group} route-map WORD {import|export} This set of commands can be used to specify the route-map that represents the Import or Export policy of a peer which is configured as a RS-client (with the previous command). -- Route-Server: match peer {A.B.C.D|X:X::X:X} This is a new _match_ statement for use in route-maps, enabling them to describe import/export policies. As we said before, an import/export policy represents a set of input/output filters of the RS-client. This statement makes possible that a single route-map represents the full set of filters that a BGP speaker would use for its different peers in a non-RS scenario. The _match peer_ statement has different semantics whether it is used inside an import or an export route-map. In the first case the statement matches if the address of the peer who sends the announce is the same that the address specified by {A.B.C.D|X:X::X:X}. For export route-maps it matches when {A.B.C.D|X:X::X:X} is the address of the RS-Client into whose Loc-RIB the announce is going to be inserted (how the same export policy is applied before different Loc-RIBs is shown in *note Figure 11.4: fig:rs-processing.). -- Route-map Command: call WORD This command (also used inside a route-map) jumps into a different route-map, whose name is specified by WORD. When the called route-map finishes, depending on its result the original route-map continues or not. Apart from being useful for making import/export route-maps easier to write, this command can also be used inside any normal (in or out) route-map.  File: quagga.info, Node: Example of Route Server Configuration, Prev: Commands for configuring a Route Server, Up: Configuring Quagga as a Route Server 11.3 Example of Route Server Configuration ========================================== Finally we are going to show how to configure a Quagga daemon to act as a Route Server. For this purpose we are going to present a scenario without route server, and then we will show how to use the configurations of the BGP routers to generate the configuration of the route server. All the configuration files shown in this section have been taken from scenarios which were tested using the VNUML tool VNUML (http://www.dit.upm.es/vnuml). * Menu: * Configuration of the BGP routers without Route Server:: * Configuration of the BGP routers with Route Server:: * Configuration of the Route Server itself:: * Further considerations about Import and Export route-maps::  File: quagga.info, Node: Configuration of the BGP routers without Route Server, Next: Configuration of the BGP routers with Route Server, Up: Example of Route Server Configuration 11.3.1 Configuration of the BGP routers without Route Server ------------------------------------------------------------ We will suppose that our initial scenario is an exchange point with three BGP capable routers, named RA, RB and RC. Each of the BGP speakers generates some routes (with the NETWORK command), and establishes BGP peerings against the other two routers. These peerings have In and Out route-maps configured, named like "PEER-X-IN" or "PEER-X-OUT". For example the configuration file for router RA could be the following: #Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::B route-map PEER-B-IN in neighbor 2001:0DB8::B route-map PEER-B-OUT out neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C soft-reconfiguration inbound neighbor 2001:0DB8::C route-map PEER-C-IN in neighbor 2001:0DB8::C route-map PEER-C-OUT out exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map PEER-C-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map PEER-C-IN permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map PEER-B-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! route-map PEER-C-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! line vty !  File: quagga.info, Node: Configuration of the BGP routers with Route Server, Next: Configuration of the Route Server itself, Prev: Configuration of the BGP routers without Route Server, Up: Example of Route Server Configuration 11.3.2 Configuration of the BGP routers with Route Server --------------------------------------------------------- To convert the initial scenario into one with route server, first we must modify the configuration of routers RA, RB and RC. Now they must not peer between them, but only with the route server. For example, RA's configuration would turn into: # Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::FFFF remote-as 65000 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::FFFF activate neighbor 2001:0DB8::FFFF soft-reconfiguration inbound exit-address-family ! line vty ! Which is logically much simpler than its initial configuration, as it now maintains only one BGP peering and all the filters (route-maps) have disappeared.  File: quagga.info, Node: Configuration of the Route Server itself, Next: Further considerations about Import and Export route-maps, Prev: Configuration of the BGP routers with Route Server, Up: Example of Route Server Configuration 11.3.3 Configuration of the Route Server itself ----------------------------------------------- As we said when we described the functions of a route server (*note Description of the Route Server model::), it is in charge of all the route filtering. To achieve that, the In and Out filters from the RA, RB and RC configurations must be converted into Import and Export policies in the route server. This is a fragment of the route server configuration (we only show the policies for client RA): # Configuration for Route Server ('RS') ! hostname RS password ix ! bgp multiple-instance ! router bgp 65000 view RS no bgp default ipv4-unicast neighbor 2001:0DB8::A remote-as 65001 neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 neighbor 2001:0DB8::A activate neighbor 2001:0DB8::A route-server-client neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export neighbor 2001:0DB8::A soft-reconfiguration inbound neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B route-server-client neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C route-server-client neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export neighbor 2001:0DB8::C soft-reconfiguration inbound exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B route-map RSCLIENT-A-IMPORT permit 20 match peer 2001:0DB8::C call A-IMPORT-FROM-C ! route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map A-IMPORT-FROM-C permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map A-IMPORT-FROM-C permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map RSCLIENT-A-EXPORT permit 10 match peer 2001:0DB8::B match ipv6 address prefix-list PEER-A-PREFIXES route-map RSCLIENT-A-EXPORT permit 20 match peer 2001:0DB8::C match ipv6 address prefix-list PEER-A-PREFIXES ! ... ... ... If you compare the initial configuration of RA with the route server configuration above, you can see how easy it is to generate the Import and Export policies for RA from the In and Out route-maps of RA's original configuration. When there was no route server, RA maintained two peerings, one with RB and another with RC. Each of this peerings had an In route-map configured. To build the Import route-map for client RA in the route server, simply add route-map entries following this scheme: route-map permit 10 match peer call route-map permit 20 match peer call This is exactly the process that has been followed to generate the route-map RSCLIENT-A-IMPORT. The route-maps that are called inside it (A-IMPORT-FROM-B and A-IMPORT-FROM-C) are exactly the same than the In route-maps from the original configuration of RA (PEER-B-IN and PEER-C-IN), only the name is different. The same could have been done to create the Export policy for RA (route-map RSCLIENT-A-EXPORT), but in this case the original Out route-maps where so simple that we decided not to use the CALL WORD commands, and we integrated all in a single route-map (RSCLIENT-A-EXPORT). The Import and Export policies for RB and RC are not shown, but the process would be identical.  File: quagga.info, Node: Further considerations about Import and Export route-maps, Prev: Configuration of the Route Server itself, Up: Example of Route Server Configuration 11.3.4 Further considerations about Import and Export route-maps ---------------------------------------------------------------- The current version of the route server patch only allows to specify a route-map for import and export policies, while in a standard BGP speaker apart from route-maps there are other tools for performing input and output filtering (access-lists, community-lists, ...). But this does not represent any limitation, as all kinds of filters can be included in import/export route-maps. For example suppose that in the non-route-server scenario peer RA had the following filters configured for input from peer B: neighbor 2001:0DB8::B prefix-list LIST-1 in neighbor 2001:0DB8::B filter-list LIST-2 in neighbor 2001:0DB8::B route-map PEER-B-IN in ... ... route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 It is posible to write a single route-map which is equivalent to the three filters (the community-list, the prefix-list and the route-map). That route-map can then be used inside the Import policy in the route server. Lets see how to do it: neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import ... ! ... route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B ... ... ! route-map A-IMPORT-FROM-B permit 1 match ipv6 address prefix-list LIST-1 match as-path LIST-2 on-match goto 10 route-map A-IMPORT-FROM-B deny 2 route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! ... ... The route-map A-IMPORT-FROM-B is equivalent to the three filters (LIST-1, LIST-2 and PEER-B-IN). The first entry of route-map A-IMPORT-FROM-B (sequence number 1) matches if and only if both the prefix-list LIST-1 and the filter-list LIST-2 match. If that happens, due to the "on-match goto 10" statement the next route-map entry to be processed will be number 10, and as of that point route-map A-IMPORT-FROM-B is identical to PEER-B-IN. If the first entry does not match, 'on-match goto 10" will be ignored and the next processed entry will be number 2, which will deny the route. Thus, the result is the same that with the three original filters, i.e., if either LIST-1 or LIST-2 rejects the route, it does not reach the route-map PEER-B-IN. In case both LIST-1 and LIST-2 accept the route, it passes to PEER-B-IN, which can reject, accept or modify the route.  File: quagga.info, Node: VTY shell, Next: Filtering, Prev: Configuring Quagga as a Route Server, Up: Top 12 VTY shell ************ 'vtysh' is integrated shell of Quagga software. To use vtysh please specify --enable-vtysh to configure script. To use PAM for authentication use --with-libpam option to configure script. vtysh only searches /etc/quagga path for vtysh.conf which is the vtysh configuration file. Vtysh does not search current directory for configuration file because the file includes user authentication settings. Currently, vtysh.conf has only two commands. * Menu: * VTY shell username:: * VTY shell integrated configuration::  File: quagga.info, Node: VTY shell username, Next: VTY shell integrated configuration, Up: VTY shell 12.1 VTY shell username ======================= -- Command: username USERNAME nopassword With this set, user foo does not need password authentication for user vtysh. With PAM vtysh uses PAM authentication mechanism. If vtysh is compiled without PAM authentication, every user can use vtysh without authentication. vtysh requires read/write permission to the various daemons vty sockets, this can be accomplished through use of unix groups and the -enable-vty-group configure option.  File: quagga.info, Node: VTY shell integrated configuration, Prev: VTY shell username, Up: VTY shell 12.2 VTY shell integrated configuration ======================================= -- Command: service integrated-vtysh-config Write out integrated Quagga.conf file when 'write file' is issued. This command controls the behaviour of vtysh when it is told to write out the configuration. Per default, vtysh will instruct each daemon to write out their own config files when 'write file' is issued. However, if 'service integrated-vtysh-config' is set, when 'write file' is issued, vtysh will instruct the daemons will write out a Quagga.conf with all daemons' commands integrated into it. Vtysh per default behaves as if 'write-conf daemon' is set. Note that both may be set at same time if one wishes to have both Quagga.conf and daemon specific files written out. Further, note that the daemons are hard-coded to first look for the integrated Quagga.conf file before looking for their own file. We recommend you do not mix the use of the two types of files. Further, it is better not to use the integrated Quagga.conf file, as any syntax error in it can lead to /all/ of your daemons being unable to start up. Per daemon files are more robust as impact of errors in configuration are limited to the daemon in whose file the error is made.  File: quagga.info, Node: Filtering, Next: Route Map, Prev: VTY shell, Up: Top 13 Filtering ************ Quagga provides many very flexible filtering features. Filtering is used for both input and output of the routing information. Once filtering is defined, it can be applied in any direction. * Menu: * IP Access List:: * IP Prefix List::  File: quagga.info, Node: IP Access List, Next: IP Prefix List, Up: Filtering 13.1 IP Access List =================== -- Command: access-list NAME permit IPV4-NETWORK -- Command: access-list NAME deny IPV4-NETWORK Basic filtering is done by 'access-list' as shown in the following example. access-list filter deny 10.0.0.0/9 access-list filter permit 10.0.0.0/8  File: quagga.info, Node: IP Prefix List, Prev: IP Access List, Up: Filtering 13.2 IP Prefix List =================== 'ip prefix-list' provides the most powerful prefix based filtering mechanism. In addition to 'access-list' functionality, 'ip prefix-list' has prefix length range specification and sequential number specification. You can add or delete prefix based filters to arbitrary points of prefix-list using sequential number specification. If no ip prefix-list is specified, it acts as permit. If 'ip prefix-list' is defined, and no match is found, default deny is applied. -- Command: ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN] -- Command: ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN] You can create 'ip prefix-list' using above commands. seq seq NUMBER can be set either automatically or manually. In the case that sequential numbers are set manually, the user may pick any number less than 4294967295. In the case that sequential number are set automatically, the sequential number will increase by a unit of five (5) per list. If a list with no specified sequential number is created after a list with a specified sequential number, the list will automatically pick the next multiple of five (5) as the list number. For example, if a list with number 2 already exists and a new list with no specified number is created, the next list will be numbered 5. If lists 2 and 7 already exist and a new list with no specified number is created, the new list will be numbered 10. le 'le' command specifies prefix length. The prefix list will be applied if the prefix length is less than or equal to the le prefix length. ge 'ge' command specifies prefix length. The prefix list will be applied if the prefix length is greater than or equal to the ge prefix length. Less than or equal to prefix numbers and greater than or equal to prefix numbers can be used together. The order of the le and ge commands does not matter. If a prefix list with a different sequential number but with the exact same rules as a previous list is created, an error will result. However, in the case that the sequential number and the rules are exactly similar, no error will result. If a list with the same sequential number as a previous list is created, the new list will overwrite the old list. Matching of IP Prefix is performed from the smaller sequential number to the larger. The matching will stop once any rule has been applied. In the case of no le or ge command, the prefix length must match exactly the length specified in the prefix list. -- Command: no ip prefix-list NAME * Menu: * ip prefix-list description:: * ip prefix-list sequential number control:: * Showing ip prefix-list:: * Clear counter of ip prefix-list::  File: quagga.info, Node: ip prefix-list description, Next: ip prefix-list sequential number control, Up: IP Prefix List 13.2.1 ip prefix-list description --------------------------------- -- Command: ip prefix-list NAME description DESC Descriptions may be added to prefix lists. This command adds a description to the prefix list. -- Command: no ip prefix-list NAME description [DESC] Deletes the description from a prefix list. It is possible to use the command without the full description.  File: quagga.info, Node: ip prefix-list sequential number control, Next: Showing ip prefix-list, Prev: ip prefix-list description, Up: IP Prefix List 13.2.2 ip prefix-list sequential number control ----------------------------------------------- -- Command: ip prefix-list sequence-number With this command, the IP prefix list sequential number is displayed. This is the default behavior. -- Command: no ip prefix-list sequence-number With this command, the IP prefix list sequential number is not displayed.  File: quagga.info, Node: Showing ip prefix-list, Next: Clear counter of ip prefix-list, Prev: ip prefix-list sequential number control, Up: IP Prefix List 13.2.3 Showing ip prefix-list ----------------------------- -- Command: show ip prefix-list Display all IP prefix lists. -- Command: show ip prefix-list NAME Show IP prefix list can be used with a prefix list name. -- Command: show ip prefix-list NAME seq NUM Show IP prefix list can be used with a prefix list name and sequential number. -- Command: show ip prefix-list NAME A.B.C.D/M If the command longer is used, all prefix lists with prefix lengths equal to or longer than the specified length will be displayed. If the command first match is used, the first prefix length match will be displayed. -- Command: show ip prefix-list NAME A.B.C.D/M longer -- Command: show ip prefix-list NAME A.B.C.D/M first-match -- Command: show ip prefix-list summary -- Command: show ip prefix-list summary NAME -- Command: show ip prefix-list detail -- Command: show ip prefix-list detail NAME  File: quagga.info, Node: Clear counter of ip prefix-list, Prev: Showing ip prefix-list, Up: IP Prefix List 13.2.4 Clear counter of ip prefix-list -------------------------------------- -- Command: clear ip prefix-list Clears the counters of all IP prefix lists. Clear IP Prefix List can be used with a specified name and prefix. -- Command: clear ip prefix-list NAME -- Command: clear ip prefix-list NAME A.B.C.D/M  File: quagga.info, Node: Route Map, Next: IPv6 Support, Prev: Filtering, Up: Top 14 Route Map ************ Route maps provide a means to both filter and/or apply actions to route, hence allowing policy to be applied to routes. * Menu: * Route Map Command:: * Route Map Match Command:: * Route Map Set Command:: * Route Map Call Command:: * Route Map Exit Action Command:: * Route Map Examples:: Route-maps are an ordered list of route-map entries. Each entry may specify up to four distincts sets of clauses: 'Matching Policy' This specifies the policy implied if the 'Matching Conditions' are met or not met, and which actions of the route-map are to be taken, if any. The two possibilities are: - 'permit': If the entry matches, then carry out the 'Set Actions'. Then finish processing the route-map, permitting the route, unless an 'Exit Action' indicates otherwise. - 'deny': If the entry matches, then finish processing the route-map and deny the route (return 'deny'). The 'Matching Policy' is specified as part of the command which defines the ordered entry in the route-map. See below. 'Matching Conditions' A route-map entry may, optionally, specify one or more conditions which must be matched if the entry is to be considered further, as governed by the Match Policy. If a route-map entry does not explicitely specify any matching conditions, then it always matches. 'Set Actions' A route-map entry may, optionally, specify one or more 'Set Actions' to set or modify attributes of the route. 'Call Action' Call to another route-map, after any 'Set Actions' have been carried out. If the route-map called returns 'deny' then processing of the route-map finishes and the route is denied, regardless of the 'Matching Policy' or the 'Exit Policy'. If the called route-map returns 'permit', then 'Matching Policy' and 'Exit Policy' govern further behaviour, as normal. 'Exit Policy' An entry may, optionally, specify an alternative 'Exit Policy' to take if the entry matched, rather than the normal policy of exiting the route-map and permitting the route. The two possibilities are: - 'next': Continue on with processing of the route-map entries. - 'goto N': Jump ahead to the first route-map entry whose order in the route-map is >= N. Jumping to a previous entry is not permitted. The default action of a route-map, if no entries match, is to deny. I.e. a route-map essentially has as its last entry an empty 'deny' entry, which matches all routes. To change this behaviour, one must specify an empty 'permit' entry as the last entry in the route-map. To summarise the above: Match No Match ----------------------------- _Permit_ action cont _Deny_ deny cont 'action' - Apply _set_ statements - If _call_ is present, call given route-map. If that returns a 'deny', finish processing and return 'deny'. - If 'Exit Policy' is _next_, goto next route-map entry - If 'Exit Policy' is _goto_, goto first entry whose order in the list is >= the given order. - Finish processing the route-map and permit the route. 'deny' - The route is denied by the route-map (return 'deny'). 'cont' - goto next route-map entry  File: quagga.info, Node: Route Map Command, Next: Route Map Match Command, Up: Route Map 14.1 Route Map Command ====================== -- Command: route-map ROUTE-MAP-NAME (permit|deny) ORDER Configure the ORDER'th entry in ROUTE-MAP-NAME with 'Match Policy' of either _permit_ or _deny_.  File: quagga.info, Node: Route Map Match Command, Next: Route Map Set Command, Prev: Route Map Command, Up: Route Map 14.2 Route Map Match Command ============================ -- Route-map Command: match ip address ACCESS_LIST Matches the specified ACCESS_LIST -- Route-map Command: match ip next-hop IPV4_ADDR Matches the specified IPV4_ADDR. -- Route-map Command: match aspath AS_PATH Matches the specified AS_PATH. -- Route-map Command: match metric METRIC Matches the specified METRIC. -- Route-map Command: match community COMMUNITY_LIST Matches the specified COMMUNITY_LIST  File: quagga.info, Node: Route Map Set Command, Next: Route Map Call Command, Prev: Route Map Match Command, Up: Route Map 14.3 Route Map Set Command ========================== -- Route-map Command: set ip next-hop IPV4_ADDRESS Set the BGP nexthop address. -- Route-map Command: set local-preference LOCAL_PREF Set the BGP local preference. -- Route-map Command: set weight WEIGHT Set the route's weight. -- Route-map Command: set metric METRIC Set the BGP attribute MED. -- Route-map Command: set as-path prepend AS_PATH Set the BGP AS path to prepend. -- Route-map Command: set community COMMUNITY Set the BGP community attribute. -- Route-map Command: set ipv6 next-hop global IPV6_ADDRESS Set the BGP-4+ global IPv6 nexthop address. -- Route-map Command: set ipv6 next-hop local IPV6_ADDRESS Set the BGP-4+ link local IPv6 nexthop address.  File: quagga.info, Node: Route Map Call Command, Next: Route Map Exit Action Command, Prev: Route Map Set Command, Up: Route Map 14.4 Route Map Call Command =========================== -- Route-map Command: call NAME Call route-map NAME. If it returns deny, deny the route and finish processing the route-map.  File: quagga.info, Node: Route Map Exit Action Command, Next: Route Map Examples, Prev: Route Map Call Command, Up: Route Map 14.5 Route Map Exit Action Command ================================== -- Route-map Command: on-match next -- Route-map Command: continue Proceed on to the next entry in the route-map. -- Route-map Command: on-match goto N -- Route-map Command: continue N Proceed processing the route-map at the first entry whose order is >= N  File: quagga.info, Node: Route Map Examples, Prev: Route Map Exit Action Command, Up: Route Map 14.6 Route Map Examples ======================= A simple example of a route-map: route-map test permit 10 match ip address 10 set local-preference 200 This means that if a route matches ip access-list number 10 it's local-preference value is set to 200. See *note BGP Configuration Examples:: for examples of more sophisticated useage of route-maps, including of the 'call' action.  File: quagga.info, Node: IPv6 Support, Next: Kernel Interface, Prev: Route Map, Up: Top 15 IPv6 Support *************** Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, Babel and BGP-4+. You can give IPv6 addresses to an interface and configure static IPv6 routing information. Quagga IPv6 also provides automatic address configuration via a feature called 'address auto configuration'. To do it, the router must send router advertisement messages to the all nodes that exist on the network. * Menu: * Router Advertisement::  File: quagga.info, Node: Router Advertisement, Up: IPv6 Support 15.1 Router Advertisement ========================= -- Interface Command: no ipv6 nd suppress-ra Send router advertisment messages. -- Interface Command: ipv6 nd suppress-ra Don't send router advertisment messages. -- Interface Command: ipv6 nd prefix IPV6PREFIX [VALID-LIFETIME] [PREFERRED-LIFETIME] [off-link] [no-autoconfig] [router-address] Configuring the IPv6 prefix to include in router advertisements. Several prefix specific optional parameters and flags may follow: * VALID-LIFETIME - the length of time in seconds during what the prefix is valid for the purpose of on-link determination. Value INFINITE represents infinity (i.e. a value of all one bits ('0xffffffff')). Range: '<0-4294967295>' Default: '2592000' * PREFERRED-LIFETIME - the length of time in seconds during what addresses generated from the prefix remain preferred. Value INFINITE represents infinity. Range: '<0-4294967295>' Default: '604800' * OFF-LINK - indicates that advertisement makes no statement about on-link or off-link properties of the prefix. Default: not set, i.e. this prefix can be used for on-link determination. * NO-AUTOCONFIG - indicates to hosts on the local link that the specified prefix cannot be used for IPv6 autoconfiguration. Default: not set, i.e. prefix can be used for autoconfiguration. * ROUTER-ADDRESS - indicates to hosts on the local link that the specified prefix contains a complete IP address by setting R flag. Default: not set, i.e. hosts do not assume a complete IP address is placed. -- Interface Command: ipv6 nd ra-interval <1-1800> -- Interface Command: no ipv6 nd ra-interval [<1-1800>] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in seconds. Default: '600' -- Interface Command: ipv6 nd ra-interval msec <70-1800000> -- Interface Command: no ipv6 nd ra-interval [msec <70-1800000>] The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in milliseconds. Default: '600000' -- Interface Command: ipv6 nd ra-lifetime <0-9000> -- Interface Command: no ipv6 nd ra-lifetime [<0-9000>] The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router as a default router on this interface. Setting the value to zero indicates that the router should not be considered a default router on this interface. Must be either zero or between value specified with IPV6 ND RA-INTERVAL (or default) and 9000 seconds. Default: '1800' -- Interface Command: ipv6 nd reachable-time <1-3600000> -- Interface Command: no ipv6 nd reachable-time [<1-3600000>] The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured time enables the router to detect unavailable neighbors. The value zero means unspecified (by this router). Default: '0' -- Interface Command: ipv6 nd managed-config-flag -- Interface Command: no ipv6 nd managed-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use managed (stateful) protocol for addresses autoconfiguration in addition to any addresses autoconfigured using stateless address autoconfiguration. Default: not set -- Interface Command: ipv6 nd other-config-flag -- Interface Command: no ipv6 nd other-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use administered (stateful) protocol to obtain autoconfiguration information other than addresses. Default: not set -- Interface Command: ipv6 nd home-agent-config-flag -- Interface Command: no ipv6 nd home-agent-config-flag Set/unset flag in IPv6 router advertisements which indicates to hosts that the router acts as a Home Agent and includes a Home Agent Option. Default: not set -- Interface Command: ipv6 nd home-agent-preference <0-65535> -- Interface Command: no ipv6 nd home-agent-preference [<0-65535>] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent preference. The default value of 0 stands for the lowest preference possible. Default: 0 -- Interface Command: ipv6 nd home-agent-lifetime <0-65520> -- Interface Command: no ipv6 nd home-agent-lifetime [<0-65520>] The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to place the current Router Lifetime value. Default: 0 -- Interface Command: ipv6 nd adv-interval-option -- Interface Command: no ipv6 nd adv-interval-option Include an Advertisement Interval option which indicates to hosts the maximum time, in milliseconds, between successive unsolicited Router Advertisements. Default: not set -- Interface Command: ipv6 nd router-preference (high|medium|low) -- Interface Command: no ipv6 nd router-preference [(high|medium|low)] Set default router preference in IPv6 router advertisements per RFC4191. Default: medium -- Interface Command: ipv6 nd mtu <1-65535> -- Interface Command: no ipv6 nd mtu [<1-65535>] Include an MTU (type 5) option in each RA packet to assist the attached hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. Default: don't advertise any MTU option interface eth0 no ipv6 nd suppress-ra ipv6 nd prefix 2001:0DB8:5009::/64 For more information see 'RFC2462 (IPv6 Stateless Address Autoconfiguration)' , 'RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))' , 'RFC6275 (Mobility Support in IPv6)' and 'RFC4191 (Default Router Preferences and More-Specific Routes)'.  File: quagga.info, Node: Kernel Interface, Next: SNMP Support, Prev: IPv6 Support, Up: Top 16 Kernel Interface ******************* There are several different methods for reading kernel routing table information, updating kernel routing tables, and for looking up interfaces. 'ioctl' The 'ioctl' method is a very traditional way for reading or writing kernel information. 'ioctl' can be used for looking up interfaces and for modifying interface addresses, flags, mtu settings and other types of information. Also, 'ioctl' can insert and delete kernel routing table entries. It will soon be available on almost any platform which zebra supports, but it is a little bit ugly thus far, so if a better method is supported by the kernel, zebra will use that. 'sysctl' 'sysctl' can lookup kernel information using MIB (Management Information Base) syntax. Normally, it only provides a way of getting information from the kernel. So one would usually want to change kernel information using another method such as 'ioctl'. 'proc filesystem' 'proc filesystem' provides an easy way of getting kernel information. 'routing socket' 'netlink' On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user communication support called 'netlink'. It makes asynchronous communication between kernel and Quagga possible, similar to a routing socket on BSD systems. Before you use this feature, be sure to select (in kernel configuration) the kernel/netlink support option 'Kernel/User network link driver' and 'Routing messages'. Today, the /dev/route special device file is obsolete. Netlink communication is done by reading/writing over netlink socket. After the kernel configuration, please reconfigure and rebuild Quagga. You can use netlink as a dynamic routing update channel between Quagga and the kernel.  File: quagga.info, Node: SNMP Support, Next: Zebra Protocol, Prev: Kernel Interface, Up: Top 17 SNMP Support *************** SNMP (Simple Network Managing Protocol) is a widely implemented feature for collecting network information from router and/or host. Quagga itself does not support SNMP agent (server daemon) functionality but is able to connect to a SNMP agent using the SMUX protocol ('RFC1227') or the AgentX protocol ('RFC2741') and make the routing protocol MIBs available through it. * Menu: * Getting and installing an SNMP agent:: * AgentX configuration:: * SMUX configuration:: * MIB and command reference:: * Handling SNMP Traps::  File: quagga.info, Node: Getting and installing an SNMP agent, Next: AgentX configuration, Up: SNMP Support 17.1 Getting and installing an SNMP agent ========================================= There are several SNMP agent which support SMUX or AgentX. We recommend to use the latest version of 'net-snmp' which was formerly known as 'ucd-snmp'. It is free and open software and available at and as binary package for most Linux distributions. 'net-snmp' has to be compiled with '--with-mib-modules=agentx' to be able to accept connections from Quagga using AgentX protocol or with '--with-mib-modules=smux' to use SMUX protocol. Nowadays, SMUX is a legacy protocol. The AgentX protocol should be preferred for any new deployment. Both protocols have the same coverage.  File: quagga.info, Node: AgentX configuration, Next: SMUX configuration, Prev: Getting and installing an SNMP agent, Up: SNMP Support 17.2 AgentX configuration ========================= To enable AgentX protocol support, Quagga must have been build with the '--enable-snmp' or '--enable-snmp=agentx' option. Both the master SNMP agent (snmpd) and each of the Quagga daemons must be configured. In '/etc/snmp/snmpd.conf', 'master agentx' directive should be added. In each of the Quagga daemons, 'agentx' command will enable AgentX support. /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # enable master agent for AgentX subagents # master agentx /etc/quagga/ospfd.conf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! agentx ! Upon successful connection, you should get something like this in the log of each Quagga daemons: 2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected Then, you can use the following command to check everything works as expected: # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 [...] The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If need to configure Quagga to use another transport, you can configure it through '/etc/snmp/quagga.conf': /etc/snmp/quagga.conf: [snmpd] # Use a remote master agent agentXSocket tcp:192.168.15.12:705  File: quagga.info, Node: SMUX configuration, Next: MIB and command reference, Prev: AgentX configuration, Up: SNMP Support 17.3 SMUX configuration ======================= To enable SMUX protocol support, Quagga must have been build with the '--enable-snmp=smux' option. A separate connection has then to be established between the SNMP agent (snmpd) and each of the Quagga daemons. This connections each use different OID numbers and passwords. Be aware that this OID number is not the one that is used in queries by clients, it is solely used for the intercommunication of the daemons. In the following example the ospfd daemon will be connected to the snmpd daemon using the password "quagga_ospfd". For testing it is recommending to take exactly the below snmpd.conf as wrong access restrictions can be hard to debug. /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # the following line is relevant for Quagga # smuxpeer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd /etc/quagga/ospf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! smux peer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd ! After restarting snmpd and quagga, a successful connection can be verified in the syslog and by querying the SNMP daemon: snmpd[12300]: [smux_accept] accepted fd 12 from 127.0.0.1:36255 snmpd[12300]: accepted smux peer: \ oid GNOME-PRODUCT-ZEBRA-MIB::ospfd, quagga-0.96.5 # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 Be warned that the current version (5.1.1) of the Net-SNMP daemon writes a line for every SNMP connect to the syslog which can lead to enormous log file sizes. If that is a problem you should consider to patch snmpd and comment out the troublesome 'snmp_log()' line in the function 'netsnmp_agent_check_packet()' in 'agent/snmp_agent.c'.  File: quagga.info, Node: MIB and command reference, Next: Handling SNMP Traps, Prev: SMUX configuration, Up: SNMP Support 17.4 MIB and command reference ============================== The following OID numbers are used for the interprocess communication of snmpd and the Quagga daemons with SMUX only. (OIDs below .iso.org.dod.internet.private.enterprises) zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv bgpd .1.3.6.1.4.1.3317.1.2.2 .gnome.gnomeProducts.zebra.bgpd ripd .1.3.6.1.4.1.3317.1.2.3 .gnome.gnomeProducts.zebra.ripd ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d Sadly, SNMP has not been implemented in all daemons yet. The following OID numbers are used for querying the SNMP daemon by a client: zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf bgpd .1.3.6.1.2.1.15 .iso.org.dot.internet.mgmt.mib-2.bgp ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2 ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3 The following syntax is understood by the Quagga daemons for configuring SNMP using SMUX: -- Command: smux peer OID -- Command: no smux peer OID -- Command: smux peer OID PASSWORD -- Command: no smux peer OID PASSWORD Here is the syntax for using AgentX: -- Command: agentx -- Command: no agentx  File: quagga.info, Node: Handling SNMP Traps, Prev: MIB and command reference, Up: SNMP Support 17.5 Handling SNMP Traps ======================== To handle snmp traps make sure your snmp setup of quagga works correctly as described in the quagga documentation in *Note SNMP Support::. The BGP4 mib will send traps on peer up/down events. These should be visible in your snmp logs with a message similar to: 'snmpd[13733]: Got trap from peer on fd 14' To react on these traps they should be handled by a trapsink. Configure your trapsink by adding the following lines to '/etc/snmpd/snmpd.conf': # send traps to the snmptrapd on localhost trapsink localhost This will send all traps to an snmptrapd running on localhost. You can of course also use a dedicated management station to catch traps. Configure the snmptrapd daemon by adding the following line to '/etc/snmpd/snmptrapd.conf': traphandle .1.3.6.1.4.1.3317.1.2.2 /etc/snmp/snmptrap_handle.sh This will use the bash script '/etc/snmp/snmptrap_handle.sh' to handle the BGP4 traps. To add traps for other protocol daemons, lookup their appropriate OID from their mib. (For additional information about which traps are supported by your mib, lookup the mib on ). Make sure snmptrapd is started. The snmptrap_handle.sh script I personally use for handling BGP4 traps is below. You can of course do all sorts of things when handling traps, like sound a siren, have your display flash, etc., be creative ;). #!/bin/bash # routers name ROUTER=`hostname -s` #email address use to sent out notification EMAILADDR="john@doe.com" #email address used (allongside above) where warnings should be sent EMAILADDR_WARN="sms-john@doe.com" # type of notification TYPE="Notice" # local snmp community for getting AS belonging to peer COMMUNITY="" # if a peer address is in $WARN_PEERS a warning should be sent WARN_PEERS="192.0.2.1" # get stdin INPUT=`cat -` # get some vars from stdin uptime=`echo $INPUT | cut -d' ' -f5` peer=`echo $INPUT | cut -d' ' -f8 | sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` peerstate=`echo $INPUT | cut -d' ' -f13` errorcode=`echo $INPUT | cut -d' ' -f9 | sed -e 's/\"//g'` suberrorcode=`echo $INPUT | cut -d' ' -f10 | sed -e 's/\"//g'` remoteas=`snmpget -v2c -c $COMMUNITY localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer | cut -d' ' -f4` WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | egrep '(as-name|descr)'` asname=`echo "$WHOISINFO" | grep "^as-name:" | sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` asdescr=`echo "$WHOISINFO" | grep "^descr:" | sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` # if peer address is in $WARN_PEER, the email should also # be sent to $EMAILADDR_WARN for ip in $WARN_PEERS; do if [ "x$ip" == "x$peer" ]; then EMAILADDR="$EMAILADDR,$EMAILADDR_WARN" TYPE="WARNING" break fi done # convert peer state case "$peerstate" in 1) peerstate="Idle" ;; 2) peerstate="Connect" ;; 3) peerstate="Active" ;; 4) peerstate="Opensent" ;; 5) peerstate="Openconfirm" ;; 6) peerstate="Established" ;; *) peerstate="Unknown" ;; esac # get textual messages for errors case "$errorcode" in 00) error="No error" suberror="" ;; 01) error="Message Header Error" case "$suberrorcode" in 01) suberror="Connection Not Synchronized" ;; 02) suberror="Bad Message Length" ;; 03) suberror="Bad Message Type" ;; *) suberror="Unknown" ;; esac ;; 02) error="OPEN Message Error" case "$suberrorcode" in 01) suberror="Unsupported Version Number" ;; 02) suberror="Bad Peer AS" ;; 03) suberror="Bad BGP Identifier" ;; 04) suberror="Unsupported Optional Parameter" ;; 05) suberror="Authentication Failure" ;; 06) suberror="Unacceptable Hold Time" ;; *) suberror="Unknown" ;; esac ;; 03) error="UPDATE Message Error" case "$suberrorcode" in 01) suberror="Malformed Attribute List" ;; 02) suberror="Unrecognized Well-known Attribute" ;; 03) suberror="Missing Well-known Attribute" ;; 04) suberror="Attribute Flags Error" ;; 05) suberror="Attribute Length Error" ;; 06) suberror="Invalid ORIGIN Attribute" ;; 07) suberror="AS Routing Loop" ;; 08) suberror="Invalid NEXT_HOP Attribute" ;; 09) suberror="Optional Attribute Error" ;; 10) suberror="Invalid Network Field" ;; 11) suberror="Malformed AS_PATH" ;; *) suberror="Unknown" ;; esac ;; 04) error="Hold Timer Expired" suberror="" ;; 05) error="Finite State Machine Error" suberror="" ;; 06) error="Cease" case "$suberrorcode" in 01) suberror="Maximum Number of Prefixes Reached" ;; 02) suberror="Administratively Shutdown" ;; 03) suberror="Peer Unconfigured" ;; 04) suberror="Administratively Reset" ;; 05) suberror="Connection Rejected" ;; 06) suberror="Other Configuration Change" ;; 07) suberror="Connection collision resolution" ;; 08) suberror="Out of Resource" ;; 09) suberror="MAX" ;; *) suberror="Unknown" ;; esac ;; *) error="Unknown" suberror="" ;; esac # create textual message from errorcodes if [ "x$suberror" == "x" ]; then NOTIFY="$errorcode ($error)" else NOTIFY="$errorcode/$suberrorcode ($error/$suberror)" fi # form a decent subject SUBJECT="$TYPE: $ROUTER [bgp] $peer is $peerstate: $NOTIFY" # create the email body MAIL=`cat << EOF BGP notification on router $ROUTER. Peer: $peer AS: $remoteas New state: $peerstate Notification: $NOTIFY Info: $asname $asdescr Snmpd uptime: $uptime EOF` # mail the notification echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR  File: quagga.info, Node: Zebra Protocol, Next: Packet Binary Dump Format, Prev: SNMP Support, Up: Top Appendix A Zebra Protocol ************************* A.1 Overview of the Zebra Protocol ================================== Zebra Protocol is used by protocol daemons to communicate with the zebra daemon. Each protocol daemon may request and send information to and from the zebra daemon such as interface states, routing state, nexthop-validation, and so on. Protocol daemons may also install routes with zebra. The zebra daemon manages which route is installed into the forwarding table with the kernel. Zebra Protocol is a streaming protocol, with a common header. Two versions of the header are in use. Version 0 is implicitely versioned. Version 1 has an explicit version field. Version 0 can be distinguished from all other versions by examining the 3rd byte of the header, which contains a marker value for all versions bar version 0. The marker byte corresponds to the command field in version 0, and the marker value is a reserved command in version 0. We do not anticipate there will be further versions of the header for the foreseeable future, as the command field in version 1 is wide enough to allow for future extensions to done compatibly through seperate commands. Version 0 is used by all versions of GNU Zebra as of this writing, and versions of Quagga up to and including Quagga 0.98. Version 1 will be used as of Quagga 1.0. A.2 Zebra Protocol Definition ============================= A.2.1 Zebra Protocol Header (version 0) --------------------------------------- 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-------------------------------+---------------+ | Length (2) | Command (1) | +-------------------------------+---------------+ A.2.2 Zebra Protocol Common Header (version 1) ---------------------------------------------- 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-------------------------------+---------------+-------------+ | Length (2) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | Command (2) | +-------------------------------+ A.2.3 Zebra Protocol Header Field Definitions --------------------------------------------- 'Length' Total packet length including this header. The minimum length is 3 bytes for version 0 messages and 6 bytes for version 1 messages. 'Marker' Static marker with a value of 255 always. This is to allow version 0 Zserv headers (which do not include version explicitely) to be distinguished from versioned headers. Not present in version 0 messages. 'Version' Version number of the Zserv message. Clients should not continue processing messages past the version field for versions they do not recognise. Not present in version 0 messages. 'Command' The Zebra Protocol command. A.2.4 Zebra Protocol Commands ----------------------------- Command Value ----------------------------------------------------- ZEBRA_INTERFACE_ADD 1 ZEBRA_INTERFACE_DELETE 2 ZEBRA_INTERFACE_ADDRESS_ADD 3 ZEBRA_INTERFACE_ADDRESS_DELETE 4 ZEBRA_INTERFACE_UP 5 ZEBRA_INTERFACE_DOWN 6 ZEBRA_IPV4_ROUTE_ADD 7 ZEBRA_IPV4_ROUTE_DELETE 8 ZEBRA_IPV6_ROUTE_ADD 9 ZEBRA_IPV6_ROUTE_DELETE 10 ZEBRA_REDISTRIBUTE_ADD 11 ZEBRA_REDISTRIBUTE_DELETE 12 ZEBRA_REDISTRIBUTE_DEFAULT_ADD 13 ZEBRA_REDISTRIBUTE_DEFAULT_DELETE 14 ZEBRA_IPV4_NEXTHOP_LOOKUP 15 ZEBRA_IPV6_NEXTHOP_LOOKUP 16  File: quagga.info, Node: Packet Binary Dump Format, Next: Command Index, Prev: Zebra Protocol, Up: Top Appendix B Packet Binary Dump Format ************************************ Quagga can dump routing protocol packet into file with a binary format (*note Dump BGP packets and table::). It seems to be better that we share the MRT's header format for backward compatibility with MRT's dump logs. We should also define the binary format excluding the header, because we must support both IP v4 and v6 addresses as socket addresses and / or routing entries. In the last meeting, we discussed to have a version field in the header. But Masaki told us that we can define new 'type' value rather than having a 'version' field, and it seems to be better because we don't need to change header format. Here is the common header format. This is same as that of MRT. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Subtype | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP (version 4) 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where State is the value defined in RFC1771. If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP version 6 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_MESSAGE, and Address Family == IP (version 4) 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Where BGP Message Packet is the whole contents of the BGP4 message including header portion. If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_MESSAGE, and Address Family == IP version 6 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_ENTRY, and Address Family == IP (version 4) 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ If 'type' is PROTOCOL_BGP4MP, 'subtype' is BGP4MP_ENTRY, and Address Family == IP version 6 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Prefix (cont'd) [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ BGP4 Attribute must not contain MP_UNREACH_NLRI. If BGP Attribute has MP_REACH_NLRI field, it must has zero length NLRI, e.g., MP_REACH_NLRI has only Address Family, SAFI and next-hop values. If 'type' is PROTOCOL_BGP4MP and 'subtype' is BGP4MP_SNAPSHOT, 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | File Name [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ The file specified in "File Name" contains all routing entries, which are in the format of "subtype == BGP4MP_ENTRY". Constants: /* type value */ #define MSG_PROTOCOL_BGP4MP 16 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3  File: quagga.info, Node: Command Index, Next: VTY Key Index, Prev: Packet Binary Dump Format, Up: Top Command Index ************* [index] * Menu: * access-class ACCESS-LIST: Basic Config Commands. (line 140) * access-list NAME deny IPV4-NETWORK: IP Access List. (line 7) * access-list NAME permit IPV4-NETWORK: IP Access List. (line 6) * agentx: MIB and command reference. (line 32) * aggregate-address A.B.C.D/M: Route Aggregation. (line 6) * aggregate-address A.B.C.D/M as-set: Route Aggregation. (line 9) * aggregate-address A.B.C.D/M summary-only: Route Aggregation. (line 13) * area <0-4294967295> authentication: OSPF area. (line 125) * area <0-4294967295> authentication message-digest: OSPF area. (line 132) * area <0-4294967295> export-list NAME: OSPF area. (line 84) * area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 115) * area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 116) * area <0-4294967295> import-list NAME: OSPF area. (line 107) * area <0-4294967295> range A.B.C.D/M: OSPF area. (line 7) * area <0-4294967295> shortcut: OSPF area. (line 54) * area <0-4294967295> stub: OSPF area. (line 61) * area <0-4294967295> stub no-summary: OSPF area. (line 73) * area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 49) * area A.B.C.D authentication: OSPF area. (line 124) * area A.B.C.D authentication message-digest: OSPF area. (line 131) * area A.B.C.D default-cost <0-16777215>: OSPF area. (line 79) * area A.B.C.D export-list NAME: OSPF area. (line 83) * area A.B.C.D filter-list prefix NAME in: OSPF area. (line 113) * area A.B.C.D filter-list prefix NAME out: OSPF area. (line 114) * area A.B.C.D import-list NAME: OSPF area. (line 106) * area A.B.C.D range A.B.C.D/M: OSPF area. (line 6) * area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 27) * area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 33) * area A.B.C.D shortcut: OSPF area. (line 53) * area A.B.C.D stub: OSPF area. (line 60) * area A.B.C.D stub no-summary: OSPF area. (line 72) * area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 48) * auto-cost reference-bandwidth <1-4294967>: OSPF router. (line 161) * auto-cost reference-bandwidth COST: OSPF6 router. (line 49) * babel hello-interval <20-655340>: Babel configuration. (line 28) * babel resend-delay <20-655340>: Babel configuration. (line 40) * babel split-horizon: Babel configuration. (line 21) * babel update-interval <20-655340>: Babel configuration. (line 34) * babel wired: Babel configuration. (line 14) * babel wireless: Babel configuration. (line 15) * bandwidth <1-10000000>: Interface Commands. (line 30) * banner motd default: Basic Config Commands. (line 122) * bgp bestpath as-path confed: BGP decision process. (line 18) * bgp bestpath as-path multipath-relax: BGP decision process. (line 23) * bgp cluster-id A.B.C.D: Route Reflector. (line 6) * bgp config-type cisco: Multiple instance. (line 19) * bgp config-type zebra: Multiple instance. (line 52) * bgp dampening <1-45> <1-20000> <1-20000> <1-255>: BGP route flap dampening. (line 6) * bgp multiple-instance: Multiple instance. (line 9) * bgp router-id A.B.C.D: BGP router. (line 21) * call NAME: Route Map Call Command. (line 6) * call WORD: Commands for configuring a Route Server. (line 51) * clear ip bgp PEER: More Show IP BGP. (line 24) * clear ip bgp PEER soft in: More Show IP BGP. (line 27) * clear ip prefix-list: Clear counter of ip prefix-list. (line 6) * clear ip prefix-list NAME: Clear counter of ip prefix-list. (line 10) * clear ip prefix-list NAME A.B.C.D/M: Clear counter of ip prefix-list. (line 12) * clear zebra fpm stats: zebra Terminal Mode Commands. (line 40) * configure terminal: Terminal Mode Commands. (line 12) * continue: Route Map Exit Action Command. (line 7) * continue N: Route Map Exit Action Command. (line 11) * debug babel KIND: Babel debugging commands. (line 6) * debug event: More Show IP BGP. (line 38) * debug keepalive: More Show IP BGP. (line 42) * debug ospf ism: Debugging OSPF. (line 13) * debug ospf ism (status|events|timers): Debugging OSPF. (line 14) * debug ospf lsa: Debugging OSPF. (line 23) * debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 24) * debug ospf nsm: Debugging OSPF. (line 18) * debug ospf nsm (status|events|timers): Debugging OSPF. (line 19) * debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 6) * debug ospf zebra: Debugging OSPF. (line 28) * debug ospf zebra (interface|redistribute): Debugging OSPF. (line 29) * debug rip events: RIP Debug Commands. (line 8) * debug rip packet: RIP Debug Commands. (line 14) * debug rip zebra: RIP Debug Commands. (line 21) * debug ripng events: ripngd Terminal Mode Commands. (line 10) * debug ripng packet: ripngd Terminal Mode Commands. (line 12) * debug ripng zebra: ripngd Terminal Mode Commands. (line 14) * debug update: More Show IP BGP. (line 40) * default-information originate: How to Announce RIP route. (line 50) * default-information originate <1>: Redistribute routes to OSPF. (line 36) * default-information originate always: Redistribute routes to OSPF. (line 42) * default-information originate always metric <0-16777214>: Redistribute routes to OSPF. (line 43) * default-information originate always metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 45) * default-information originate always metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 47) * default-information originate metric <0-16777214>: Redistribute routes to OSPF. (line 37) * default-information originate metric <0-16777214> metric-type (1|2): Redistribute routes to OSPF. (line 38) * default-information originate metric <0-16777214> metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 40) * default-metric <0-16777214>: Redistribute routes to OSPF. (line 64) * default-metric <1-16>: RIP Metric Manipulation. (line 10) * description DESCRIPTION ...: Interface Commands. (line 23) * distance <1-255>: RIP distance. (line 8) * distance <1-255> <1>: Redistribute routes to OSPF. (line 67) * distance <1-255> A.B.C.D/M: RIP distance. (line 12) * distance <1-255> A.B.C.D/M <1>: BGP distance. (line 11) * distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 17) * distance <1-255> A.B.C.D/M WORD: BGP distance. (line 12) * distance bgp <1-255> <1-255> <1-255>: BGP distance. (line 6) * distance ospf (intra-area|inter-area|external) <1-255>: Redistribute routes to OSPF. (line 70) * distribute-list ACCESS_LIST (in|out) IFNAME: ripngd Filtering Commands. (line 6) * distribute-list ACCESS_LIST DIRECT IFNAME: Filtering RIP Routes. (line 8) * distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 56) * distribute-list prefix PREFIX_LIST (in|out) IFNAME: Filtering RIP Routes. (line 31) * dump bgp all PATH: Dump BGP packets and table. (line 6) * dump bgp all PATH INTERVAL: Dump BGP packets and table. (line 7) * dump bgp routes PATH: Dump BGP packets and table. (line 14) * dump bgp routes PATH <1>: Dump BGP packets and table. (line 15) * dump bgp updates PATH: Dump BGP packets and table. (line 10) * dump bgp updates PATH INTERVAL: Dump BGP packets and table. (line 11) * enable password PASSWORD: Basic Config Commands. (line 13) * exec-timeout MINUTE: Basic Config Commands. (line 128) * exec-timeout MINUTE SECOND: Basic Config Commands. (line 129) * flush_timer TIME: ripngd Configuration. (line 11) * hostname HOSTNAME: Basic Config Commands. (line 6) * interface IFNAME: Interface Commands. (line 6) * interface IFNAME area AREA: OSPF6 router. (line 11) * ip address ADDRESS/PREFIX: Interface Commands. (line 12) * ip address ADDRESS/PREFIX secondary: Interface Commands. (line 18) * ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 8) * ip community-list <1-99> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 13) * ip community-list <100-199> {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 19) * ip community-list expanded NAME {permit|deny} LINE: BGP Community Lists. (line 29) * ip community-list NAME {permit|deny} COMMUNITY: Numbered BGP Community Lists. (line 24) * ip community-list standard NAME {permit|deny} COMMUNITY: BGP Community Lists. (line 19) * ip extcommunity-list expanded NAME {permit|deny} LINE: BGP Extended Community Lists. (line 20) * ip extcommunity-list standard NAME {permit|deny} EXTCOMMUNITY: BGP Extended Community Lists. (line 8) * ip mroute PREFIX NEXTHOP [DISTANCE]: Multicast RIB Commands. (line 70) * ip multicast rpf-lookup-mode MODE: Multicast RIB Commands. (line 18) * ip ospf authentication message-digest: OSPF interface. (line 16) * ip ospf authentication-key AUTH_KEY: OSPF interface. (line 6) * ip ospf cost <1-65535>: OSPF interface. (line 44) * ip ospf dead-interval <1-65535>: OSPF interface. (line 49) * ip ospf dead-interval minimal hello-multiplier <2-20>: OSPF interface. (line 50) * ip ospf hello-interval <1-65535>: OSPF interface. (line 68) * ip ospf message-digest-key KEYID md5 KEY: OSPF interface. (line 32) * ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point): OSPF interface. (line 78) * ip ospf priority <0-255>: OSPF interface. (line 83) * ip ospf retransmit-interval <1-65535>: OSPF interface. (line 90) * ip ospf transmit-delay: OSPF interface. (line 96) * ip prefix-list NAME (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 15) * ip prefix-list NAME description DESC: ip prefix-list description. (line 6) * ip prefix-list NAME seq NUMBER (permit|deny) PREFIX [le LEN] [ge LEN]: IP Prefix List. (line 16) * ip prefix-list sequence-number: ip prefix-list sequential number control. (line 6) * ip protocol PROTOCOL route-map ROUTEMAP: zebra Route Filtering. (line 11) * ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 42) * ip rip authentication mode md5: RIP Authentication. (line 28) * ip rip authentication mode text: RIP Authentication. (line 32) * ip rip authentication string STRING: RIP Authentication. (line 36) * ip rip receive version VERSION: RIP Version Control. (line 43) * ip rip send version VERSION: RIP Version Control. (line 32) * ip route NETWORK GATEWAY: Static Route Commands. (line 9) * ip route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 35) * ip route NETWORK NETMASK GATEWAY: Static Route Commands. (line 24) * ip split-horizon: RIP Configuration. (line 69) * ipv6 address ADDRESS/PREFIX: Interface Commands. (line 13) * ipv6 nd adv-interval-option: Router Advertisement. (line 126) * ipv6 nd home-agent-config-flag: Router Advertisement. (line 101) * ipv6 nd home-agent-lifetime <0-65520>: Router Advertisement. (line 117) * ipv6 nd home-agent-preference <0-65535>: Router Advertisement. (line 109) * ipv6 nd managed-config-flag: Router Advertisement. (line 84) * ipv6 nd mtu <1-65535>: Router Advertisement. (line 141) * ipv6 nd other-config-flag: Router Advertisement. (line 93) * ipv6 nd prefix IPV6PREFIX [VALID-LIFETIME] [PREFERRED-LIFETIME] [off-link] [no-autoconfig] [router-address]: Router Advertisement. (line 12) * ipv6 nd ra-interval <1-1800>: Router Advertisement. (line 49) * ipv6 nd ra-interval msec <70-1800000>: Router Advertisement. (line 56) * ipv6 nd ra-lifetime <0-9000>: Router Advertisement. (line 63) * ipv6 nd reachable-time <1-3600000>: Router Advertisement. (line 75) * ipv6 nd router-preference (high|medium|low): Router Advertisement. (line 134) * ipv6 nd suppress-ra: Router Advertisement. (line 9) * ipv6 ospf6 cost COST: OSPF6 interface. (line 6) * ipv6 ospf6 dead-interval DEADINTERVAL: OSPF6 interface. (line 13) * ipv6 ospf6 hello-interval HELLOINTERVAL: OSPF6 interface. (line 10) * ipv6 ospf6 network (broadcast|point-to-point): OSPF6 interface. (line 25) * ipv6 ospf6 priority PRIORITY: OSPF6 interface. (line 19) * ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL: OSPF6 interface. (line 16) * ipv6 ospf6 transmit-delay TRANSMITDELAY: OSPF6 interface. (line 22) * ipv6 route NETWORK GATEWAY: Static Route Commands. (line 76) * ipv6 route NETWORK GATEWAY DISTANCE: Static Route Commands. (line 77) * line vty: Basic Config Commands. (line 119) * link-detect: Interface Commands. (line 36) * list: Terminal Mode Commands. (line 23) * log facility FACILITY: Basic Config Commands. (line 79) * log file FILENAME: Basic Config Commands. (line 39) * log file FILENAME LEVEL: Basic Config Commands. (line 40) * log monitor: Basic Config Commands. (line 66) * log monitor LEVEL: Basic Config Commands. (line 67) * log record-priority: Basic Config Commands. (line 85) * log stdout: Basic Config Commands. (line 27) * log stdout LEVEL: Basic Config Commands. (line 28) * log syslog: Basic Config Commands. (line 57) * log syslog LEVEL: Basic Config Commands. (line 58) * log timestamp precision <0-6>: Basic Config Commands. (line 95) * log trap LEVEL: Basic Config Commands. (line 16) * log-adjacency-changes [detail]: OSPF router. (line 71) * logmsg LEVEL MESSAGE: Terminal Mode Commands. (line 33) * match as-path WORD: Using AS Path in Route Map. (line 6) * match aspath AS_PATH: Route Map Match Command. (line 12) * match community COMMUNITY_LIST: Route Map Match Command. (line 18) * match community WORD: BGP Community in Route Map. (line 12) * match community WORD exact-match: BGP Community in Route Map. (line 13) * match extcommunity WORD: BGP Extended Communities in Route Map. (line 6) * match interface WORD: RIP route-map. (line 25) * match ip address ACCESS_LIST: Route Map Match Command. (line 6) * match ip address prefix-list WORD: RIP route-map. (line 38) * match ip address WORD: RIP route-map. (line 37) * match ip next-hop IPV4_ADDR: Route Map Match Command. (line 9) * match ip next-hop prefix-list WORD: RIP route-map. (line 42) * match ip next-hop WORD: RIP route-map. (line 41) * match metric <0-4294967295>: RIP route-map. (line 47) * match metric METRIC: Route Map Match Command. (line 15) * match peer {A.B.C.D|X:X::X:X}: Commands for configuring a Route Server. (line 33) * max-metric router-lsa administrative: OSPF router. (line 129) * max-metric router-lsa [on-startup|on-shutdown] <5-86400>: OSPF router. (line 127) * multicast: Interface Commands. (line 26) * neigbor {A.B.C.D|X.X::X.X|peer-group} route-map WORD {import|export}: Commands for configuring a Route Server. (line 27) * neighbor A.B.C.D: RIP Configuration. (line 33) * neighbor A.B.C.D route-server-client: Commands for configuring a Route Server. (line 10) * neighbor PEER default-originate: BGP Peer commands. (line 60) * neighbor PEER description ...: BGP Peer commands. (line 19) * neighbor PEER distribute-list NAME [in|out]: Peer filtering. (line 6) * neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 50) * neighbor PEER ebgp-multihop: BGP Peer commands. (line 16) * neighbor PEER filter-list NAME [in|out]: Peer filtering. (line 12) * neighbor PEER interface IFNAME: BGP Peer commands. (line 32) * neighbor PEER local-as AS-NUMBER: BGP Peer commands. (line 80) * neighbor PEER local-as AS-NUMBER no-prepend: BGP Peer commands. (line 81) * neighbor PEER local-as AS-NUMBER no-prepend replace-as: BGP Peer commands. (line 82) * neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 77) * neighbor PEER next-hop-self [all]: BGP Peer commands. (line 42) * neighbor PEER override-capability: Capability Negotiation. (line 66) * neighbor PEER peer-group WORD: BGP Peer Group. (line 9) * neighbor PEER port PORT: BGP Peer commands. (line 66) * neighbor PEER port PORT <1>: BGP Peer commands. (line 67) * neighbor PEER prefix-list NAME [in|out]: Peer filtering. (line 10) * neighbor PEER remote-as ASN: Defining Peer. (line 6) * neighbor PEER route-map NAME [in|out]: Peer filtering. (line 14) * neighbor PEER route-reflector-client: Route Reflector. (line 8) * neighbor PEER send-community: BGP Peer commands. (line 69) * neighbor PEER send-community <1>: BGP Peer commands. (line 70) * neighbor PEER shutdown: BGP Peer commands. (line 9) * neighbor PEER strict-capability-match: Capability Negotiation. (line 39) * neighbor PEER ttl-security hops NUMBER: BGP Peer commands. (line 101) * neighbor PEER update-source : BGP Peer commands. (line 49) * neighbor PEER version VERSION: BGP Peer commands. (line 23) * neighbor PEER weight WEIGHT: BGP Peer commands. (line 72) * neighbor PEER-GROUP route-server-client: Commands for configuring a Route Server. (line 9) * neighbor WORD peer-group: BGP Peer Group. (line 6) * neighbor X:X::X:X route-server-client: Commands for configuring a Route Server. (line 11) * network A.B.C.D/M: BGP route. (line 6) * network A.B.C.D/M area <0-4294967295>: OSPF router. (line 173) * network A.B.C.D/M area A.B.C.D: OSPF router. (line 172) * network IFNAME: RIP Configuration. (line 26) * network IFNAME <1>: ripngd Configuration. (line 17) * network IFNAME <2>: Babel configuration. (line 10) * network NETWORK: RIP Configuration. (line 14) * network NETWORK <1>: ripngd Configuration. (line 14) * no agentx: MIB and command reference. (line 33) * no aggregate-address A.B.C.D/M: Route Aggregation. (line 17) * no area <0-4294967295> authentication: OSPF area. (line 127) * no area <0-4294967295> export-list NAME: OSPF area. (line 86) * no area <0-4294967295> filter-list prefix NAME in: OSPF area. (line 119) * no area <0-4294967295> filter-list prefix NAME out: OSPF area. (line 120) * no area <0-4294967295> import-list NAME: OSPF area. (line 109) * no area <0-4294967295> range A.B.C.D/M: OSPF area. (line 9) * no area <0-4294967295> shortcut: OSPF area. (line 56) * no area <0-4294967295> stub: OSPF area. (line 63) * no area <0-4294967295> stub no-summary: OSPF area. (line 75) * no area <0-4294967295> virtual-link A.B.C.D: OSPF area. (line 51) * no area A.B.C.D authentication: OSPF area. (line 126) * no area A.B.C.D default-cost <0-16777215>: OSPF area. (line 80) * no area A.B.C.D export-list NAME: OSPF area. (line 85) * no area A.B.C.D filter-list prefix NAME in: OSPF area. (line 117) * no area A.B.C.D filter-list prefix NAME out: OSPF area. (line 118) * no area A.B.C.D import-list NAME: OSPF area. (line 108) * no area A.B.C.D range A.B.C.D/M: OSPF area. (line 8) * no area A.B.C.D range IPV4_PREFIX not-advertise: OSPF area. (line 28) * no area A.B.C.D range IPV4_PREFIX substitute IPV4_PREFIX: OSPF area. (line 34) * no area A.B.C.D shortcut: OSPF area. (line 55) * no area A.B.C.D stub: OSPF area. (line 62) * no area A.B.C.D stub no-summary: OSPF area. (line 74) * no area A.B.C.D virtual-link A.B.C.D: OSPF area. (line 50) * no auto-cost reference-bandwidth: OSPF router. (line 162) * no auto-cost reference-bandwidth <1>: OSPF6 router. (line 50) * no babel split-horizon: Babel configuration. (line 22) * no bandwidth <1-10000000>: Interface Commands. (line 31) * no banner motd: Basic Config Commands. (line 125) * no bgp multiple-instance: Multiple instance. (line 13) * no debug babel KIND: Babel debugging commands. (line 7) * no debug event: More Show IP BGP. (line 44) * no debug keepalive: More Show IP BGP. (line 48) * no debug ospf ism: Debugging OSPF. (line 15) * no debug ospf ism (status|events|timers): Debugging OSPF. (line 16) * no debug ospf lsa: Debugging OSPF. (line 25) * no debug ospf lsa (generate|flooding|refresh): Debugging OSPF. (line 26) * no debug ospf nsm: Debugging OSPF. (line 20) * no debug ospf nsm (status|events|timers): Debugging OSPF. (line 21) * no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]: Debugging OSPF. (line 9) * no debug ospf zebra: Debugging OSPF. (line 30) * no debug ospf zebra (interface|redistribute): Debugging OSPF. (line 31) * no debug update: More Show IP BGP. (line 46) * no default-information originate: Redistribute routes to OSPF. (line 49) * no default-metric: Redistribute routes to OSPF. (line 65) * no default-metric <1-16>: RIP Metric Manipulation. (line 11) * no distance <1-255>: RIP distance. (line 9) * no distance <1-255> <1>: Redistribute routes to OSPF. (line 68) * no distance <1-255> A.B.C.D/M: RIP distance. (line 13) * no distance <1-255> A.B.C.D/M ACCESS-LIST: RIP distance. (line 18) * no distance ospf: Redistribute routes to OSPF. (line 71) * no distribute-list NAME out (kernel|connected|static|rip|ospf: Redistribute routes to OSPF. (line 58) * no exec-timeout: Basic Config Commands. (line 136) * no ip address ADDRESS/PREFIX: Interface Commands. (line 14) * no ip address ADDRESS/PREFIX secondary: Interface Commands. (line 19) * no ip as-path access-list WORD: AS Path Access List. (line 11) * no ip as-path access-list WORD {permit|deny} LINE: AS Path Access List. (line 12) * no ip community-list expanded NAME: BGP Community Lists. (line 36) * no ip community-list NAME: BGP Community Lists. (line 34) * no ip community-list standard NAME: BGP Community Lists. (line 35) * no ip extcommunity-list expanded NAME: BGP Extended Community Lists. (line 28) * no ip extcommunity-list NAME: BGP Extended Community Lists. (line 26) * no ip extcommunity-list standard NAME: BGP Extended Community Lists. (line 27) * no ip mroute PREFIX NEXTHOP [DISTANCE]: Multicast RIB Commands. (line 71) * no ip multicast rpf-lookup-mode [MODE]: Multicast RIB Commands. (line 19) * no ip ospf authentication-key: OSPF interface. (line 7) * no ip ospf cost: OSPF interface. (line 45) * no ip ospf dead-interval: OSPF interface. (line 52) * no ip ospf hello-interval: OSPF interface. (line 69) * no ip ospf message-digest-key: OSPF interface. (line 33) * no ip ospf network: OSPF interface. (line 80) * no ip ospf priority: OSPF interface. (line 84) * no ip ospf retransmit interval: OSPF interface. (line 91) * no ip ospf transmit-delay: OSPF interface. (line 97) * no ip prefix-list NAME: IP Prefix List. (line 64) * no ip prefix-list NAME description [DESC]: ip prefix-list description. (line 10) * no ip prefix-list sequence-number: ip prefix-list sequential number control. (line 10) * no ip rip authentication key-chain KEY-CHAIN: RIP Authentication. (line 43) * no ip rip authentication mode md5: RIP Authentication. (line 29) * no ip rip authentication mode text: RIP Authentication. (line 33) * no ip rip authentication string STRING: RIP Authentication. (line 37) * no ip split-horizon: RIP Configuration. (line 70) * no ipv6 address ADDRESS/PREFIX: Interface Commands. (line 15) * no ipv6 nd adv-interval-option: Router Advertisement. (line 127) * no ipv6 nd home-agent-config-flag: Router Advertisement. (line 102) * no ipv6 nd home-agent-lifetime [<0-65520>]: Router Advertisement. (line 118) * no ipv6 nd home-agent-preference [<0-65535>]: Router Advertisement. (line 110) * no ipv6 nd managed-config-flag: Router Advertisement. (line 85) * no ipv6 nd mtu [<1-65535>]: Router Advertisement. (line 142) * no ipv6 nd other-config-flag: Router Advertisement. (line 94) * no ipv6 nd ra-interval [<1-1800>]: Router Advertisement. (line 50) * no ipv6 nd ra-interval [msec <70-1800000>]: Router Advertisement. (line 57) * no ipv6 nd ra-lifetime [<0-9000>]: Router Advertisement. (line 64) * no ipv6 nd reachable-time [<1-3600000>]: Router Advertisement. (line 76) * no ipv6 nd router-preference [(high|medium|low)]: Router Advertisement. (line 135) * no ipv6 nd suppress-ra: Router Advertisement. (line 6) * no link-detect: Interface Commands. (line 37) * no log facility: Basic Config Commands. (line 80) * no log file: Basic Config Commands. (line 41) * no log monitor: Basic Config Commands. (line 68) * no log record-priority: Basic Config Commands. (line 86) * no log stdout: Basic Config Commands. (line 29) * no log syslog: Basic Config Commands. (line 59) * no log timestamp precision: Basic Config Commands. (line 96) * no log trap: Basic Config Commands. (line 17) * no log-adjacency-changes [detail]: OSPF router. (line 72) * no max-metric router-lsa [on-startup|on-shutdown|administrative]: OSPF router. (line 130) * no multicast: Interface Commands. (line 27) * no neighbor A.B.C.D: RIP Configuration. (line 34) * no neighbor PEER default-originate: BGP Peer commands. (line 61) * no neighbor PEER description ...: BGP Peer commands. (line 20) * no neighbor PEER dont-capability-negotiate: Capability Negotiation. (line 51) * no neighbor PEER ebgp-multihop: BGP Peer commands. (line 17) * no neighbor PEER interface IFNAME: BGP Peer commands. (line 33) * no neighbor PEER local-as: BGP Peer commands. (line 83) * no neighbor PEER maximum-prefix NUMBER: BGP Peer commands. (line 78) * no neighbor PEER next-hop-self [all]: BGP Peer commands. (line 43) * no neighbor PEER override-capability: Capability Negotiation. (line 67) * no neighbor PEER route-reflector-client: Route Reflector. (line 9) * no neighbor PEER shutdown: BGP Peer commands. (line 10) * no neighbor PEER strict-capability-match: Capability Negotiation. (line 40) * no neighbor PEER ttl-security hops NUMBER: BGP Peer commands. (line 102) * no neighbor PEER update-source: BGP Peer commands. (line 50) * no neighbor PEER weight WEIGHT: BGP Peer commands. (line 73) * no network A.B.C.D/M: BGP route. (line 15) * no network A.B.C.D/M area <0-4294967295>: OSPF router. (line 175) * no network A.B.C.D/M area A.B.C.D: OSPF router. (line 174) * no network IFNAME: RIP Configuration. (line 27) * no network IFNAME <1>: Babel configuration. (line 11) * no network NETWORK: RIP Configuration. (line 15) * no ospf abr-type TYPE: OSPF router. (line 26) * no ospf rfc1583compatibility: OSPF router. (line 61) * no ospf router-id: OSPF router. (line 16) * no passive-interface IFNAME: RIP Configuration. (line 57) * no passive-interface INTERFACE: OSPF router. (line 78) * no redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 21) * no redistribute bgp: How to Announce RIP route. (line 43) * no redistribute connected: How to Announce RIP route. (line 25) * no redistribute kernel: How to Announce RIP route. (line 9) * no redistribute KIND: Babel redistribution. (line 7) * no redistribute ospf: How to Announce RIP route. (line 35) * no redistribute static: How to Announce RIP route. (line 17) * no route A.B.C.D/M: How to Announce RIP route. (line 53) * no router babel: Babel configuration. (line 7) * no router bgp ASN: BGP router. (line 18) * no router ospf: OSPF router. (line 10) * no router rip: RIP Configuration. (line 11) * no shutdown: Interface Commands. (line 9) * no smux peer OID: MIB and command reference. (line 26) * no smux peer OID PASSWORD: MIB and command reference. (line 29) * no timers basic: RIP Timers. (line 30) * no timers throttle spf: OSPF router. (line 90) * no timers throttle spf <1>: OSPF6 router. (line 17) * no version: RIP Version Control. (line 29) * offset-list ACCESS-LIST (in|out): RIP Metric Manipulation. (line 19) * offset-list ACCESS-LIST (in|out) IFNAME: RIP Metric Manipulation. (line 20) * on-match goto N: Route Map Exit Action Command. (line 10) * on-match next: Route Map Exit Action Command. (line 6) * ospf abr-type TYPE: OSPF router. (line 25) * ospf rfc1583compatibility: OSPF router. (line 60) * ospf router-id A.B.C.D: OSPF router. (line 15) * passive-interface (IFNAME|default): RIP Configuration. (line 56) * passive-interface INTERFACE: OSPF router. (line 77) * password PASSWORD: Basic Config Commands. (line 9) * redistribute (kernel|connected|static|rip|bgp): Redistribute routes to OSPF. (line 6) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>: Redistribute routes to OSPF. (line 13) * redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 15) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2): Redistribute routes to OSPF. (line 9) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>: Redistribute routes to OSPF. (line 17) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map WORD: Redistribute routes to OSPF. (line 19) * redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map WORD: Redistribute routes to OSPF. (line 11) * redistribute (kernel|connected|static|rip|bgp) ROUTE-MAP: Redistribute routes to OSPF. (line 7) * redistribute bgp: How to Announce RIP route. (line 40) * redistribute bgp metric <0-16>: How to Announce RIP route. (line 41) * redistribute bgp route-map ROUTE-MAP: How to Announce RIP route. (line 42) * redistribute connected: How to Announce RIP route. (line 22) * redistribute connected <1>: Redistribute routes to OSPF6. (line 7) * redistribute connected <2>: Redistribute to BGP. (line 12) * redistribute connected metric <0-16>: How to Announce RIP route. (line 23) * redistribute connected route-map ROUTE-MAP: How to Announce RIP route. (line 24) * redistribute kernel: How to Announce RIP route. (line 6) * redistribute kernel <1>: Redistribute to BGP. (line 6) * redistribute kernel metric <0-16>: How to Announce RIP route. (line 7) * redistribute kernel route-map ROUTE-MAP: How to Announce RIP route. (line 8) * redistribute KIND: Babel redistribution. (line 6) * redistribute ospf: How to Announce RIP route. (line 32) * redistribute ospf <1>: Redistribute to BGP. (line 18) * redistribute ospf metric <0-16>: How to Announce RIP route. (line 33) * redistribute ospf route-map ROUTE-MAP: How to Announce RIP route. (line 34) * redistribute rip: Redistribute to BGP. (line 15) * redistribute ripng: Redistribute routes to OSPF6. (line 8) * redistribute static: How to Announce RIP route. (line 14) * redistribute static <1>: Redistribute routes to OSPF6. (line 6) * redistribute static <2>: Redistribute to BGP. (line 9) * redistribute static metric <0-16>: How to Announce RIP route. (line 15) * redistribute static route-map ROUTE-MAP: How to Announce RIP route. (line 16) * route A.B.C.D/M: How to Announce RIP route. (line 52) * route NETWORK: ripngd Configuration. (line 20) * route-map ROUTE-MAP-NAME (permit|deny) ORDER: Route Map Command. (line 6) * router babel: Babel configuration. (line 6) * router bgp AS-NUMBER: BGP instance and view. (line 10) * router bgp AS-NUMBER view NAME: BGP instance and view. (line 27) * router bgp ASN: BGP router. (line 12) * router ospf: OSPF router. (line 9) * router ospf6: OSPF6 router. (line 6) * router rip: RIP Configuration. (line 6) * router ripng: ripngd Configuration. (line 8) * router zebra: ripngd Configuration. (line 23) * router-id A.B.C.D: OSPF6 router. (line 8) * service advanced-vty: Basic Config Commands. (line 112) * service integrated-vtysh-config: VTY shell integrated configuration. (line 6) * service password-encryption: Basic Config Commands. (line 109) * service terminal-length <0-512>: Basic Config Commands. (line 115) * set as-path prepend AS-PATH: Using AS Path in Route Map. (line 8) * set as-path prepend AS_PATH: Route Map Set Command. (line 18) * set as-path prepend last-as NUM: Using AS Path in Route Map. (line 11) * set comm-list WORD delete: BGP Community in Route Map. (line 33) * set community COMMUNITY: BGP Community in Route Map. (line 22) * set community COMMUNITY <1>: Route Map Set Command. (line 21) * set community COMMUNITY additive: BGP Community in Route Map. (line 23) * set community none: BGP Community in Route Map. (line 21) * set extcommunity rt EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 8) * set extcommunity soo EXTCOMMUNITY: BGP Extended Communities in Route Map. (line 11) * set ip next-hop A.B.C.D: RIP route-map. (line 52) * set ip next-hop IPV4_ADDRESS: Route Map Set Command. (line 6) * set ipv6 next-hop global IPV6_ADDRESS: Route Map Set Command. (line 24) * set ipv6 next-hop local IPV6_ADDRESS: Route Map Set Command. (line 27) * set local-preference LOCAL_PREF: Route Map Set Command. (line 9) * set metric <0-4294967295>: RIP route-map. (line 57) * set metric METRIC: Route Map Set Command. (line 15) * set src ADDRESS: zebra Route Filtering. (line 16) * set weight WEIGHT: Route Map Set Command. (line 12) * show babel database: Show Babel information. (line 6) * show babel interface: Show Babel information. (line 7) * show babel neighbour: Show Babel information. (line 8) * show babel parameters: Show Babel information. (line 9) * show debug: More Show IP BGP. (line 36) * show debugging ospf: Debugging OSPF. (line 33) * show debugging rip: RIP Debug Commands. (line 28) * show debugging ripng: ripngd Terminal Mode Commands. (line 8) * show interface: zebra Terminal Mode Commands. (line 20) * show ip bgp: Show IP BGP. (line 6) * show ip bgp A.B.C.D: Show IP BGP. (line 7) * show ip bgp community: Display BGP Routes by Community. (line 10) * show ip bgp community COMMUNITY: Display BGP Routes by Community. (line 11) * show ip bgp community COMMUNITY <1>: More Show IP BGP. (line 10) * show ip bgp community COMMUNITY exact-match: Display BGP Routes by Community. (line 12) * show ip bgp community COMMUNITY exact-match <1>: More Show IP BGP. (line 11) * show ip bgp community-list WORD: Display BGP Routes by Community. (line 19) * show ip bgp community-list WORD <1>: More Show IP BGP. (line 15) * show ip bgp community-list WORD exact-match: Display BGP Routes by Community. (line 20) * show ip bgp community-list WORD exact-match <1>: More Show IP BGP. (line 16) * show ip bgp dampened-paths: More Show IP BGP. (line 30) * show ip bgp flap-statistics: More Show IP BGP. (line 33) * show ip bgp neighbor [PEER]: More Show IP BGP. (line 22) * show ip bgp regexp LINE: Display BGP Routes by AS Path. (line 9) * show ip bgp regexp LINE <1>: More Show IP BGP. (line 6) * show ip bgp summary: More Show IP BGP. (line 20) * show ip bgp view NAME: Viewing the view. (line 8) * show ip bgp X:X::X:X: Show IP BGP. (line 8) * show ip community-list: BGP Community Lists. (line 41) * show ip community-list NAME: BGP Community Lists. (line 42) * show ip extcommunity-list: BGP Extended Community Lists. (line 34) * show ip extcommunity-list NAME: BGP Extended Community Lists. (line 35) * show ip ospf: Showing OSPF information. (line 6) * show ip ospf database: Showing OSPF information. (line 19) * show ip ospf database (asbr-summary|external|network|router|summary): Showing OSPF information. (line 21) * show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER: Showing OSPF information. (line 28) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID: Showing OSPF information. (line 23) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER: Showing OSPF information. (line 25) * show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate: Showing OSPF information. (line 31) * show ip ospf database (asbr-summary|external|network|router|summary) self-originate: Showing OSPF information. (line 34) * show ip ospf database max-age: Showing OSPF information. (line 37) * show ip ospf database self-originate: Showing OSPF information. (line 39) * show ip ospf interface [INTERFACE]: Showing OSPF information. (line 10) * show ip ospf neighbor: Showing OSPF information. (line 14) * show ip ospf neighbor detail: Showing OSPF information. (line 16) * show ip ospf neighbor INTERFACE: Showing OSPF information. (line 15) * show ip ospf neighbor INTERFACE detail: Showing OSPF information. (line 17) * show ip ospf route: Showing OSPF information. (line 41) * show ip prefix-list: Showing ip prefix-list. (line 6) * show ip prefix-list detail: Showing ip prefix-list. (line 29) * show ip prefix-list detail NAME: Showing ip prefix-list. (line 30) * show ip prefix-list NAME: Showing ip prefix-list. (line 9) * show ip prefix-list NAME A.B.C.D/M: Showing ip prefix-list. (line 16) * show ip prefix-list NAME A.B.C.D/M first-match: Showing ip prefix-list. (line 24) * show ip prefix-list NAME A.B.C.D/M longer: Showing ip prefix-list. (line 22) * show ip prefix-list NAME seq NUM: Showing ip prefix-list. (line 12) * show ip prefix-list summary: Showing ip prefix-list. (line 26) * show ip prefix-list summary NAME: Showing ip prefix-list. (line 27) * show ip prefix-list [NAME]: zebra Terminal Mode Commands. (line 22) * show ip protocol: zebra Terminal Mode Commands. (line 26) * show ip rip: Show RIP Information. (line 8) * show ip rip status: Show RIP Information. (line 16) * show ip ripng: ripngd Terminal Mode Commands. (line 6) * show ip route: zebra Terminal Mode Commands. (line 6) * show ip rpf: Multicast RIB Commands. (line 64) * show ip rpf ADDR: Multicast RIB Commands. (line 50) * show ipforward: zebra Terminal Mode Commands. (line 28) * show ipv6 ospf6 database: Showing OSPF6 information. (line 10) * show ipv6 ospf6 interface: Showing OSPF6 information. (line 14) * show ipv6 ospf6 neighbor: Showing OSPF6 information. (line 17) * show ipv6 ospf6 request-list A.B.C.D: Showing OSPF6 information. (line 20) * show ipv6 ospf6 [INSTANCE_ID]: Showing OSPF6 information. (line 6) * show ipv6 route: zebra Terminal Mode Commands. (line 18) * show ipv6 route ospf6: Showing OSPF6 information. (line 23) * show ipv6forward: zebra Terminal Mode Commands. (line 33) * show logging: Terminal Mode Commands. (line 29) * show route-map [NAME]: zebra Terminal Mode Commands. (line 24) * show version: Terminal Mode Commands. (line 26) * show zebra fpm stats: zebra Terminal Mode Commands. (line 36) * shutdown: Interface Commands. (line 8) * smux peer OID: MIB and command reference. (line 25) * smux peer OID PASSWORD: MIB and command reference. (line 28) * table TABLENO: Static Route Commands. (line 80) * terminal length <0-512>: Terminal Mode Commands. (line 16) * timers basic UPDATE TIMEOUT GARBAGE: RIP Timers. (line 6) * timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME: OSPF router. (line 88) * timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME <1>: OSPF6 router. (line 15) * username USERNAME nopassword: VTY shell username. (line 6) * version VERSION: RIP Version Control. (line 19) * who: Terminal Mode Commands. (line 20) * write file: Terminal Mode Commands. (line 9) * write terminal: Terminal Mode Commands. (line 6) quagga-0.99.24.1/doc/quagga.info0000644000175000017500000001771612476521364013141 00000000000000This is quagga.info, produced by makeinfo version 5.2 from quagga.texi. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro. INFO-DIR-SECTION Routing Software: START-INFO-DIR-ENTRY * Quagga: (quagga). The Quagga Software Routing Suite END-INFO-DIR-ENTRY This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition 0.99.24.1, last updated 7 March 2015 of 'The Quagga Manual', for Quagga Version 0.99.24.1. Copyright (C) 1999-2005 Kunihiro Ishiguro, et al. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro.  Indirect: quagga.info-1: 1942 quagga.info-2: 325285  Tag Table: (Indirect) Node: Top1942 Node: Overview3321 Node: About Quagga4755 Node: System Architecture7041 Node: Supported Platforms9730 Node: Supported RFCs10976 Node: How to get Quagga13157 Node: Mailing List13581 Node: Bug Reports14027 Node: Installation14903 Node: Configure the Software15337 Node: The Configure script and its options15585 Node: Least-Privilege support19144 Node: Linux notes20883 Ref: Linux notes-Footnote-122741 Node: Build the Software22807 Node: Install the Software23357 Node: Basic commands24861 Node: Config Commands25635 Node: Basic Config Commands26493 Node: Sample Config File32565 Node: Terminal Mode Commands33338 Node: Common Invocation Options34469 Node: Virtual Terminal Interfaces35885 Node: VTY Overview36396 Node: VTY Modes37651 Node: VTY View Mode38101 Node: VTY Enable Mode38351 Node: VTY Other Modes38629 Node: VTY CLI Commands38805 Node: CLI Movement Commands39265 Node: CLI Editing Commands39788 Node: CLI Advanced Commands40376 Node: Zebra41142 Node: Invoking zebra41857 Node: Interface Commands42387 Node: Static Route Commands43954 Node: Multicast RIB Commands47222 Node: zebra Route Filtering50354 Node: zebra FIB push interface51508 Node: zebra Terminal Mode Commands54012 Node: RIP55417 Node: Starting and Stopping ripd56484 Node: RIP netmask57912 Node: RIP Configuration59009 Node: RIP Version Control62007 Node: How to Announce RIP route64194 Node: Filtering RIP Routes66763 Node: RIP Metric Manipulation68230 Node: RIP distance69143 Node: RIP route-map69958 Node: RIP Authentication72507 Node: RIP Timers74752 Node: Show RIP Information76042 Node: RIP Debug Commands77418 Node: RIPng78414 Node: Invoking ripngd78760 Node: ripngd Configuration79009 Node: ripngd Terminal Mode Commands79760 Node: ripngd Filtering Commands80124 Node: OSPFv280633 Node: Configuring ospfd81365 Node: OSPF router81914 Ref: ospf router-id82461 Ref: OSPF passive-interface85672 Ref: OSPF auto-cost reference-bandwidth90137 Node: OSPF area91814 Ref: OSPF virtual-link94161 Ref: area authentication message-digest97873 Node: OSPF interface98296 Ref: ip ospf authentication message-digest98947 Ref: ip ospf message-digest-key99932 Ref: ip ospf dead-interval minimal100751 Node: Redistribute routes to OSPF103169 Ref: OSPF redistribute104225 Ref: ospf distribute-list106136 Node: Showing OSPF information106579 Ref: show ip ospf106790 Node: Debugging OSPF108185 Node: OSPF Configuration Examples109300 Node: OSPFv3110670 Node: OSPF6 router111077 Node: OSPF6 area113793 Node: OSPF6 interface113971 Node: Redistribute routes to OSPF6115041 Node: Showing OSPF6 information115357 Node: OSPF6 Configuration Examples116214 Node: Babel116635 Node: Configuring babeld117484 Node: Babel configuration117941 Node: Babel redistribution119871 Node: Show Babel information120191 Node: Babel debugging commands120627 Node: BGP121119 Node: Starting BGP122198 Node: BGP router122777 Node: BGP distance124081 Node: BGP decision process124520 Node: BGP route flap dampening125312 Node: BGP network126030 Node: BGP route126261 Node: Route Aggregation126815 Node: Redistribute to BGP127386 Node: BGP Peer127915 Node: Defining Peer128144 Node: BGP Peer commands128759 Node: Peer filtering133283 Node: BGP Peer Group133793 Node: BGP Address Family134108 Node: Autonomous System134264 Node: AS Path Regular Expression135167 Node: Display BGP Routes by AS Path136409 Node: AS Path Access List136851 Node: Using AS Path in Route Map137320 Node: Private AS Numbers137792 Node: BGP Communities Attribute137952 Node: BGP Community Lists140427 Node: Numbered BGP Community Lists143079 Node: BGP Community in Route Map144668 Node: Display BGP Routes by Community146614 Node: Using BGP Communities Attribute147785 Node: BGP Extended Communities Attribute151355 Node: BGP Extended Community Lists153134 Node: BGP Extended Communities in Route Map155021 Node: Displaying BGP routes155482 Node: Show IP BGP155750 Node: More Show IP BGP156452 Node: Capability Negotiation157774 Node: Route Reflector161247 Node: Route Server161528 Node: Multiple instance162641 Node: BGP instance and view164488 Node: Routing policy165871 Node: Viewing the view166641 Node: How to set up a 6-Bone connection166928 Node: Dump BGP packets and table168302 Node: BGP Configuration Examples168886 Node: Configuring Quagga as a Route Server177843 Node: Description of the Route Server model178830 Ref: fig:normal-processing180423 Ref: fig:full-mesh181115 Ref: fig:route-server181292 Ref: filter-delegation181767 Ref: Route Server tasks182941 Ref: Route-server path filter process183312 Ref: fig:rs-processing185642 Node: Commands for configuring a Route Server188050 Node: Example of Route Server Configuration191095 Node: Configuration of the BGP routers without Route Server192017 Node: Configuration of the BGP routers with Route Server194901 Node: Configuration of the Route Server itself196203 Node: Further considerations about Import and Export route-maps201204 Node: VTY shell204252 Node: VTY shell username204921 Node: VTY shell integrated configuration205554 Node: Filtering206999 Node: IP Access List207380 Node: IP Prefix List207766 Node: ip prefix-list description210809 Node: ip prefix-list sequential number control211336 Node: Showing ip prefix-list211878 Node: Clear counter of ip prefix-list212984 Node: Route Map213423 Node: Route Map Command216894 Node: Route Map Match Command217203 Node: Route Map Set Command217826 Node: Route Map Call Command218734 Node: Route Map Exit Action Command219065 Node: Route Map Examples219547 Node: IPv6 Support220059 Node: Router Advertisement220646 Node: Kernel Interface226983 Node: SNMP Support228940 Node: Getting and installing an SNMP agent229599 Node: AgentX configuration230410 Node: SMUX configuration232213 Node: MIB and command reference234333 Node: Handling SNMP Traps235858 Node: Zebra Protocol241941 Node: Packet Binary Dump Format246041 Node: Command Index257649 Node: VTY Key Index325285 Node: Index328201  End Tag Table quagga-0.99.24.1/doc/fig_topologies_rs.dia0000644000175000017500000004162512476520570015205 00000000000000 #A4# #RS# #RF2# #RF4# #RF3# #RF1# quagga-0.99.24.1/doc/fig_topologies_full.dia0000644000175000017500000004363012476520570015521 00000000000000 #A4# #RF2# #RF4# #RF3# #RF1# quagga-0.99.24.1/doc/fig-rs-processing.dia0000644000175000017500000045232612476520570015035 00000000000000 #A4# #Best Path Selection# #Main Loc-RIB# #From Peer A# #From RS-Client B# #D# #C# #B# #A# #X# #“Out†Filter for Peer X# ## #“In†Filter for Peer X# #X# #From RS-Client D# #From RS-Client C# #Best Path Selection# #Loc-RIB For C# #Best Path Selection# #Loc-RIB For D# #Best Path Selection# #Loc-RIB For B# #D# #C# #B# #B# #B# #C# #C# #C# #D# #B# #D# #D# #D# #B# #C# ## #Export Policy of RS-Client X# #X# ## #Import Policy of RS-Client X# #X# #To RS-Client B# #B# #C# #To RS-Client C# #A# #To Peer A# #D# #To RS-Client D# quagga-0.99.24.1/doc/fig-normal-processing.dia0000644000175000017500000017005612476520570015676 00000000000000 #A4# #Best Path Selection# #Local RIB# #From Peer A# #From Peer B# #From Peer C# #From Peer D# #To Peer A# #To Peer B# #To Peer C# #To Peer D# #D# #C# #B# #A# #A# #B# #C# #D# #X# #“Out†Filter for Peer X# ## #“In†Filter for Peer X# #X# quagga-0.99.24.1/doc/zebra.80000644000175000017500000000671512476520570012206 00000000000000.TH ZEBRA 8 "25 November 2004" "Zebra daemon" "Version 0.97.3" .SH NAME zebra \- a routing manager for use with associated Quagga components. .SH SYNOPSIS .B zebra [ .B \-bdhklrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B zebra is a routing manager that implements the .B zebra route engine. .B zebra supports RIPv1, RIPv2, RIPng, OSPF, OSPF6, IS-IS, BGP4+, and BGP4-. .SH OPTIONS Options available for the .B zebra command: .TP \fB\-b\fR, \fB\-\-batch\fR Runs in batch mode, \fBzebra\fR parses its config and exits. .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/zebra.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When zebra starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart zebra. The likely default is \fB\fI/var/run/zebra.pid\fR. .TP \fB\-k\fR, \fB\-\-keep_kernel\fR On startup, don't delete self inserted routes. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the zebra VTY will listen on. This defaults to 2601, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the zebra VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBzebra\fR. .TP \fB\-s\fR, \fB\-\-nl-bufsize \fR\fInetlink-buffer-size\fR Set netlink receive buffer size. There are cases where zebra daemon can't handle flood of netlink messages from kernel. If you ever see "recvmsg overrun" messages in zebra log, you are in trouble. Solution is to increase receive buffer of netlink socket. Note that kernel < 2.6.14 doesn't allow to increase it over maximum value defined in \fI/proc/sys/net/core/rmem_max\fR. If you want to do it, you have to increase maximum before starting zebra. Note that this affects Linux only. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/zebra The default location of the .B zebra binary. .TP .BI /usr/local/etc/zebra.conf The default location of the .B zebra config file. .TP .BI $(PWD)/zebra.log If the .B zebra process is config'd to output logs to a file, then you will find this file in the directory where you started \fBzebra\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The zebra process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBzebra\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR vtysh (1) .SH BUGS .B zebra eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/watchquagga.80000644000175000017500000001550012476520570013367 00000000000000.\" This file was originally generated by help2man 1.36. .TH WATCHQUAGGA 8 "July 2010" .SH NAME watchquagga \- a program to monitor the status of quagga daemons .SH SYNOPSIS .B watchquagga .RI [ option ...] .IR daemon ... .br .B watchquagga .BR \-h " | " \-v .SH DESCRIPTION .B watchquagga is a watchdog program that monitors the status of supplied quagga .IR daemon s and tries to restart them in case they become unresponsive or shut down. .PP To determine whether a daemon is running, it tries to connect to the daemon's VTY UNIX stream socket, and send echo commands to ensure the daemon responds. When the daemon crashes, EOF is received from the socket, so that watchquagga can react immediately. .PP This program can run in one of the following 5 modes: .TP .B Mode 0: monitor In this mode, the program serves as a monitor and reports status changes. .IP Example usage: watchquagga \-d zebra ospfd bgpd .TP .B Mode 1: global restart In this mode, whenever a daemon hangs or crashes, the given command is used to restart all watched daemons. .IP Example usage: watchquagga \-dz \e .br -R '/sbin/service zebra restart; /sbin/service ospfd restart' \e .br zebra ospfd .TP .B Mode 2: individual daemon restart In this mode, whenever a single daemon hangs or crashes, the given command is used to restart this daemon only. .IP Example usage: watchquagga \-dz \-r '/sbin/service %s restart' \e .br zebra ospfd bgpd .TP .B Mode 3: phased zebra restart In this mode, whenever a single daemon hangs or crashes, the given command is used to restart this daemon only. The only exception is the zebra daemon; in this case, the following steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, and (3) other daemons are started again. .IP Example usage: watchquagga \-adz \-r '/sbin/service %s restart' \e .br \-s '/sbin/service %s start' \e .br \-k '/sbin/service %s stop' zebra ospfd bgpd .TP .B Mode 4: phased global restart for any failure In this mode, whenever a single daemon hangs or crashes, the following steps are taken: (1) all other daemons are stopped, (2) zebra is restarted, and (3) other daemons are started again. .IP Example usage: watchquagga \-Adz \-r '/sbin/service %s restart' \e .br \-s '/sbin/service %s start' \e .br \-k '/sbin/service %s stop' zebra ospfd bgpd .PP Important: It is believed that mode 2 (individual daemon restart) is not safe, and mode 3 (phased zebra restart) may not be safe with certain routing daemons. .PP In order to avoid restarting the daemons in quick succession, you can supply the .B \-m and .B \-M options to set the minimum and maximum delay between the restart commands. The minimum restart delay is recalculated each time a restart is attempted. If the time since the last restart attempt exceeds twice the value of .BR \-M , the restart delay is set to the value of .BR \-m , otherwise the interval is doubled (but capped at the value of .BR \-M ). .SH OPTIONS .TP .BR \-d ", " \-\-daemon Run in daemon mode. When supplied, error messages are sent to Syslog instead of standard output (stdout). .TP .BI \-S " directory" "\fR, \fB\-\-statedir " directory Set the VTY socket .I directory (the default value is "/var/run/quagga"). .TP .BR \-e ", " \-\-no\-echo Do not ping the daemons to test whether they respond. This option is necessary if one or more daemons do not support the echo command. .TP .BI \-l " level" "\fR, \fB\-\-loglevel " level Set the logging .I level (the default value is "6"). The value should range from 0 (LOG_EMERG) to 7 (LOG_DEBUG), but higher number can be supplied if extra debugging messages are required. .TP .BI \-m " number" "\fR, \fB\-\-min\-restart\-interval " number Set the minimum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "60"). .TP .BI \-M " number" "\fR, \fB\-\-max\-restart\-interval " number Set the maximum .I number of seconds to wait between invocations of the daemon restart commands (the default value is "600"). .TP .BI \-i " number" "\fR, \fB\-\-interval " number Set the status polling interval in seconds (the default value is "5"). .TP .BI \-t " number" "\fR, \fB\-\-timeout " number Set the unresponsiveness timeout in seconds (the default value is "10"). .TP .BI \-T " number" "\fR, \fB\-\-restart\-timeout " number Set the restart (kill) timeout in seconds (the default value is "20"). If any background jobs are still running after this period has elapsed, they will be killed. .TP .BI \-r " command" "\fR, \fB\-\-restart " command Supply a Bourne shell .I command to restart a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .IP Note that .B \-r and .B \-R options are not compatible. .TP .BI \-s " command" "\fR, \fB\-\-start\-command " command Supply a Bourne shell .I command to start a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .TP .BI \-k " command" "\fR, \fB\-\-kill\-command " command Supply a Bourne shell .I command to stop a single daemon. The command string should contain the '%s' placeholder to be substituted with the daemon name. .TP .BR \-R ", " \-\-restart\-all When one or more daemons are shut down, try to restart them using the Bourne shell command supplied on the command line. .IP Note that .B \-r and .B \-R options are not compatible. .TP .BR \-z ", " \-\-unresponsive\-restart When a daemon is in an unresponsive state, treat it as being shut down for the restart purposes. .TP .BR \-a ", " \-\-all\-restart When zebra hangs or crashes, restart all daemons taking the following steps: (1) stop all other daemons, (2) restart zebra, and (3) start other daemons again. .IP Note that this option also requires .BR \-r , .BR \-s , and .B \-k options to be specified. .TP .BR \-A ", " \-\-always\-all\-restart When any daemon (i.e., not just zebra) hangs or crashes, restart all daemons taking the following steps: (1) stop all other daemons, (2) restart zebra, and (3) start other daemons again. .IP Note that this option also requires .BR \-r , .BR \-s , and .B \-k options to be specified. .TP .BI \-p " filename" "\fR, \fB\-\-pid\-file " filename Set the process identifier .I filename (the default value is "/var/run/quagga/watchquagga.pid"). .TP .BI \-b " string" "\fR, \fB\-\-blank\-string " string When the supplied .I string is found in any of the command line option arguments (i.e., .BR \-r , .BR \-s , .BR \-k , or .BR \-R ), replace it with a space. .IP This is an ugly hack to circumvent problems with passing the command line arguments containing embedded spaces. .TP .BR \-v ", " \-\-version Display the version information and exit. .TP .BR \-h ", " \-\-help Display the usage information and exit. .SH SEE ALSO .BR zebra (8), .BR bgpd (8), .BR isisd (8), .BR ospfd (8), .BR ospf6d (8), .BR ripd (8), .BR ripngd (8) .PP See the project homepage at . .SH AUTHORS Copyright 2004 Andrew J. Schorr quagga-0.99.24.1/doc/vtysh.10000644000175000017500000000533112476520570012242 00000000000000.TH VTYSH 1 "27 July 2006" "Quagga VTY shell" "Version 0.96.5" .SH NAME vtysh \- a integrated shell for Quagga routing software .SH SYNOPSIS .B vtysh [ .B \-b ] .br .B vtysh [ .B \-E ] [ .B \-d .I daemon ] ] [ .B \-c .I command ] .SH DESCRIPTION .B vtysh is a integrated shell for .B Quagga routing engine. .SH OPTIONS Options available for the .B vtysh command: .IP "\fB\-b, \-\-boot\fP" Execute boot startup configuration. It makes sense only if integrated config file is in use (not default in Quagga). See Info file \fBQuagga\fR for more info. .IP "\fB\-c, \-\-command \fIcommand\fP" Specify command to be executed under batch mode. It behaves like -c option in any other shell - .I command is executed and .B vtysh exits. It's useful for gathering info from Quagga routing software or reconfiguring daemons from inside shell scripts, etc. Note that multiple commands may be executed by using more than one -c option and/or embedding linefeed characters inside the .I command string. .IP "\fB\-d, \-\-daemon \fIdaemon_name\fP" Specify which daemon to connect to. By default, .B vtysh attempts to connect to all Quagga daemons running on the system. With this flag, one can specify a single daemon to connect to instead. For example, specifying '-d ospfd' will connect only to ospfd. This can be particularly useful inside scripts with -c where the command is targeted for a single daemon. .IP "\fB\-e, \-\-execute \fIcommand\fP" Alias for -c. It's here only for compatibility with Zebra routing software and older Quagga versions. This will be removed in future. .IP "\fB\-E, \-\-echo\fP" When the -c option is being used, this flag will cause the standard .B vtysh prompt and command to be echoed prior to displaying the results. This is particularly useful to separate the results when executing multiple commands. .IP "\fB\-h, \-\-help\fP" Display a usage message on standard output and exit. .SH ENVIRONMENT VARIABLES .IP "\fBVTYSH_PAGER\fR" This should be the name of the pager to use. Default is \fBmore\fR. .SH FILES .TP .BI /usr/local/etc/vtysh.conf The default location of the .B vtysh config file. .TP .BI /usr/local/etc/Quagga.conf The default location of the integrated Quagga routing engine config file if integrated config file is in use (not default). .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8) .SH BUGS .B vtysh eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/pimd.80000644000175000017500000000547512476520570012036 00000000000000.TH PIM 8 "10 December 2008" "Quagga PIM daemon" "Version 0.99.11" .SH NAME pimd \- a PIM routing for use with Quagga Routing Suite. .SH SYNOPSIS .B pimd [ .B \-dhvZ ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-z .I path ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B pimd is a protocol-independent multicast component that works with the .B Quagga Routing Suite. .SH OPTIONS Options available for the .B pimd command: .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/pimd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When pimd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart pimd. The likely default is \fB\fI/var/run/pimd.pid\fR. .TP \fB\-z\fR, \fB\-\-socket \fR\fIpath\fR Specify the socket path for contacting the zebra daemon. The likely default is \fB\fI/var/run/zserv.api\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the pimd VTY will listen on. This defaults to 2611, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the pimd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .TP \fB\-Z\fR, \fB\-\-debug_zclient\fR Enable logging information for zclient debugging. .SH FILES .TP .BI /usr/local/sbin/pimd The default location of the .B pimd binary. .TP .BI /usr/local/etc/pimd.conf The default location of the .B pimd config file. .TP .BI /var/run/pimd.pid The default location of the .B pimd pid file. .TP .BI /var/run/zserv.api The default location of the .B zebra unix socket file. .TP .BI $(PWD)/pimd.log If the .B pimd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBpimd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. .SH DIAGNOSTICS The pimd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. .SH "SEE ALSO" .BR zebra (8), .BR vtysh (1) .SH BUGS \fBpimd\fR is in early development at the moment and is not ready for production use. .B pimd eats bugs for breakfast. If you have food for the maintainers try .BI https://github.com/udhos/qpimd .SH AUTHORS See .BI https://github.com/udhos/qpimd for an accurate list of authors. quagga-0.99.24.1/doc/ripngd.80000644000175000017500000000532312476520570012360 00000000000000.TH RIPNGD 8 "25 November 2004" "Quagga RIPNG daemon" "Version 0.97.3" .SH NAME ripngd \- a RIPNG routing engine for use with Quagga routing software. .SH SYNOPSIS .B ripngd [ .B \-dhlrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ripngd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ripngd command: .SH OPTIONS .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ripngd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When ripngd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart ripngd. The likely default is \fB\fI/var/run/ripngd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the ripngd VTY will listen on. This defaults to 2603, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ripngd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/ripngd The default location of the .B ripngd binary. .TP .BI /usr/local/etc/ripngd.conf The default location of the .B ripngd config file. .TP .BI $(PWD)/ripngd.log If the .B ripngd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBripngd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The ripngd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBripngd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ripngd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/ripd.80000644000175000017500000000524412476520570012035 00000000000000.TH RIPD 8 "25 November 2004" "Quagga RIP daemon" "Version 0.97.3" .SH NAME ripd \- a RIP routing engine for use with Quagga routing software. .SH SYNOPSIS .B ripd [ .B \-dhrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ripd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ripd command: .SH OPTIONS .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ripd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When ripd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart ripd. The likely default is \fB\fI/var/run/ripd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the ripd VTY will listen on. This defaults to 2602, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ripd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBripd\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/ripd The default location of the .B ripd binary. .TP .BI /usr/local/etc/ripd.conf The default location of the .B ripd config file. .TP .BI $(PWD)/ripd.log If the .B ripd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBripd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The ripd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBripd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ripd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/ospfd.80000644000175000017500000000524412476520570012212 00000000000000.TH OSPFD 8 "25 November 2004" "Quagga OSPFv2 daemon" "Version 0.97.3" .SH NAME ospfd \- an OSPFv2 routing engine for use with Quagga routing software. .SH SYNOPSIS .B ospfd [ .B \-dhlv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ospfd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ospfd command: .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ospfd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When ospfd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart ospfd. The likely default is \fB\fI/var/run/ospfd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the ospfd VTY will listen on. This defaults to 2604, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ospfd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-a\fR, \fB\-\-apiserver \fR Enable OSPF apiserver. Default is disabled. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/ospfd The default location of the .B ospfd binary. .TP .BI /usr/local/etc/ospfd.conf The default location of the .B ospfd config file. .TP .BI $(PWD)/ospfd.log If the .B ospfd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBospfd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The ospfd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBospfd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ospfd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/ospfclient.80000644000175000017500000000166612476520570013251 00000000000000.\" This file was originally generated by help2man 1.36. .TH OSPFCLIENT "1" "July 2010" .SH NAME ospfclient \- an example ospf-api client .SH SYNOPSIS .B ospfclient .I ospfd .I lsatype .I opaquetype .I opaqueid .I ifaddr .I areaid .SH DESCRIPTION .B ospfclient is a an example ospf-api client to test the ospfd daemon. .SH OPTIONS .TP .I ospfd A router where the API\-enabled OSPF daemon is running. .TP .I lsatype The value has to be either "9", "10", or "11", depending on the flooding scope. .TP .I opaquetype The value has to be in the range of 0\-255 (for example, experimental applications use .I opaquetype larger than 128). .TP .I opaqueid Arbitrary application instance (24 bits). .TP .I ifaddr Interface IP address for type 9, otherwise it will be ignored. .TP .I areaid Area in the IP address format for type 10, otherwise it will be ignored. .SH "SEE ALSO" .BR ospfd (8). .SH AUTHORS See the project homepage at . quagga-0.99.24.1/doc/ospf6d.80000644000175000017500000000516312476520570012300 00000000000000.TH OSPF6D 8 "25 November 2004" "Quagga OSPFv3 daemon" "Version 0.97.3" .SH NAME ospf6d \- an OSPFv3 routing engine for use with Quagga routing software. .SH SYNOPSIS .B ospf6d [ .B \-dhv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B ospf6d is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B ospf6d command: .SH OPTIONS .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/ospf6d.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When ospf6d starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart ospf6d. The likely default is \fB\fI/var/run/ospf6d.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the ospf6d VTY will listen on. This defaults to 2606, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the ospf6d VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/ospf6d The default location of the .B ospf6d binary. .TP .BI /usr/local/etc/ospf6d.conf The default location of the .B ospf6d config file. .TP .BI $(PWD)/ospf6d.log If the .B ospf6d process is config'd to output logs to a file, then you will find this file in the directory where you started \fBospf6d\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The ospf6d process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBospf6d\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B ospf6d eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/isisd.80000644000175000017500000000522412476520570012210 00000000000000.TH IS-IS 8 "25 November 2004" "Quagga IS-IS daemon" "Version 0.97.3" .SH NAME isisd \- an IS-IS routing engine for use with Quagga routing software. .SH SYNOPSIS .B isisd [ .B \-dhv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B isisd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B isisd command: .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/isisd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When isisd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart isisd. The likely default is \fB\fI/var/run/isisd.pid\fR. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the isisd VTY will listen on. This defaults to 2608, as specified in \fB\fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the isisd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/isisd The default location of the .B isisd binary. .TP .BI /usr/local/etc/isisd.conf The default location of the .B isisd config file. .TP .BI $(PWD)/isisd.log If the .B isisd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBisisd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The isisd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBisisd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR bgpd (8), .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR zebra (8), .BR vtysh (1) .SH BUGS \fBisisd\fR is ALPHA quality at the moment and hasn't any way ready for production use. .B isisd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://isisd.sourceforge.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/bgpd.80000644000175000017500000000547312476520570012017 00000000000000.TH BGPD 8 "25 November 2004" "Quagga BGPD daemon" "Version 0.97.3" .SH NAME bgpd \- a BGPv4, BGPv4\+, BGPv4\- routing engine for use with Quagga routing software .SH SYNOPSIS .B bgpd [ .B \-dhrv ] [ .B \-f .I config-file ] [ .B \-i .I pid-file ] [ .B \-p .I bgp-port-number ] [ .B \-P .I port-number ] [ .B \-A .I vty-address ] [ .B \-u .I user ] [ .B \-g .I group ] .SH DESCRIPTION .B bgpd is a routing component that works with the .B Quagga routing engine. .SH OPTIONS Options available for the .B bgpd command: .TP \fB\-d\fR, \fB\-\-daemon\fR Runs in daemon mode, forking and exiting from tty. .TP \fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR Specifies the config file to use for startup. If not specified this option will likely default to \fB\fI/usr/local/etc/bgpd.conf\fR. .TP \fB\-g\fR, \fB\-\-group \fR\fIgroup\fR Specify the group to run as. Default is \fIquagga\fR. .TP \fB\-h\fR, \fB\-\-help\fR A brief message. .TP \fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR When bgpd starts its process identifier is written to \fB\fIpid-file\fR. The init system uses the recorded PID to stop or restart bgpd. The likely default is \fB\fI/var/run/bgpd.pid\fR. .TP \fB\-p\fR, \fB\-\-bgp_port \fR\fIbgp-port-number\fR Set the port that bgpd will listen to for bgp data. .TP \fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR Specify the port that the bgpd VTY will listen on. This defaults to 2605, as specified in \fI/etc/services\fR. .TP \fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR Specify the address that the bgpd VTY will listen on. Default is all interfaces. .TP \fB\-u\fR, \fB\-\-user \fR\fIuser\fR Specify the user to run as. Default is \fIquagga\fR. .TP \fB\-r\fR, \fB\-\-retain\fR When the program terminates, retain routes added by \fBbgpd\fR. .TP \fB\-v\fR, \fB\-\-version\fR Print the version and exit. .SH FILES .TP .BI /usr/local/sbin/bgpd The default location of the .B bgpd binary. .TP .BI /usr/local/etc/bgpd.conf The default location of the .B bgpd config file. .TP .BI $(PWD)/bgpd.log If the .B bgpd process is config'd to output logs to a file, then you will find this file in the directory where you started \fBbgpd\fR. .SH WARNING This man page is intended to be a quick reference for command line options. The definitive document is the Info file \fBQuagga\fR. .SH DIAGNOSTICS The bgpd process may log to standard output, to a VTY, to a log file, or through syslog to the system logs. \fBbgpd\fR supports many debugging options, see the Info file, or the source for details. .SH "SEE ALSO" .BR ripd (8), .BR ripngd (8), .BR ospfd (8), .BR ospf6d (8), .BR isisd (8), .BR zebra (8), .BR vtysh (1) .SH BUGS .B bgpd eats bugs for breakfast. If you have food for the maintainers try .BI http://bugzilla.quagga.net .SH AUTHORS See .BI http://www.zebra.org and .BI http://www.quagga.net or the Info file for an accurate list of authors. quagga-0.99.24.1/doc/draft-zebra-00.txt0000644000175000017500000001316512476521356014171 00000000000000 Network Working Group K. Ishiguro Request for Comments: DRAFT Digital Magic Labs, Inc. March 1998 Zebra Protocol Draft Status of this Memo This draft is very eary beta version. Introduction The zebra protocol is a communication protocol between kernel routing table manager and routing protocol daemon. It is built over TCP/IP protocol suite. Request message formats zebra is TCP-based protocol. Below is request packet format. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length (2) | Command (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Length is total packet length. Here is summary of command list. 1 - ZEBRA_IPV4_ROUTE_ADD 2 - ZEBRA_IPV4_ROUTE_DELETE 3 - ZEBRA_IPV6_ROUTE_ADD 4 - ZEBRA_IPV6_ROUTE_DELETE 5 - ZEBRA_GET_ONE_INTERFACE 6 - ZEBRA_GET_ALL_INTERFACE 7 - ZEBRA_GET_HOSTINFO Ishiguro FORMFEED[Page 1] RFC DRAFT March 1998 IPv4 reply message formats 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+ | Type (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Gateway (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Type field specify route's origin type. 1 - ZEBRA_ROUTE_RESERVE 2 - ZEBRA_ROUTE_CONNECT 3 - ZEBRA_ROUTE_STATIC 4 - ZEBRA_ROUTE_RIP 5 - ZEBRA_ROUTE_RIPNG 6 - ZEBRA_ROUTE_BGP 7 - ZEBRA_ROUTE_RADIX After above message there can be variale length IPv4 prefix data. Each IPv4 prefix is encoded as a two tuple of the form +----------------------+ |Subnet mask (1 octet) | +----------------------+ |IPv4 prefix (variable)| +----------------------+ IPv6 reply message formats Ishiguro FORMFEED[Page 2] RFC DRAFT March 1998 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+ | Type (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Gateway (16) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Type field specify route's origin type. 1 - ZEBRA_ROUTE_RESERVE 2 - ZEBRA_ROUTE_CONNECT 3 - ZEBRA_ROUTE_STATIC 4 - ZEBRA_ROUTE_RIP 5 - ZEBRA_ROUTE_RIPNG 6 - ZEBRA_ROUTE_BGP 7 - ZEBRA_ROUTE_RADIX +----------------------+ | ifindex (4 octet) | +----------------------+ | prefixlen (1 octet)| +----------------------+ |IPv6 prefix (variable)| +----------------------+ I am not sure but it seems some operation systems IPv6 implementation may need interface index when add and delete linklocal routes. I have added ifindex field to specify IPv6 routes interface index. If this index is value zero, it will ignored. Interface information message format. Ishiguro FORMFEED[Page 3] RFC DRAFT March 1998 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface name (20) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Index (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface flag (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface metric (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface MTU (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface Address count (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Address message format. Host inforamtion message format. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |IPv4 forwarding|IPv6 forwarding| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Host information contain IPv4/IPv6 forwarding information. Ishiguro FORMFEED[Page 4] quagga-0.99.24.1/doc/draft-zebra-00.ms0000644000175000017500000001213512476520570013762 00000000000000.pl 10.0i .po 0 .ll 7.2i .lt 7.2i .nr LL 7.2i .nr LT 7.2i .ds LF Ishiguro .ds RF FORMFEED[Page %] .ds CF .ds LH RFC DRAFT .ds RH March 1998 .ds CH .hy 0 .ad l Network Working Group K. Ishiguro Request for Comments: DRAFT Digital Magic Labs, Inc. March 1998 .sp 2 .ce Zebra Protocol Draft .sp 2 .fi .ne 4 Status of this Memo .sp .in 3 This draft is very eary beta version. .sp .in 0 .ne 4 Introduction .sp .in 3 The zebra protocol is a communication protocol between kernel routing table manager and routing protocol daemon. It is built over TCP/IP protocol suite. .sp .in 0 .ne 4 Request message formats .sp .in 3 zebra is TCP-based protocol. .sp Below is request packet format. .sp .in 0 .DS 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length (2) | Command (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .DE .sp .in 3 Length is total packet length. .sp Here is summary of command list. .sp .in 0 .DS 1 - ZEBRA_IPV4_ROUTE_ADD 2 - ZEBRA_IPV4_ROUTE_DELETE 3 - ZEBRA_IPV6_ROUTE_ADD 4 - ZEBRA_IPV6_ROUTE_DELETE 5 - ZEBRA_GET_ONE_INTERFACE 6 - ZEBRA_GET_ALL_INTERFACE 7 - ZEBRA_GET_HOSTINFO .DE .sp .in 0 .ne 4 IPv4 reply message formats .sp .in 0 .DS 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+ | Type (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Gateway (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .DE .sp .in 3 Type field specify route's origin type. .sp .in 0 .DS 1 - ZEBRA_ROUTE_RESERVE 2 - ZEBRA_ROUTE_CONNECT 3 - ZEBRA_ROUTE_STATIC 4 - ZEBRA_ROUTE_RIP 5 - ZEBRA_ROUTE_RIPNG 6 - ZEBRA_ROUTE_BGP 7 - ZEBRA_ROUTE_RADIX .DE .sp .in 3 After above message there can be variale length IPv4 prefix data. Each IPv4 prefix is encoded as a two tuple of the form .sp .in 0 .DS +----------------------+ |Subnet mask (1 octet) | +----------------------+ |IPv4 prefix (variable)| +----------------------+ .DE .sp .in 0 .ne 4 IPv6 reply message formats .sp .in 0 .DS 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+ | Type (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Gateway (16) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .DE .sp .in 3 Type field specify route's origin type. .sp .in 0 .DS 1 - ZEBRA_ROUTE_RESERVE 2 - ZEBRA_ROUTE_CONNECT 3 - ZEBRA_ROUTE_STATIC 4 - ZEBRA_ROUTE_RIP 5 - ZEBRA_ROUTE_RIPNG 6 - ZEBRA_ROUTE_BGP 7 - ZEBRA_ROUTE_RADIX .DE .sp .in 0 .DS +----------------------+ | ifindex (4 octet) | +----------------------+ | prefixlen (1 octet)| +----------------------+ |IPv6 prefix (variable)| +----------------------+ .DE .sp .in 3 I am not sure but it seems some operation systems IPv6 implementation may need interface index when add and delete linklocal routes. .sp I have added ifindex field to specify IPv6 routes interface index. If this index is value zero, it will ignored. .sp .in 0 .ne 4 Interface information message format. .sp .in 0 .DS 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface name (20) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Index (1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface flag (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface metric (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface MTU (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Inteface Address count (4) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .DE .sp .in 3 Address message format. .sp .in 0 .ne 4 Host inforamtion message format. .sp .in 0 .DS 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |IPv4 forwarding|IPv6 forwarding| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ .DE .sp .in 3 Host information contain IPv4/IPv6 forwarding information. quagga-0.99.24.1/doc/BGP-TypeCode0000644000175000017500000000175212476520570013053 00000000000000 BGP-4[+] UPDATE Attribute TypeCode list Value Attribute References ========================================================================= 1 ORIGIN [RFC 4271] 2 AS_PATH [RFC 4271] 3 NEXT_HOP [RFC 4271] 4 MULTI_EXIT_DISC [RFC 4271] 5 LOCAL_PREF [RFC 4271] 6 ATOMIC_AGGREGATE [RFC 4271] 7 AGGREGATOR [RFC 4271] 8 COMMUNITIES [RFC 1997] 9 ORIGINATOR_ID [RFC 4456] 10 CLUSTER_LIST [RFC 4456] 11 DPA [draft-ietf-idr-bgp-dpa-05.txt(expired)] 12 ADVERTISER [RFC 1863] 13 RCID_PATH [RFC 1863] 14 MP_REACH_NLRI [RFC 4760] 15 MP_UNREACH_NLRI [RFC 4760] 16 EXT_COMMUNITIES [RFC 4360] 17 AS4_PATH [RFC 4893] 18 AS4_AGGREGATOR [RFC 4893] ========================================================================= quagga-0.99.24.1/doc/quagga.texi0000644000175000017500000000613412476520570013145 00000000000000\input texinfo @c -*- texinfo -*- @c %**start of header @setfilename quagga.info @c Set variables - sourced from defines.texi @include defines.texi @settitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @c %**end of header @c automake will automatically generate version.texi @c and set EDITION, VERSION, UPDATED and UPDATED-MONTH @include version.texi @copying @value{COPYRIGHT_STR} @quotation Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by Kunihiro Ishiguro. @end quotation @end copying @c Info entry @dircategory Routing Software: @direntry * @value{PACKAGE_NAME}: (quagga). The Quagga Software Routing Suite @end direntry @c @smallbook @ifinfo This file documents the Quagga Software Routing Suite which manages common TCP/IP routing protocols. This is Edition @value{EDITION}, last updated @value{UPDATED} of @cite{The Quagga Manual}, for @uref{http://www.quagga.net/,,@value{PACKAGE_NAME}} Version @value{VERSION}. @insertcopying @end ifinfo @titlepage @title @uref{http://www.quagga.net,,Quagga} @subtitle A routing software package for TCP/IP networks @subtitle @uref{http://www.quagga.net,,@value{PACKAGE_NAME}} @value{VERSION} @subtitle @value{UPDATED-MONTH} @author @value{AUTHORS} @page @vskip 0pt plus 1filll @insertcopying @end titlepage @page @ifnottex @node Top @top Quagga @uref{http://www.quagga.net,,Quagga} is an advanced routing software package that provides a suite of TCP/IP based routing protocols. This is the Manual for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of @uref{http://www.zebra.org,,GNU Zebra}. @insertcopying @end ifnottex @menu * Overview:: * Installation:: * Basic commands:: * Zebra:: * RIP:: * RIPng:: * OSPFv2:: * OSPFv3:: * Babel:: * BGP:: * Configuring Quagga as a Route Server:: * VTY shell:: * Filtering:: * Route Map:: * IPv6 Support:: * Kernel Interface:: * SNMP Support:: * Zebra Protocol:: * Packet Binary Dump Format:: * Command Index:: * VTY Key Index:: * Index:: @end menu @contents @include overview.texi @include install.texi @include basic.texi @include main.texi @include ripd.texi @include ripngd.texi @include ospfd.texi @include ospf6d.texi @include babeld.texi @include bgpd.texi @include routeserver.texi @include vtysh.texi @include filter.texi @include routemap.texi @include ipv6.texi @include kernel.texi @include snmp.texi @include protocol.texi @include appendix.texi @node Command Index @unnumbered Command Index @printindex fn @node VTY Key Index @unnumbered VTY Key Index @printindex ky @node Index @unnumbered Index @printindex cp @bye quagga-0.99.24.1/doc/texinfo.tex0000644000175000017500000116703612476521250013211 00000000000000% texinfo.tex -- TeX macros to handle Texinfo files. % % Load plain if necessary, i.e., if running under initex. \expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi % \def\texinfoversion{2013-02-01.11} % % Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, % 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, % 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. % % This texinfo.tex file is free software: you can redistribute it and/or % modify it under the terms of the GNU General Public License as % published by the Free Software Foundation, either version 3 of the % License, or (at your option) any later version. % % This texinfo.tex file is distributed in the hope that it will be % useful, but WITHOUT ANY WARRANTY; without even the implied warranty % of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU % General Public License for more details. % % You should have received a copy of the GNU General Public License % along with this program. If not, see . % % As a special exception, when this file is read by TeX when processing % a Texinfo source document, you may use the result without % restriction. This Exception is an additional permission under section 7 % of the GNU General Public License, version 3 ("GPLv3"). % % Please try the latest version of texinfo.tex before submitting bug % reports; you can get the latest version from: % http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or % http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or % http://www.gnu.org/software/texinfo/ (the Texinfo home page) % The texinfo.tex in any given distribution could well be out % of date, so if that's what you're using, please check. % % Send bug reports to bug-texinfo@gnu.org. Please include including a % complete document in each bug report with which we can reproduce the % problem. Patches are, of course, greatly appreciated. % % To process a Texinfo manual with TeX, it's most reliable to use the % texi2dvi shell script that comes with the distribution. For a simple % manual foo.texi, however, you can get away with this: % tex foo.texi % texindex foo.?? % tex foo.texi % tex foo.texi % dvips foo.dvi -o # or whatever; this makes foo.ps. % The extra TeX runs get the cross-reference information correct. % Sometimes one run after texindex suffices, and sometimes you need more % than two; texi2dvi does it as many times as necessary. % % It is possible to adapt texinfo.tex for other languages, to some % extent. You can get the existing language-specific files from the % full Texinfo distribution. % % The GNU Texinfo home page is http://www.gnu.org/software/texinfo. \message{Loading texinfo [version \texinfoversion]:} % If in a .fmt file, print the version number % and turn on active characters that we couldn't do earlier because % they might have appeared in the input file name. \everyjob{\message{[Texinfo version \texinfoversion]}% \catcode`+=\active \catcode`\_=\active} \chardef\other=12 % We never want plain's \outer definition of \+ in Texinfo. % For @tex, we can use \tabalign. \let\+ = \relax % Save some plain tex macros whose names we will redefine. \let\ptexb=\b \let\ptexbullet=\bullet \let\ptexc=\c \let\ptexcomma=\, \let\ptexdot=\. \let\ptexdots=\dots \let\ptexend=\end \let\ptexequiv=\equiv \let\ptexexclam=\! \let\ptexfootnote=\footnote \let\ptexgtr=> \let\ptexhat=^ \let\ptexi=\i \let\ptexindent=\indent \let\ptexinsert=\insert \let\ptexlbrace=\{ \let\ptexless=< \let\ptexnewwrite\newwrite \let\ptexnoindent=\noindent \let\ptexplus=+ \let\ptexraggedright=\raggedright \let\ptexrbrace=\} \let\ptexslash=\/ \let\ptexstar=\* \let\ptext=\t \let\ptextop=\top {\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode % If this character appears in an error message or help string, it % starts a new line in the output. \newlinechar = `^^J % Use TeX 3.0's \inputlineno to get the line number, for better error % messages, but if we're using an old version of TeX, don't do anything. % \ifx\inputlineno\thisisundefined \let\linenumber = \empty % Pre-3.0. \else \def\linenumber{l.\the\inputlineno:\space} \fi % Set up fixed words for English if not already set. \ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi \ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi \ifx\putworderror\undefined \gdef\putworderror{error}\fi \ifx\putwordfile\undefined \gdef\putwordfile{file}\fi \ifx\putwordin\undefined \gdef\putwordin{in}\fi \ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi \ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi \ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi \ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi \ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi \ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi \ifx\putwordof\undefined \gdef\putwordof{of}\fi \ifx\putwordon\undefined \gdef\putwordon{on}\fi \ifx\putwordpage\undefined \gdef\putwordpage{page}\fi \ifx\putwordsection\undefined \gdef\putwordsection{section}\fi \ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi \ifx\putwordsee\undefined \gdef\putwordsee{see}\fi \ifx\putwordSee\undefined \gdef\putwordSee{See}\fi \ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi \ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi % \ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi \ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi \ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi \ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi \ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi \ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi \ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi \ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi \ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi \ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi \ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi \ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi % \ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi \ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi \ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi \ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi \ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi % Since the category of space is not known, we have to be careful. \chardef\spacecat = 10 \def\spaceisspace{\catcode`\ =\spacecat} % sometimes characters are active, so we need control sequences. \chardef\ampChar = `\& \chardef\colonChar = `\: \chardef\commaChar = `\, \chardef\dashChar = `\- \chardef\dotChar = `\. \chardef\exclamChar= `\! \chardef\hashChar = `\# \chardef\lquoteChar= `\` \chardef\questChar = `\? \chardef\rquoteChar= `\' \chardef\semiChar = `\; \chardef\slashChar = `\/ \chardef\underChar = `\_ % Ignore a token. % \def\gobble#1{} % The following is used inside several \edef's. \def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} % Hyphenation fixes. \hyphenation{ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script ap-pen-dix bit-map bit-maps data-base data-bases eshell fall-ing half-way long-est man-u-script man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces spell-ing spell-ings stand-alone strong-est time-stamp time-stamps which-ever white-space wide-spread wrap-around } % Margin to add to right of even pages, to left of odd pages. \newdimen\bindingoffset \newdimen\normaloffset \newdimen\pagewidth \newdimen\pageheight % For a final copy, take out the rectangles % that mark overfull boxes (in case you have decided % that the text looks ok even though it passes the margin). % \def\finalout{\overfullrule=0pt } % Sometimes it is convenient to have everything in the transcript file % and nothing on the terminal. We don't just call \tracingall here, % since that produces some useless output on the terminal. We also make % some effort to order the tracing commands to reduce output in the log % file; cf. trace.sty in LaTeX. % \def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% \def\loggingall{% \tracingstats2 \tracingpages1 \tracinglostchars2 % 2 gives us more in etex \tracingparagraphs1 \tracingoutput1 \tracingmacros2 \tracingrestores1 \showboxbreadth\maxdimen \showboxdepth\maxdimen \ifx\eTeXversion\thisisundefined\else % etex gives us more logging \tracingscantokens1 \tracingifs1 \tracinggroups1 \tracingnesting2 \tracingassigns1 \fi \tracingcommands3 % 3 gives us more in etex \errorcontextlines16 }% % @errormsg{MSG}. Do the index-like expansions on MSG, but if things % aren't perfect, it's not the end of the world, being an error message, % after all. % \def\errormsg{\begingroup \indexnofonts \doerrormsg} \def\doerrormsg#1{\errmessage{#1}} % add check for \lastpenalty to plain's definitions. If the last thing % we did was a \nobreak, we don't want to insert more space. % \def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount \removelastskip\penalty-50\smallskip\fi\fi} \def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount \removelastskip\penalty-100\medskip\fi\fi} \def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount \removelastskip\penalty-200\bigskip\fi\fi} % Do @cropmarks to get crop marks. % \newif\ifcropmarks \let\cropmarks = \cropmarkstrue % % Dimensions to add cropmarks at corners. % Added by P. A. MacKay, 12 Nov. 1986 % \newdimen\outerhsize \newdimen\outervsize % set by the paper size routines \newdimen\cornerlong \cornerlong=1pc \newdimen\cornerthick \cornerthick=.3pt \newdimen\topandbottommargin \topandbottommargin=.75in % Output a mark which sets \thischapter, \thissection and \thiscolor. % We dump everything together because we only have one kind of mark. % This works because we only use \botmark / \topmark, not \firstmark. % % A mark contains a subexpression of the \ifcase ... \fi construct. % \get*marks macros below extract the needed part using \ifcase. % % Another complication is to let the user choose whether \thischapter % (\thissection) refers to the chapter (section) in effect at the top % of a page, or that at the bottom of a page. The solution is % described on page 260 of The TeXbook. It involves outputting two % marks for the sectioning macros, one before the section break, and % one after. I won't pretend I can describe this better than DEK... \def\domark{% \toks0=\expandafter{\lastchapterdefs}% \toks2=\expandafter{\lastsectiondefs}% \toks4=\expandafter{\prevchapterdefs}% \toks6=\expandafter{\prevsectiondefs}% \toks8=\expandafter{\lastcolordefs}% \mark{% \the\toks0 \the\toks2 \noexpand\or \the\toks4 \the\toks6 \noexpand\else \the\toks8 }% } % \topmark doesn't work for the very first chapter (after the title % page or the contents), so we use \firstmark there -- this gets us % the mark with the chapter defs, unless the user sneaks in, e.g., % @setcolor (or @url, or @link, etc.) between @contents and the very % first @chapter. \def\gettopheadingmarks{% \ifcase0\topmark\fi \ifx\thischapter\empty \ifcase0\firstmark\fi \fi } \def\getbottomheadingmarks{\ifcase1\botmark\fi} \def\getcolormarks{\ifcase2\topmark\fi} % Avoid "undefined control sequence" errors. \def\lastchapterdefs{} \def\lastsectiondefs{} \def\prevchapterdefs{} \def\prevsectiondefs{} \def\lastcolordefs{} % Main output routine. \chardef\PAGE = 255 \output = {\onepageout{\pagecontents\PAGE}} \newbox\headlinebox \newbox\footlinebox % \onepageout takes a vbox as an argument. Note that \pagecontents % does insertions, but you have to call it yourself. \def\onepageout#1{% \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi % \ifodd\pageno \advance\hoffset by \bindingoffset \else \advance\hoffset by -\bindingoffset\fi % % Do this outside of the \shipout so @code etc. will be expanded in % the headline as they should be, not taken literally (outputting ''code). \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% % {% % Have to do this stuff outside the \shipout because we want it to % take effect in \write's, yet the group defined by the \vbox ends % before the \shipout runs. % \indexdummies % don't expand commands in the output. \normalturnoffactive % \ in index entries must not stay \, e.g., if % the page break happens to be in the middle of an example. % We don't want .vr (or whatever) entries like this: % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} % "\acronym" won't work when it's read back in; % it needs to be % {\code {{\tt \backslashcurfont }acronym} \shipout\vbox{% % Do this early so pdf references go to the beginning of the page. \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi % \ifcropmarks \vbox to \outervsize\bgroup \hsize = \outerhsize \vskip-\topandbottommargin \vtop to0pt{% \line{\ewtop\hfil\ewtop}% \nointerlineskip \line{% \vbox{\moveleft\cornerthick\nstop}% \hfill \vbox{\moveright\cornerthick\nstop}% }% \vss}% \vskip\topandbottommargin \line\bgroup \hfil % center the page within the outer (page) hsize. \ifodd\pageno\hskip\bindingoffset\fi \vbox\bgroup \fi % \unvbox\headlinebox \pagebody{#1}% \ifdim\ht\footlinebox > 0pt % Only leave this space if the footline is nonempty. % (We lessened \vsize for it in \oddfootingyyy.) % The \baselineskip=24pt in plain's \makefootline has no effect. \vskip 24pt \unvbox\footlinebox \fi % \ifcropmarks \egroup % end of \vbox\bgroup \hfil\egroup % end of (centering) \line\bgroup \vskip\topandbottommargin plus1fill minus1fill \boxmaxdepth = \cornerthick \vbox to0pt{\vss \line{% \vbox{\moveleft\cornerthick\nsbot}% \hfill \vbox{\moveright\cornerthick\nsbot}% }% \nointerlineskip \line{\ewbot\hfil\ewbot}% }% \egroup % \vbox from first cropmarks clause \fi }% end of \shipout\vbox }% end of group with \indexdummies \advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi } \newinsert\margin \dimen\margin=\maxdimen \def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} {\catcode`\@ =11 \gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi % marginal hacks, juha@viisa.uucp (Juha Takala) \ifvoid\margin\else % marginal info is present \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi \dimen@=\dp#1\relax \unvbox#1\relax \ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi \ifr@ggedbottom \kern-\dimen@ \vfil \fi} } % Here are the rules for the cropmarks. Note that they are % offset so that the space between them is truly \outerhsize or \outervsize % (P. A. MacKay, 12 November, 1986) % \def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} \def\nstop{\vbox {\hrule height\cornerthick depth\cornerlong width\cornerthick}} \def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} \def\nsbot{\vbox {\hrule height\cornerlong depth\cornerthick width\cornerthick}} % Parse an argument, then pass it to #1. The argument is the rest of % the input line (except we remove a trailing comment). #1 should be a % macro which expects an ordinary undelimited TeX argument. % \def\parsearg{\parseargusing{}} \def\parseargusing#1#2{% \def\argtorun{#2}% \begingroup \obeylines \spaceisspace #1% \parseargline\empty% Insert the \empty token, see \finishparsearg below. } {\obeylines % \gdef\parseargline#1^^M{% \endgroup % End of the group started in \parsearg. \argremovecomment #1\comment\ArgTerm% }% } % First remove any @comment, then any @c comment. \def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} \def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} % Each occurrence of `\^^M' or `\^^M' is replaced by a single space. % % \argremovec might leave us with trailing space, e.g., % @end itemize @c foo % This space token undergoes the same procedure and is eventually removed % by \finishparsearg. % \def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} \def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} \def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% \def\temp{#3}% \ifx\temp\empty % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: \let\temp\finishparsearg \else \let\temp\argcheckspaces \fi % Put the space token in: \temp#1 #3\ArgTerm } % If a _delimited_ argument is enclosed in braces, they get stripped; so % to get _exactly_ the rest of the line, we had to prevent such situation. % We prepended an \empty token at the very beginning and we expand it now, % just before passing the control to \argtorun. % (Similarly, we have to think about #3 of \argcheckspacesY above: it is % either the null string, or it ends with \^^M---thus there is no danger % that a pair of braces would be stripped. % % But first, we have to remove the trailing space token. % \def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} % \parseargdef\foo{...} % is roughly equivalent to % \def\foo{\parsearg\Xfoo} % \def\Xfoo#1{...} % % Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my % favourite TeX trick. --kasal, 16nov03 \def\parseargdef#1{% \expandafter \doparseargdef \csname\string#1\endcsname #1% } \def\doparseargdef#1#2{% \def#2{\parsearg#1}% \def#1##1% } % Several utility definitions with active space: { \obeyspaces \gdef\obeyedspace{ } % Make each space character in the input produce a normal interword % space in the output. Don't allow a line break at this space, as this % is used only in environments like @example, where each line of input % should produce a line of output anyway. % \gdef\sepspaces{\obeyspaces\let =\tie} % If an index command is used in an @example environment, any spaces % therein should become regular spaces in the raw index file, not the % expansion of \tie (\leavevmode \penalty \@M \ ). \gdef\unsepspaces{\let =\space} } \def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} % Define the framework for environments in texinfo.tex. It's used like this: % % \envdef\foo{...} % \def\Efoo{...} % % It's the responsibility of \envdef to insert \begingroup before the % actual body; @end closes the group after calling \Efoo. \envdef also % defines \thisenv, so the current environment is known; @end checks % whether the environment name matches. The \checkenv macro can also be % used to check whether the current environment is the one expected. % % Non-false conditionals (@iftex, @ifset) don't fit into this, so they % are not treated as environments; they don't open a group. (The % implementation of @end takes care not to call \endgroup in this % special case.) % At run-time, environments start with this: \def\startenvironment#1{\begingroup\def\thisenv{#1}} % initialize \let\thisenv\empty % ... but they get defined via ``\envdef\foo{...}'': \long\def\envdef#1#2{\def#1{\startenvironment#1#2}} \def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} % Check whether we're in the right environment: \def\checkenv#1{% \def\temp{#1}% \ifx\thisenv\temp \else \badenverr \fi } % Environment mismatch, #1 expected: \def\badenverr{% \errhelp = \EMsimple \errmessage{This command can appear only \inenvironment\temp, not \inenvironment\thisenv}% } \def\inenvironment#1{% \ifx#1\empty outside of any environment% \else in environment \expandafter\string#1% \fi } % @end foo executes the definition of \Efoo. % But first, it executes a specialized version of \checkenv % \parseargdef\end{% \if 1\csname iscond.#1\endcsname \else % The general wording of \badenverr may not be ideal. \expandafter\checkenv\csname#1\endcsname \csname E#1\endcsname \endgroup \fi } \newhelp\EMsimple{Press RETURN to continue.} % Be sure we're in horizontal mode when doing a tie, since we make space % equivalent to this in @example-like environments. Otherwise, a space % at the beginning of a line will start with \penalty -- and % since \penalty is valid in vertical mode, we'd end up putting the % penalty on the vertical list instead of in the new paragraph. {\catcode`@ = 11 % Avoid using \@M directly, because that causes trouble % if the definition is written into an index file. \global\let\tiepenalty = \@M \gdef\tie{\leavevmode\penalty\tiepenalty\ } } % @: forces normal size whitespace following. \def\:{\spacefactor=1000 } % @* forces a line break. \def\*{\unskip\hfil\break\hbox{}\ignorespaces} % @/ allows a line break. \let\/=\allowbreak % @. is an end-of-sentence period. \def\.{.\spacefactor=\endofsentencespacefactor\space} % @! is an end-of-sentence bang. \def\!{!\spacefactor=\endofsentencespacefactor\space} % @? is an end-of-sentence query. \def\?{?\spacefactor=\endofsentencespacefactor\space} % @frenchspacing on|off says whether to put extra space after punctuation. % \def\onword{on} \def\offword{off} % \parseargdef\frenchspacing{% \def\temp{#1}% \ifx\temp\onword \plainfrenchspacing \else\ifx\temp\offword \plainnonfrenchspacing \else \errhelp = \EMsimple \errmessage{Unknown @frenchspacing option `\temp', must be on|off}% \fi\fi } % @w prevents a word break. Without the \leavevmode, @w at the % beginning of a paragraph, when TeX is still in vertical mode, would % produce a whole line of output instead of starting the paragraph. \def\w#1{\leavevmode\hbox{#1}} % @group ... @end group forces ... to be all on one page, by enclosing % it in a TeX vbox. We use \vtop instead of \vbox to construct the box % to keep its height that of a normal line. According to the rules for % \topskip (p.114 of the TeXbook), the glue inserted is % max (\topskip - \ht (first item), 0). If that height is large, % therefore, no glue is inserted, and the space between the headline and % the text is small, which looks bad. % % Another complication is that the group might be very large. This can % cause the glue on the previous page to be unduly stretched, because it % does not have much material. In this case, it's better to add an % explicit \vfill so that the extra space is at the bottom. The % threshold for doing this is if the group is more than \vfilllimit % percent of a page (\vfilllimit can be changed inside of @tex). % \newbox\groupbox \def\vfilllimit{0.7} % \envdef\group{% \ifnum\catcode`\^^M=\active \else \errhelp = \groupinvalidhelp \errmessage{@group invalid in context where filling is enabled}% \fi \startsavinginserts % \setbox\groupbox = \vtop\bgroup % Do @comment since we are called inside an environment such as % @example, where each end-of-line in the input causes an % end-of-line in the output. We don't want the end-of-line after % the `@group' to put extra space in the output. Since @group % should appear on a line by itself (according to the Texinfo % manual), we don't worry about eating any user text. \comment } % % The \vtop produces a box with normal height and large depth; thus, TeX puts % \baselineskip glue before it, and (when the next line of text is done) % \lineskip glue after it. Thus, space below is not quite equal to space % above. But it's pretty close. \def\Egroup{% % To get correct interline space between the last line of the group % and the first line afterwards, we have to propagate \prevdepth. \endgraf % Not \par, as it may have been set to \lisppar. \global\dimen1 = \prevdepth \egroup % End the \vtop. % \dimen0 is the vertical size of the group's box. \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox % \dimen2 is how much space is left on the page (more or less). \dimen2 = \pageheight \advance\dimen2 by -\pagetotal % if the group doesn't fit on the current page, and it's a big big % group, force a page break. \ifdim \dimen0 > \dimen2 \ifdim \pagetotal < \vfilllimit\pageheight \page \fi \fi \box\groupbox \prevdepth = \dimen1 \checkinserts } % % TeX puts in an \escapechar (i.e., `@') at the beginning of the help % message, so this ends up printing `@group can only ...'. % \newhelp\groupinvalidhelp{% group can only be used in environments such as @example,^^J% where each line of input produces a line of output.} % @need space-in-mils % forces a page break if there is not space-in-mils remaining. \newdimen\mil \mil=0.001in \parseargdef\need{% % Ensure vertical mode, so we don't make a big box in the middle of a % paragraph. \par % % If the @need value is less than one line space, it's useless. \dimen0 = #1\mil \dimen2 = \ht\strutbox \advance\dimen2 by \dp\strutbox \ifdim\dimen0 > \dimen2 % % Do a \strut just to make the height of this box be normal, so the % normal leading is inserted relative to the preceding line. % And a page break here is fine. \vtop to #1\mil{\strut\vfil}% % % TeX does not even consider page breaks if a penalty added to the % main vertical list is 10000 or more. But in order to see if the % empty box we just added fits on the page, we must make it consider % page breaks. On the other hand, we don't want to actually break the % page after the empty box. So we use a penalty of 9999. % % There is an extremely small chance that TeX will actually break the % page at this \penalty, if there are no other feasible breakpoints in % sight. (If the user is using lots of big @group commands, which % almost-but-not-quite fill up a page, TeX will have a hard time doing % good page breaking, for example.) However, I could not construct an % example where a page broke at this \penalty; if it happens in a real % document, then we can reconsider our strategy. \penalty9999 % % Back up by the size of the box, whether we did a page break or not. \kern -#1\mil % % Do not allow a page break right after this kern. \nobreak \fi } % @br forces paragraph break (and is undocumented). \let\br = \par % @page forces the start of a new page. % \def\page{\par\vfill\supereject} % @exdent text.... % outputs text on separate line in roman font, starting at standard page margin % This records the amount of indent in the innermost environment. % That's how much \exdent should take out. \newskip\exdentamount % This defn is used inside fill environments such as @defun. \parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} % This defn is used inside nofill environments such as @example. \parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount \leftline{\hskip\leftskip{\rm#1}}}} % @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current % paragraph. For more general purposes, use the \margin insertion % class. WHICH is `l' or `r'. Not documented, written for gawk manual. % \newskip\inmarginspacing \inmarginspacing=1cm \def\strutdepth{\dp\strutbox} % \def\doinmargin#1#2{\strut\vadjust{% \nobreak \kern-\strutdepth \vtop to \strutdepth{% \baselineskip=\strutdepth \vss % if you have multiple lines of stuff to put here, you'll need to % make the vbox yourself of the appropriate size. \ifx#1l% \llap{\ignorespaces #2\hskip\inmarginspacing}% \else \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% \fi \null }% }} \def\inleftmargin{\doinmargin l} \def\inrightmargin{\doinmargin r} % % @inmargin{TEXT [, RIGHT-TEXT]} % (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; % else use TEXT for both). % \def\inmargin#1{\parseinmargin #1,,\finish} \def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \def\lefttext{#1}% have both texts \def\righttext{#2}% \else \def\lefttext{#1}% have only one text \def\righttext{#1}% \fi % \ifodd\pageno \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin \else \def\temp{\inleftmargin\lefttext}% \fi \temp } % @| inserts a changebar to the left of the current line. It should % surround any changed text. This approach does *not* work if the % change spans more than two lines of output. To handle that, we would % have adopt a much more difficult approach (putting marks into the main % vertical list for the beginning and end of each change). This command % is not documented, not supported, and doesn't work. % \def\|{% % \vadjust can only be used in horizontal mode. \leavevmode % % Append this vertical mode material after the current line in the output. \vadjust{% % We want to insert a rule with the height and depth of the current % leading; that is exactly what \strutbox is supposed to record. \vskip-\baselineskip % % \vadjust-items are inserted at the left edge of the type. So % the \llap here moves out into the left-hand margin. \llap{% % % For a thicker or thinner bar, change the `1pt'. \vrule height\baselineskip width1pt % % This is the space between the bar and the text. \hskip 12pt }% }% } % @include FILE -- \input text of FILE. % \def\include{\parseargusing\filenamecatcodes\includezzz} \def\includezzz#1{% \pushthisfilestack \def\thisfile{#1}% {% \makevalueexpandable % we want to expand any @value in FILE. \turnoffactive % and allow special characters in the expansion \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @include of #1^^J}% \edef\temp{\noexpand\input #1 }% % % This trickery is to read FILE outside of a group, in case it makes % definitions, etc. \expandafter }\temp \popthisfilestack } \def\filenamecatcodes{% \catcode`\\=\other \catcode`~=\other \catcode`^=\other \catcode`_=\other \catcode`|=\other \catcode`<=\other \catcode`>=\other \catcode`+=\other \catcode`-=\other \catcode`\`=\other \catcode`\'=\other } \def\pushthisfilestack{% \expandafter\pushthisfilestackX\popthisfilestack\StackTerm } \def\pushthisfilestackX{% \expandafter\pushthisfilestackY\thisfile\StackTerm } \def\pushthisfilestackY #1\StackTerm #2\StackTerm {% \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% } \def\popthisfilestack{\errthisfilestackempty} \def\errthisfilestackempty{\errmessage{Internal error: the stack of filenames is empty.}} % \def\thisfile{} % @center line % outputs that line, centered. % \parseargdef\center{% \ifhmode \let\centersub\centerH \else \let\centersub\centerV \fi \centersub{\hfil \ignorespaces#1\unskip \hfil}% \let\centersub\relax % don't let the definition persist, just in case } \def\centerH#1{{% \hfil\break \advance\hsize by -\leftskip \advance\hsize by -\rightskip \line{#1}% \break }} % \newcount\centerpenalty \def\centerV#1{% % The idea here is the same as in \startdefun, \cartouche, etc.: if % @center is the first thing after a section heading, we need to wipe % out the negative parskip inserted by \sectionheading, but still % prevent a page break here. \centerpenalty = \lastpenalty \ifnum\centerpenalty>10000 \vskip\parskip \fi \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi \line{\kern\leftskip #1\kern\rightskip}% } % @sp n outputs n lines of vertical space % \parseargdef\sp{\vskip #1\baselineskip} % @comment ...line which is ignored... % @c is the same as @comment % @ignore ... @end ignore is another way to write a comment % \def\comment{\begingroup \catcode`\^^M=\other% \catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% \commentxxx} {\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} % \let\c=\comment % @paragraphindent NCHARS % We'll use ems for NCHARS, close enough. % NCHARS can also be the word `asis' or `none'. % We cannot feasibly implement @paragraphindent asis, though. % \def\asisword{asis} % no translation, these are keywords \def\noneword{none} % \parseargdef\paragraphindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \defaultparindent = 0pt \else \defaultparindent = #1em \fi \fi \parindent = \defaultparindent } % @exampleindent NCHARS % We'll use ems for NCHARS like @paragraphindent. % It seems @exampleindent asis isn't necessary, but % I preserve it to make it similar to @paragraphindent. \parseargdef\exampleindent{% \def\temp{#1}% \ifx\temp\asisword \else \ifx\temp\noneword \lispnarrowing = 0pt \else \lispnarrowing = #1em \fi \fi } % @firstparagraphindent WORD % If WORD is `none', then suppress indentation of the first paragraph % after a section heading. If WORD is `insert', then do indent at such % paragraphs. % % The paragraph indentation is suppressed or not by calling % \suppressfirstparagraphindent, which the sectioning commands do. % We switch the definition of this back and forth according to WORD. % By default, we suppress indentation. % \def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} \def\insertword{insert} % \parseargdef\firstparagraphindent{% \def\temp{#1}% \ifx\temp\noneword \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent \else\ifx\temp\insertword \let\suppressfirstparagraphindent = \relax \else \errhelp = \EMsimple \errmessage{Unknown @firstparagraphindent option `\temp'}% \fi\fi } % Here is how we actually suppress indentation. Redefine \everypar to % \kern backwards by \parindent, and then reset itself to empty. % % We also make \indent itself not actually do anything until the next % paragraph. % \gdef\dosuppressfirstparagraphindent{% \gdef\indent{% \restorefirstparagraphindent \indent }% \gdef\noindent{% \restorefirstparagraphindent \noindent }% \global\everypar = {% \kern -\parindent \restorefirstparagraphindent }% } \gdef\restorefirstparagraphindent{% \global \let \indent = \ptexindent \global \let \noindent = \ptexnoindent \global \everypar = {}% } % @refill is a no-op. \let\refill=\relax % If working on a large document in chapters, it is convenient to % be able to disable indexing, cross-referencing, and contents, for test runs. % This is done with @novalidate (before @setfilename). % \newif\iflinks \linkstrue % by default we want the aux files. \let\novalidate = \linksfalse % @setfilename is done at the beginning of every texinfo file. % So open here the files we need to have open while reading the input. % This makes it possible to make a .fmt file for texinfo. \def\setfilename{% \fixbackslash % Turn off hack to swallow `\input texinfo'. \iflinks \tryauxfile % Open the new aux file. TeX will close it automatically at exit. \immediate\openout\auxfile=\jobname.aux \fi % \openindices needs to do some work in any case. \openindices \let\setfilename=\comment % Ignore extra @setfilename cmds. % % If texinfo.cnf is present on the system, read it. % Useful for site-wide @afourpaper, etc. \openin 1 texinfo.cnf \ifeof 1 \else \input texinfo.cnf \fi \closein 1 % \comment % Ignore the actual filename. } % Called from \setfilename. % \def\openindices{% \newindex{cp}% \newcodeindex{fn}% \newcodeindex{vr}% \newcodeindex{tp}% \newcodeindex{ky}% \newcodeindex{pg}% } % @bye. \outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} \message{pdf,} % adobe `portable' document format \newcount\tempnum \newcount\lnkcount \newtoks\filename \newcount\filenamelength \newcount\pgn \newtoks\toksA \newtoks\toksB \newtoks\toksC \newtoks\toksD \newbox\boxA \newcount\countA \newif\ifpdf \newif\ifpdfmakepagedest % when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 % can be set). So we test for \relax and 0 as well as being undefined. \ifx\pdfoutput\thisisundefined \else \ifx\pdfoutput\relax \else \ifcase\pdfoutput \else \pdftrue \fi \fi \fi % PDF uses PostScript string constants for the names of xref targets, % for display in the outlines, and in other places. Thus, we have to % double any backslashes. Otherwise, a name like "\node" will be % interpreted as a newline (\n), followed by o, d, e. Not good. % % See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and % related messages. The final outcome is that it is up to the TeX user % to double the backslashes and otherwise make the string valid, so % that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to % do this reliably, so we use it. % #1 is a control sequence in which to do the replacements, % which we \xdef. \def\txiescapepdf#1{% \ifx\pdfescapestring\thisisundefined % No primitive available; should we give a warning or log? % Many times it won't matter. \else % The expandable \pdfescapestring primitive escapes parentheses, % backslashes, and other special chars. \xdef#1{\pdfescapestring{#1}}% \fi } \newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images with PDF output, and none of those formats could be found. (.eps cannot be supported due to the design of the PDF format; use regular TeX (DVI output) for that.)} \ifpdf % % Color manipulation macros based on pdfcolor.tex, % except using rgb instead of cmyk; the latter is said to render as a % very dark gray on-screen and a very dark halftone in print, instead % of actual black. \def\rgbDarkRed{0.50 0.09 0.12} \def\rgbBlack{0 0 0} % % k sets the color for filling (usual text, etc.); % K sets the color for stroking (thin rules, e.g., normal _'s). \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} % % Set color, and create a mark which defines \thiscolor accordingly, % so that \makeheadline knows which color to restore. \def\setcolor#1{% \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% \domark \pdfsetcolor{#1}% } % \def\maincolor{\rgbBlack} \pdfsetcolor{\maincolor} \edef\thiscolor{\maincolor} \def\lastcolordefs{} % \def\makefootline{% \baselineskip24pt \line{\pdfsetcolor{\maincolor}\the\footline}% } % \def\makeheadline{% \vbox to 0pt{% \vskip-22.5pt \line{% \vbox to8.5pt{}% % Extract \thiscolor definition from the marks. \getcolormarks % Typeset the headline with \maincolor, then restore the color. \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% }% \vss }% \nointerlineskip } % % \pdfcatalog{/PageMode /UseOutlines} % % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). \def\dopdfimage#1#2#3{% \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% % % pdftex (and the PDF format) support .pdf, .png, .jpg (among % others). Let's try in that order, PDF first since if % someone has a scalable image, presumably better to use that than a % bitmap. \let\pdfimgext=\empty \begingroup \openin 1 #1.pdf \ifeof 1 \openin 1 #1.PDF \ifeof 1 \openin 1 #1.png \ifeof 1 \openin 1 #1.jpg \ifeof 1 \openin 1 #1.jpeg \ifeof 1 \openin 1 #1.JPG \ifeof 1 \errhelp = \nopdfimagehelp \errmessage{Could not find image file #1 for pdf}% \else \gdef\pdfimgext{JPG}% \fi \else \gdef\pdfimgext{jpeg}% \fi \else \gdef\pdfimgext{jpg}% \fi \else \gdef\pdfimgext{png}% \fi \else \gdef\pdfimgext{PDF}% \fi \else \gdef\pdfimgext{pdf}% \fi \closein 1 \endgroup % % without \immediate, ancient pdftex seg faults when the same image is % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) \ifnum\pdftexversion < 14 \immediate\pdfimage \else \immediate\pdfximage \fi \ifdim \wd0 >0pt width \pdfimagewidth \fi \ifdim \wd2 >0pt height \pdfimageheight \fi \ifnum\pdftexversion<13 #1.\pdfimgext \else {#1.\pdfimgext}% \fi \ifnum\pdftexversion < 14 \else \pdfrefximage \pdflastximage \fi} % \def\pdfmkdest#1{{% % We have to set dummies so commands such as @code, and characters % such as \, aren't expanded when present in a section title. \indexnofonts \turnoffactive \makevalueexpandable \def\pdfdestname{#1}% \txiescapepdf\pdfdestname \safewhatsit{\pdfdest name{\pdfdestname} xyz}% }} % % used to mark target names; must be expandable. \def\pdfmkpgn#1{#1} % % by default, use a color that is dark enough to print on paper as % nearly black, but still distinguishable for online viewing. \def\urlcolor{\rgbDarkRed} \def\linkcolor{\rgbDarkRed} \def\endlink{\setcolor{\maincolor}\pdfendlink} % % Adding outlines to PDF; macros for calculating structure of outlines % come from Petr Olsak \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% \else \csname#1\endcsname \fi} \def\advancenumber#1{\tempnum=\expnumber{#1}\relax \advance\tempnum by 1 \expandafter\xdef\csname#1\endcsname{\the\tempnum}} % % #1 is the section text, which is what will be displayed in the % outline by the pdf viewer. #2 is the pdf expression for the number % of subentries (or empty, for subsubsections). #3 is the node text, % which might be empty if this toc entry had no corresponding node. % #4 is the page number % \def\dopdfoutline#1#2#3#4{% % Generate a link to the node text if that exists; else, use the % page number. We could generate a destination for the section % text in the case where a section has no node, but it doesn't % seem worth the trouble, since most documents are normally structured. \edef\pdfoutlinedest{#3}% \ifx\pdfoutlinedest\empty \def\pdfoutlinedest{#4}% \else \txiescapepdf\pdfoutlinedest \fi % % Also escape PDF chars in the display string. \edef\pdfoutlinetext{#1}% \txiescapepdf\pdfoutlinetext % \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% } % \def\pdfmakeoutlines{% \begingroup % Read toc silently, to get counts of subentries for \pdfoutline. \def\partentry##1##2##3##4{}% ignore parts in the outlines \def\numchapentry##1##2##3##4{% \def\thischapnum{##2}% \def\thissecnum{0}% \def\thissubsecnum{0}% }% \def\numsecentry##1##2##3##4{% \advancenumber{chap\thischapnum}% \def\thissecnum{##2}% \def\thissubsecnum{0}% }% \def\numsubsecentry##1##2##3##4{% \advancenumber{sec\thissecnum}% \def\thissubsecnum{##2}% }% \def\numsubsubsecentry##1##2##3##4{% \advancenumber{subsec\thissubsecnum}% }% \def\thischapnum{0}% \def\thissecnum{0}% \def\thissubsecnum{0}% % % use \def rather than \let here because we redefine \chapentry et % al. a second time, below. \def\appentry{\numchapentry}% \def\appsecentry{\numsecentry}% \def\appsubsecentry{\numsubsecentry}% \def\appsubsubsecentry{\numsubsubsecentry}% \def\unnchapentry{\numchapentry}% \def\unnsecentry{\numsecentry}% \def\unnsubsecentry{\numsubsecentry}% \def\unnsubsubsecentry{\numsubsubsecentry}% \readdatafile{toc}% % % Read toc second time, this time actually producing the outlines. % The `-' means take the \expnumber as the absolute number of % subentries, which we calculated on our first read of the .toc above. % % We use the node names as the destinations. \def\numchapentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% \def\numsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% \def\numsubsecentry##1##2##3##4{% \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% \def\numsubsubsecentry##1##2##3##4{% count is always zero \dopdfoutline{##1}{}{##3}{##4}}% % % PDF outlines are displayed using system fonts, instead of % document fonts. Therefore we cannot use special characters, % since the encoding is unknown. For example, the eogonek from % Latin 2 (0xea) gets translated to a | character. Info from % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. % % TODO this right, we have to translate 8-bit characters to % their "best" equivalent, based on the @documentencoding. Too % much work for too little return. Just use the ASCII equivalents % we use for the index sort strings. % \indexnofonts \setupdatafile % We can have normal brace characters in the PDF outlines, unlike % Texinfo index files. So set that up. \def\{{\lbracecharliteral}% \def\}{\rbracecharliteral}% \catcode`\\=\active \otherbackslash \input \tocreadfilename \endgroup } {\catcode`[=1 \catcode`]=2 \catcode`{=\other \catcode`}=\other \gdef\lbracecharliteral[{]% \gdef\rbracecharliteral[}]% ] % \def\skipspaces#1{\def\PP{#1}\def\D{|}% \ifx\PP\D\let\nextsp\relax \else\let\nextsp\skipspaces \addtokens{\filename}{\PP}% \advance\filenamelength by 1 \fi \nextsp} \def\getfilename#1{% \filenamelength=0 % If we don't expand the argument now, \skipspaces will get % snagged on things like "@value{foo}". \edef\temp{#1}% \expandafter\skipspaces\temp|\relax } \ifnum\pdftexversion < 14 \let \startlink \pdfannotlink \else \let \startlink \pdfstartlink \fi % make a live url in pdf output. \def\pdfurl#1{% \begingroup % it seems we really need yet another set of dummies; have not % tried to figure out what each command should do in the context % of @url. for now, just make @/ a no-op, that's the only one % people have actually reported a problem with. % \normalturnoffactive \def\@{@}% \let\/=\empty \makevalueexpandable % do we want to go so far as to use \indexnofonts instead of just % special-casing \var here? \def\var##1{##1}% % \leavevmode\setcolor{\urlcolor}% \startlink attr{/Border [0 0 0]}% user{/Subtype /Link /A << /S /URI /URI (#1) >>}% \endgroup} \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} \def\maketoks{% \expandafter\poptoks\the\toksA|ENDTOKS|\relax \ifx\first0\adn0 \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 \else \ifnum0=\countA\else\makelink\fi \ifx\first.\let\next=\done\else \let\next=\maketoks \addtokens{\toksB}{\the\toksD} \ifx\first,\addtokens{\toksB}{\space}\fi \fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next} \def\makelink{\addtokens{\toksB}% {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} \def\pdflink#1{% \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} \setcolor{\linkcolor}#1\endlink} \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} \else % non-pdf mode \let\pdfmkdest = \gobble \let\pdfurl = \gobble \let\endlink = \relax \let\setcolor = \gobble \let\pdfsetcolor = \gobble \let\pdfmakeoutlines = \relax \fi % \ifx\pdfoutput \message{fonts,} % Change the current font style to #1, remembering it in \curfontstyle. % For now, we do not accumulate font styles: @b{@i{foo}} prints foo in % italics, not bold italics. % \def\setfontstyle#1{% \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. \csname ten#1\endcsname % change the current font } % Select #1 fonts with the current style. % \def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} \def\rm{\fam=0 \setfontstyle{rm}} \def\it{\fam=\itfam \setfontstyle{it}} \def\sl{\fam=\slfam \setfontstyle{sl}} \def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} \def\tt{\fam=\ttfam \setfontstyle{tt}} % Unfortunately, we have to override this for titles and the like, since % in those cases "rm" is bold. Sigh. \def\rmisbold{\rm\def\curfontstyle{bf}} % Texinfo sort of supports the sans serif font style, which plain TeX does not. % So we set up a \sf. \newfam\sffam \def\sf{\fam=\sffam \setfontstyle{sf}} \let\li = \sf % Sometimes we call it \li, not \sf. % We don't need math for this font style. \def\ttsl{\setfontstyle{ttsl}} % Set the baselineskip to #1, and the lineskip and strut size % correspondingly. There is no deep meaning behind these magic numbers % used as factors; they just match (closely enough) what Knuth defined. % \def\lineskipfactor{.08333} \def\strutheightpercent{.70833} \def\strutdepthpercent {.29167} % % can get a sort of poor man's double spacing by redefining this. \def\baselinefactor{1} % \newdimen\textleading \def\setleading#1{% \dimen0 = #1\relax \normalbaselineskip = \baselinefactor\dimen0 \normallineskip = \lineskipfactor\normalbaselineskip \normalbaselines \setbox\strutbox =\hbox{% \vrule width0pt height\strutheightpercent\baselineskip depth \strutdepthpercent \baselineskip }% } % PDF CMaps. See also LaTeX's t1.cmap. % % do nothing with this by default. \expandafter\let\csname cmapOT1\endcsname\gobble \expandafter\let\csname cmapOT1IT\endcsname\gobble \expandafter\let\csname cmapOT1TT\endcsname\gobble % if we are producing pdf, and we have \pdffontattr, then define cmaps. % (\pdffontattr was introduced many years ago, but people still run % older pdftex's; it's easy to conditionalize, so we do.) \ifpdf \ifx\pdffontattr\thisisundefined \else \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1-0) %%Title: (TeX-OT1-0 TeX OT1 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1) /Supplement 0 >> def /CMapName /TeX-OT1-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <23> <26> <0023> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 40 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1IT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1IT-0) %%Title: (TeX-OT1IT-0 TeX OT1IT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1IT) /Supplement 0 >> def /CMapName /TeX-OT1IT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 8 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <25> <26> <0025> <28> <3B> <0028> <3F> <5B> <003F> <5D> <5E> <005D> <61> <7A> <0061> <7B> <7C> <2013> endbfrange 42 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <00660066> <0C> <00660069> <0D> <0066006C> <0E> <006600660069> <0F> <00660066006C> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <21> <0021> <22> <201D> <23> <0023> <24> <00A3> <27> <2019> <3C> <00A1> <3D> <003D> <3E> <00BF> <5C> <201C> <5F> <02D9> <60> <2018> <7D> <02DD> <7E> <007E> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1IT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% % % \cmapOT1TT \begingroup \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap %%DocumentNeededResources: ProcSet (CIDInit) %%IncludeResource: ProcSet (CIDInit) %%BeginResource: CMap (TeX-OT1TT-0) %%Title: (TeX-OT1TT-0 TeX OT1TT 0) %%Version: 1.000 %%EndComments /CIDInit /ProcSet findresource begin 12 dict begin begincmap /CIDSystemInfo << /Registry (TeX) /Ordering (OT1TT) /Supplement 0 >> def /CMapName /TeX-OT1TT-0 def /CMapType 2 def 1 begincodespacerange <00> <7F> endcodespacerange 5 beginbfrange <00> <01> <0393> <09> <0A> <03A8> <21> <26> <0021> <28> <5F> <0028> <61> <7E> <0061> endbfrange 32 beginbfchar <02> <0398> <03> <039B> <04> <039E> <05> <03A0> <06> <03A3> <07> <03D2> <08> <03A6> <0B> <2191> <0C> <2193> <0D> <0027> <0E> <00A1> <0F> <00BF> <10> <0131> <11> <0237> <12> <0060> <13> <00B4> <14> <02C7> <15> <02D8> <16> <00AF> <17> <02DA> <18> <00B8> <19> <00DF> <1A> <00E6> <1B> <0153> <1C> <00F8> <1D> <00C6> <1E> <0152> <1F> <00D8> <20> <2423> <27> <2019> <60> <2018> <7F> <00A8> endbfchar endcmap CMapName currentdict /CMap defineresource pop end end %%EndResource %%EOF }\endgroup \expandafter\edef\csname cmapOT1TT\endcsname#1{% \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% }% \fi\fi % Set the font macro #1 to the font named \fontprefix#2. % #3 is the font's design size, #4 is a scale factor, #5 is the CMap % encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit). % Example: % #1 = \textrm % #2 = \rmshape % #3 = 10 % #4 = \mainmagstep % #5 = OT1 % \def\setfont#1#2#3#4#5{% \font#1=\fontprefix#2#3 scaled #4 \csname cmap#5\endcsname#1% } % This is what gets called when #5 of \setfont is empty. \let\cmap\gobble % % (end of cmaps) % Use cm as the default font prefix. % To specify the font prefix, you must define \fontprefix % before you read in texinfo.tex. \ifx\fontprefix\thisisundefined \def\fontprefix{cm} \fi % Support font families that don't use the same naming scheme as CM. \def\rmshape{r} \def\rmbshape{bx} % where the normal face is bold \def\bfshape{b} \def\bxshape{bx} \def\ttshape{tt} \def\ttbshape{tt} \def\ttslshape{sltt} \def\itshape{ti} \def\itbshape{bxti} \def\slshape{sl} \def\slbshape{bxsl} \def\sfshape{ss} \def\sfbshape{ss} \def\scshape{csc} \def\scbshape{csc} % Definitions for a main text size of 11pt. (The default in Texinfo.) % \def\definetextfontsizexi{% % Text fonts (11.2pt, magstep1). \def\textnominalsize{11pt} \edef\mainmagstep{\magstephalf} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1095} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstep1}{OT1} \setfont\deftt\ttshape{10}{\magstep1}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter (and unnumbered) fonts (17.28pt). \def\chapnominalsize{17pt} \setfont\chaprm\rmbshape{12}{\magstep2}{OT1} \setfont\chapit\itbshape{10}{\magstep3}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep3}{OT1} \setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} \setfont\chapsf\sfbshape{17}{1000}{OT1} \let\chapbf=\chaprm \setfont\chapsc\scbshape{10}{\magstep3}{OT1} \font\chapi=cmmi12 scaled \magstep2 \font\chapsy=cmsy10 scaled \magstep3 \def\chapecsize{1728} % Section fonts (14.4pt). \def\secnominalsize{14pt} \setfont\secrm\rmbshape{12}{\magstep1}{OT1} \setfont\secit\itbshape{10}{\magstep2}{OT1IT} \setfont\secsl\slbshape{10}{\magstep2}{OT1} \setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\secsf\sfbshape{12}{\magstep1}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep2}{OT1} \font\seci=cmmi12 scaled \magstep1 \font\secsy=cmsy10 scaled \magstep2 \def\sececsize{1440} % Subsection fonts (13.15pt). \def\ssecnominalsize{13pt} \setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} \setfont\ssecit\itbshape{10}{1315}{OT1IT} \setfont\ssecsl\slbshape{10}{1315}{OT1} \setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} \setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1315}{OT1} \font\sseci=cmmi12 scaled \magstephalf \font\ssecsy=cmsy10 scaled 1315 \def\ssececsize{1200} % Reduced fonts for @acro in text (10pt). \def\reducednominalsize{10pt} \setfont\reducedrm\rmshape{10}{1000}{OT1} \setfont\reducedtt\ttshape{10}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{1000}{OT1} \setfont\reducedit\itshape{10}{1000}{OT1IT} \setfont\reducedsl\slshape{10}{1000}{OT1} \setfont\reducedsf\sfshape{10}{1000}{OT1} \setfont\reducedsc\scshape{10}{1000}{OT1} \setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} \font\reducedi=cmmi10 \font\reducedsy=cmsy10 \def\reducedecsize{1000} \textleading = 13.2pt % line spacing for 11pt CM \textfonts % reset the current fonts \rm } % end of 11pt text font size definitions, \definetextfontsizexi % Definitions to make the main text be 10pt Computer Modern, with % section, chapter, etc., sizes following suit. This is for the GNU % Press printing of the Emacs 22 manual. Maybe other manuals in the % future. Used with @smallbook, which sets the leading to 12pt. % \def\definetextfontsizex{% % Text fonts (10pt). \def\textnominalsize{10pt} \edef\mainmagstep{1000} \setfont\textrm\rmshape{10}{\mainmagstep}{OT1} \setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} \setfont\textbf\bfshape{10}{\mainmagstep}{OT1} \setfont\textit\itshape{10}{\mainmagstep}{OT1IT} \setfont\textsl\slshape{10}{\mainmagstep}{OT1} \setfont\textsf\sfshape{10}{\mainmagstep}{OT1} \setfont\textsc\scshape{10}{\mainmagstep}{OT1} \setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} \font\texti=cmmi10 scaled \mainmagstep \font\textsy=cmsy10 scaled \mainmagstep \def\textecsize{1000} % A few fonts for @defun names and args. \setfont\defbf\bfshape{10}{\magstephalf}{OT1} \setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} \setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} \def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} % Fonts for indices, footnotes, small examples (9pt). \def\smallnominalsize{9pt} \setfont\smallrm\rmshape{9}{1000}{OT1} \setfont\smalltt\ttshape{9}{1000}{OT1TT} \setfont\smallbf\bfshape{10}{900}{OT1} \setfont\smallit\itshape{9}{1000}{OT1IT} \setfont\smallsl\slshape{9}{1000}{OT1} \setfont\smallsf\sfshape{9}{1000}{OT1} \setfont\smallsc\scshape{10}{900}{OT1} \setfont\smallttsl\ttslshape{10}{900}{OT1TT} \font\smalli=cmmi9 \font\smallsy=cmsy9 \def\smallecsize{0900} % Fonts for small examples (8pt). \def\smallernominalsize{8pt} \setfont\smallerrm\rmshape{8}{1000}{OT1} \setfont\smallertt\ttshape{8}{1000}{OT1TT} \setfont\smallerbf\bfshape{10}{800}{OT1} \setfont\smallerit\itshape{8}{1000}{OT1IT} \setfont\smallersl\slshape{8}{1000}{OT1} \setfont\smallersf\sfshape{8}{1000}{OT1} \setfont\smallersc\scshape{10}{800}{OT1} \setfont\smallerttsl\ttslshape{10}{800}{OT1TT} \font\smalleri=cmmi8 \font\smallersy=cmsy8 \def\smallerecsize{0800} % Fonts for title page (20.4pt): \def\titlenominalsize{20pt} \setfont\titlerm\rmbshape{12}{\magstep3}{OT1} \setfont\titleit\itbshape{10}{\magstep4}{OT1IT} \setfont\titlesl\slbshape{10}{\magstep4}{OT1} \setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} \setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} \setfont\titlesf\sfbshape{17}{\magstep1}{OT1} \let\titlebf=\titlerm \setfont\titlesc\scbshape{10}{\magstep4}{OT1} \font\titlei=cmmi12 scaled \magstep3 \font\titlesy=cmsy10 scaled \magstep4 \def\titleecsize{2074} % Chapter fonts (14.4pt). \def\chapnominalsize{14pt} \setfont\chaprm\rmbshape{12}{\magstep1}{OT1} \setfont\chapit\itbshape{10}{\magstep2}{OT1IT} \setfont\chapsl\slbshape{10}{\magstep2}{OT1} \setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} \setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} \setfont\chapsf\sfbshape{12}{\magstep1}{OT1} \let\chapbf\chaprm \setfont\chapsc\scbshape{10}{\magstep2}{OT1} \font\chapi=cmmi12 scaled \magstep1 \font\chapsy=cmsy10 scaled \magstep2 \def\chapecsize{1440} % Section fonts (12pt). \def\secnominalsize{12pt} \setfont\secrm\rmbshape{12}{1000}{OT1} \setfont\secit\itbshape{10}{\magstep1}{OT1IT} \setfont\secsl\slbshape{10}{\magstep1}{OT1} \setfont\sectt\ttbshape{12}{1000}{OT1TT} \setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} \setfont\secsf\sfbshape{12}{1000}{OT1} \let\secbf\secrm \setfont\secsc\scbshape{10}{\magstep1}{OT1} \font\seci=cmmi12 \font\secsy=cmsy10 scaled \magstep1 \def\sececsize{1200} % Subsection fonts (10pt). \def\ssecnominalsize{10pt} \setfont\ssecrm\rmbshape{10}{1000}{OT1} \setfont\ssecit\itbshape{10}{1000}{OT1IT} \setfont\ssecsl\slbshape{10}{1000}{OT1} \setfont\ssectt\ttbshape{10}{1000}{OT1TT} \setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} \setfont\ssecsf\sfbshape{10}{1000}{OT1} \let\ssecbf\ssecrm \setfont\ssecsc\scbshape{10}{1000}{OT1} \font\sseci=cmmi10 \font\ssecsy=cmsy10 \def\ssececsize{1000} % Reduced fonts for @acro in text (9pt). \def\reducednominalsize{9pt} \setfont\reducedrm\rmshape{9}{1000}{OT1} \setfont\reducedtt\ttshape{9}{1000}{OT1TT} \setfont\reducedbf\bfshape{10}{900}{OT1} \setfont\reducedit\itshape{9}{1000}{OT1IT} \setfont\reducedsl\slshape{9}{1000}{OT1} \setfont\reducedsf\sfshape{9}{1000}{OT1} \setfont\reducedsc\scshape{10}{900}{OT1} \setfont\reducedttsl\ttslshape{10}{900}{OT1TT} \font\reducedi=cmmi9 \font\reducedsy=cmsy9 \def\reducedecsize{0900} \divide\parskip by 2 % reduce space between paragraphs \textleading = 12pt % line spacing for 10pt CM \textfonts % reset the current fonts \rm } % end of 10pt text font size definitions, \definetextfontsizex % We provide the user-level command % @fonttextsize 10 % (or 11) to redefine the text font size. pt is assumed. % \def\xiword{11} \def\xword{10} \def\xwordpt{10pt} % \parseargdef\fonttextsize{% \def\textsizearg{#1}% %\wlog{doing @fonttextsize \textsizearg}% % % Set \globaldefs so that documents can use this inside @tex, since % makeinfo 4.8 does not support it, but we need it nonetheless. % \begingroup \globaldefs=1 \ifx\textsizearg\xword \definetextfontsizex \else \ifx\textsizearg\xiword \definetextfontsizexi \else \errhelp=\EMsimple \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} \fi\fi \endgroup } % In order for the font changes to affect most math symbols and letters, % we have to define the \textfont of the standard families. Since % texinfo doesn't allow for producing subscripts and superscripts except % in the main text, we don't bother to reset \scriptfont and % \scriptscriptfont (which would also require loading a lot more fonts). % \def\resetmathfonts{% \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf \textfont\ttfam=\tentt \textfont\sffam=\tensf } % The font-changing commands redefine the meanings of \tenSTYLE, instead % of just \STYLE. We do this because \STYLE needs to also set the % current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire % \tenSTYLE to set the current font. % % Each font-changing command also sets the names \lsize (one size lower) % and \lllsize (three sizes lower). These relative commands are used in % the LaTeX logo and acronyms. % % This all needs generalizing, badly. % \def\textfonts{% \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl \def\curfontsize{text}% \def\lsize{reduced}\def\lllsize{smaller}% \resetmathfonts \setleading{\textleading}} \def\titlefonts{% \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy \let\tenttsl=\titlettsl \def\curfontsize{title}% \def\lsize{chap}\def\lllsize{subsec}% \resetmathfonts \setleading{27pt}} \def\titlefont#1{{\titlefonts\rmisbold #1}} \def\chapfonts{% \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl \def\curfontsize{chap}% \def\lsize{sec}\def\lllsize{text}% \resetmathfonts \setleading{19pt}} \def\secfonts{% \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl \def\curfontsize{sec}% \def\lsize{subsec}\def\lllsize{reduced}% \resetmathfonts \setleading{16pt}} \def\subsecfonts{% \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl \def\curfontsize{ssec}% \def\lsize{text}\def\lllsize{small}% \resetmathfonts \setleading{15pt}} \let\subsubsecfonts = \subsecfonts \def\reducedfonts{% \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy \let\tenttsl=\reducedttsl \def\curfontsize{reduced}% \def\lsize{small}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallfonts{% \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy \let\tenttsl=\smallttsl \def\curfontsize{small}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{10.5pt}} \def\smallerfonts{% \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy \let\tenttsl=\smallerttsl \def\curfontsize{smaller}% \def\lsize{smaller}\def\lllsize{smaller}% \resetmathfonts \setleading{9.5pt}} % Fonts for short table of contents. \setfont\shortcontrm\rmshape{12}{1000}{OT1} \setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 \setfont\shortcontsl\slshape{12}{1000}{OT1} \setfont\shortconttt\ttshape{12}{1000}{OT1TT} % Define these just so they can be easily changed for other fonts. \def\angleleft{$\langle$} \def\angleright{$\rangle$} % Set the fonts to use with the @small... environments. \let\smallexamplefonts = \smallfonts % About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample % can fit this many characters: % 8.5x11=86 smallbook=72 a4=90 a5=69 % If we use \scriptfonts (8pt), then we can fit this many characters: % 8.5x11=90+ smallbook=80 a4=90+ a5=77 % For me, subjectively, the few extra characters that fit aren't worth % the additional smallness of 8pt. So I'm making the default 9pt. % % By the way, for comparison, here's what fits with @example (10pt): % 8.5x11=71 smallbook=60 a4=75 a5=58 % --karl, 24jan03. % Set up the default fonts, so we can use them for creating boxes. % \definetextfontsizexi \message{markup,} % Check if we are currently using a typewriter font. Since all the % Computer Modern typewriter fonts have zero interword stretch (and % shrink), and it is reasonable to expect all typewriter fonts to have % this property, we can check that font parameter. % \def\ifmonospace{\ifdim\fontdimen3\font=0pt } % Markup style infrastructure. \defmarkupstylesetup\INITMACRO will % define and register \INITMACRO to be called on markup style changes. % \INITMACRO can check \currentmarkupstyle for the innermost % style and the set of \ifmarkupSTYLE switches for all styles % currently in effect. \newif\ifmarkupvar \newif\ifmarkupsamp \newif\ifmarkupkey %\newif\ifmarkupfile % @file == @samp. %\newif\ifmarkupoption % @option == @samp. \newif\ifmarkupcode \newif\ifmarkupkbd %\newif\ifmarkupenv % @env == @code. %\newif\ifmarkupcommand % @command == @code. \newif\ifmarkuptex % @tex (and part of @math, for now). \newif\ifmarkupexample \newif\ifmarkupverb \newif\ifmarkupverbatim \let\currentmarkupstyle\empty \def\setupmarkupstyle#1{% \csname markup#1true\endcsname \def\currentmarkupstyle{#1}% \markupstylesetup } \let\markupstylesetup\empty \def\defmarkupstylesetup#1{% \expandafter\def\expandafter\markupstylesetup \expandafter{\markupstylesetup #1}% \def#1% } % Markup style setup for left and right quotes. \defmarkupstylesetup\markupsetuplq{% \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuplqdefault \else \temp \fi } \defmarkupstylesetup\markupsetuprq{% \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname \ifx\temp\relax \markupsetuprqdefault \else \temp \fi } { \catcode`\'=\active \catcode`\`=\active \gdef\markupsetuplqdefault{\let`\lq} \gdef\markupsetuprqdefault{\let'\rq} \gdef\markupsetcodequoteleft{\let`\codequoteleft} \gdef\markupsetcodequoteright{\let'\codequoteright} } \let\markupsetuplqcode \markupsetcodequoteleft \let\markupsetuprqcode \markupsetcodequoteright % \let\markupsetuplqexample \markupsetcodequoteleft \let\markupsetuprqexample \markupsetcodequoteright % \let\markupsetuplqkbd \markupsetcodequoteleft \let\markupsetuprqkbd \markupsetcodequoteright % \let\markupsetuplqsamp \markupsetcodequoteleft \let\markupsetuprqsamp \markupsetcodequoteright % \let\markupsetuplqverb \markupsetcodequoteleft \let\markupsetuprqverb \markupsetcodequoteright % \let\markupsetuplqverbatim \markupsetcodequoteleft \let\markupsetuprqverbatim \markupsetcodequoteright % Allow an option to not use regular directed right quote/apostrophe % (char 0x27), but instead the undirected quote from cmtt (char 0x0d). % The undirected quote is ugly, so don't make it the default, but it % works for pasting with more pdf viewers (at least evince), the % lilypond developers report. xpdf does work with the regular 0x27. % \def\codequoteright{% \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax '% \else \char'15 \fi \else \char'15 \fi } % % and a similar option for the left quote char vs. a grave accent. % Modern fonts display ASCII 0x60 as a grave accent, so some people like % the code environments to do likewise. % \def\codequoteleft{% \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax % [Knuth] pp. 380,381,391 % \relax disables Spanish ligatures ?` and !` of \tt font. \relax`% \else \char'22 \fi \else \char'22 \fi } % Commands to set the quote options. % \parseargdef\codequoteundirected{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequoteundirected\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequoteundirected\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}% \fi\fi } % \parseargdef\codequotebacktick{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxicodequotebacktick\endcsname = t% \else\ifx\temp\offword \expandafter\let\csname SETtxicodequotebacktick\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}% \fi\fi } % [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. \def\noligaturesquoteleft{\relax\lq} % Count depth in font-changes, for error checks \newcount\fontdepth \fontdepth=0 % Font commands. % #1 is the font command (\sl or \it), #2 is the text to slant. % If we are in a monospaced environment, however, 1) always use \ttsl, % and 2) do not add an italic correction. \def\dosmartslant#1#2{% \ifusingtt {{\ttsl #2}\let\next=\relax}% {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}% \next } \def\smartslanted{\dosmartslant\sl} \def\smartitalic{\dosmartslant\it} % Output an italic correction unless \next (presumed to be the following % character) is such as not to need one. \def\smartitaliccorrection{% \ifx\next,% \else\ifx\next-% \else\ifx\next.% \else\ptexslash \fi\fi\fi \aftersmartic } % Unconditional use \ttsl, and no ic. @var is set to this for defuns. \def\ttslanted#1{{\ttsl #1}} % @cite is like \smartslanted except unconditionally use \sl. We never want % ttsl for book titles, do we? \def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection} \def\aftersmartic{} \def\var#1{% \let\saveaftersmartic = \aftersmartic \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}% \smartslanted{#1}% } \let\i=\smartitalic \let\slanted=\smartslanted \let\dfn=\smartslanted \let\emph=\smartitalic % Explicit font changes: @r, @sc, undocumented @ii. \def\r#1{{\rm #1}} % roman font \def\sc#1{{\smallcaps#1}} % smallcaps font \def\ii#1{{\it #1}} % italic font % @b, explicit bold. Also @strong. \def\b#1{{\bf #1}} \let\strong=\b % @sansserif, explicit sans. \def\sansserif#1{{\sf #1}} % We can't just use \exhyphenpenalty, because that only has effect at % the end of a paragraph. Restore normal hyphenation at the end of the % group within which \nohyphenation is presumably called. % \def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} \def\restorehyphenation{\hyphenchar\font = `- } % Set sfcode to normal for the chars that usually have another value. % Can't use plain's \frenchspacing because it uses the `\x notation, and % sometimes \x has an active definition that messes things up. % \catcode`@=11 \def\plainfrenchspacing{% \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m \def\endofsentencespacefactor{1000}% for @. and friends } \def\plainnonfrenchspacing{% \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 \def\endofsentencespacefactor{3000}% for @. and friends } \catcode`@=\other \def\endofsentencespacefactor{3000}% default % @t, explicit typewriter. \def\t#1{% {\tt \rawbackslash \plainfrenchspacing #1}% \null } % @samp. \def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} % @indicateurl is \samp, that is, with quotes. \let\indicateurl=\samp % @code (and similar) prints in typewriter, but with spaces the same % size as normal in the surrounding text, without hyphenation, etc. % This is a subroutine for that. \def\tclose#1{% {% % Change normal interword space to be same as for the current font. \spaceskip = \fontdimen2\font % % Switch to typewriter. \tt % % But `\ ' produces the large typewriter interword space. \def\ {{\spaceskip = 0pt{} }}% % % Turn off hyphenation. \nohyphenation % \rawbackslash \plainfrenchspacing #1% }% \null % reset spacefactor to 1000 } % We *must* turn on hyphenation at `-' and `_' in @code. % Otherwise, it is too hard to avoid overfull hboxes % in the Emacs manual, the Library manual, etc. % % Unfortunately, TeX uses one parameter (\hyphenchar) to control % both hyphenation at - and hyphenation within words. % We must therefore turn them both off (\tclose does that) % and arrange explicitly to hyphenate at a dash. % -- rms. { \catcode`\-=\active \catcode`\_=\active \catcode`\'=\active \catcode`\`=\active \global\let'=\rq \global\let`=\lq % default definitions % \global\def\code{\begingroup \setupmarkupstyle{code}% % The following should really be moved into \setupmarkupstyle handlers. \catcode\dashChar=\active \catcode\underChar=\active \ifallowcodebreaks \let-\codedash \let_\codeunder \else \let-\normaldash \let_\realunder \fi \codex } } \def\codex #1{\tclose{#1}\endgroup} \def\normaldash{-} \def\codedash{-\discretionary{}{}{}} \def\codeunder{% % this is all so @math{@code{var_name}+1} can work. In math mode, _ % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) % will therefore expand the active definition of _, which is us % (inside @code that is), therefore an endless loop. \ifusingtt{\ifmmode \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. \else\normalunderscore \fi \discretionary{}{}{}}% {\_}% } % An additional complication: the above will allow breaks after, e.g., % each of the four underscores in __typeof__. This is bad. % @allowcodebreaks provides a document-level way to turn breaking at - % and _ on and off. % \newif\ifallowcodebreaks \allowcodebreakstrue \def\keywordtrue{true} \def\keywordfalse{false} \parseargdef\allowcodebreaks{% \def\txiarg{#1}% \ifx\txiarg\keywordtrue \allowcodebreakstrue \else\ifx\txiarg\keywordfalse \allowcodebreaksfalse \else \errhelp = \EMsimple \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}% \fi\fi } % For @command, @env, @file, @option quotes seem unnecessary, % so use \code rather than \samp. \let\command=\code \let\env=\code \let\file=\code \let\option=\code % @uref (abbreviation for `urlref') takes an optional (comma-separated) % second argument specifying the text to display and an optional third % arg as text to display instead of (rather than in addition to) the url % itself. First (mandatory) arg is the url. % (This \urefnobreak definition isn't used now, leaving it for a while % for comparison.) \def\urefnobreak#1{\dourefnobreak #1,,,\finish} \def\dourefnobreak#1,#2,#3,#4\finish{\begingroup \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url \fi \else \code{#1}% only url given, so show it \fi \fi \endlink \endgroup} % This \urefbreak definition is the active one. \def\urefbreak{\begingroup \urefcatcodes \dourefbreak} \let\uref=\urefbreak \def\dourefbreak#1{\urefbreakfinish #1,,,\finish} \def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example \unsepspaces \pdfurl{#1}% \setbox0 = \hbox{\ignorespaces #3}% \ifdim\wd0 > 0pt \unhbox0 % third arg given, show only that \else \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0 > 0pt \ifpdf \unhbox0 % PDF: 2nd arg given, show only it \else \unhbox0\ (\urefcode{#1})% DVI: 2nd arg given, show both it and url \fi \else \urefcode{#1}% only url given, so show it \fi \fi \endlink \endgroup} % Allow line breaks around only a few characters (only). \def\urefcatcodes{% \catcode\ampChar=\active \catcode\dotChar=\active \catcode\hashChar=\active \catcode\questChar=\active \catcode\slashChar=\active } { \urefcatcodes % \global\def\urefcode{\begingroup \setupmarkupstyle{code}% \urefcatcodes \let&\urefcodeamp \let.\urefcodedot \let#\urefcodehash \let?\urefcodequest \let/\urefcodeslash \codex } % % By default, they are just regular characters. \global\def&{\normalamp} \global\def.{\normaldot} \global\def#{\normalhash} \global\def?{\normalquest} \global\def/{\normalslash} } % we put a little stretch before and after the breakable chars, to help % line breaking of long url's. The unequal skips make look better in % cmtt at least, especially for dots. \def\urefprestretch{\urefprebreak \hskip0pt plus.13em } \def\urefpoststretch{\urefpostbreak \hskip0pt plus.1em } % \def\urefcodeamp{\urefprestretch \&\urefpoststretch} \def\urefcodedot{\urefprestretch .\urefpoststretch} \def\urefcodehash{\urefprestretch \#\urefpoststretch} \def\urefcodequest{\urefprestretch ?\urefpoststretch} \def\urefcodeslash{\futurelet\next\urefcodeslashfinish} { \catcode`\/=\active \global\def\urefcodeslashfinish{% \urefprestretch \slashChar % Allow line break only after the final / in a sequence of % slashes, to avoid line break between the slashes in http://. \ifx\next/\else \urefpoststretch \fi } } % One more complication: by default we'll break after the special % characters, but some people like to break before the special chars, so % allow that. Also allow no breaking at all, for manual control. % \parseargdef\urefbreakstyle{% \def\txiarg{#1}% \ifx\txiarg\wordnone \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordbefore \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak} \else\ifx\txiarg\wordafter \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak} \else \errhelp = \EMsimple \errmessage{Unknown @urefbreakstyle setting `\txiarg'}% \fi\fi\fi } \def\wordafter{after} \def\wordbefore{before} \def\wordnone{none} \urefbreakstyle after % @url synonym for @uref, since that's how everyone uses it. % \let\url=\uref % rms does not like angle brackets --karl, 17may97. % So now @email is just like @uref, unless we are pdf. % %\def\email#1{\angleleft{\tt #1}\angleright} \ifpdf \def\email#1{\doemail#1,,\finish} \def\doemail#1,#2,#3\finish{\begingroup \unsepspaces \pdfurl{mailto:#1}% \setbox0 = \hbox{\ignorespaces #2}% \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi \endlink \endgroup} \else \let\email=\uref \fi % @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), % `example' (@kbd uses ttsl only inside of @example and friends), % or `code' (@kbd uses normal tty font always). \parseargdef\kbdinputstyle{% \def\txiarg{#1}% \ifx\txiarg\worddistinct \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% \else\ifx\txiarg\wordexample \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% \else\ifx\txiarg\wordcode \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% \else \errhelp = \EMsimple \errmessage{Unknown @kbdinputstyle setting `\txiarg'}% \fi\fi\fi } \def\worddistinct{distinct} \def\wordexample{example} \def\wordcode{code} % Default is `distinct'. \kbdinputstyle distinct % @kbd is like @code, except that if the argument is just one @key command, % then @kbd has no effect. \def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}} \def\xkey{\key} \def\kbdsub#1#2#3\par{% \def\one{#1}\def\three{#3}\def\threex{??}% \ifx\one\xkey\ifx\threex\three \key{#2}% \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi } % definition of @key that produces a lozenge. Doesn't adjust to text size. %\setfont\keyrm\rmshape{8}{1000}{OT1} %\font\keysy=cmsy9 %\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% % \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% % \vbox{\hrule\kern-0.4pt % \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% % \kern-0.4pt\hrule}% % \kern-.06em\raise0.4pt\hbox{\angleright}}}} % definition of @key with no lozenge. If the current font is already % monospace, don't change it; that way, we respect @kbdinputstyle. But % if it isn't monospace, then use \tt. % \def\key#1{{\setupmarkupstyle{key}% \nohyphenation \ifmonospace\else\tt\fi #1}\null} % @clicksequence{File @click{} Open ...} \def\clicksequence#1{\begingroup #1\endgroup} % @clickstyle @arrow (by default) \parseargdef\clickstyle{\def\click{#1}} \def\click{\arrow} % Typeset a dimension, e.g., `in' or `pt'. The only reason for the % argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. % \def\dmn#1{\thinspace #1} % @l was never documented to mean ``switch to the Lisp font'', % and it is not used as such in any manual I can find. We need it for % Polish suppressed-l. --karl, 22sep96. %\def\l#1{{\li #1}\null} % @acronym for "FBI", "NATO", and the like. % We print this one point size smaller, since it's intended for % all-uppercase. % \def\acronym#1{\doacronym #1,,\finish} \def\doacronym#1,#2,#3\finish{% {\selectfonts\lsize #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @abbr for "Comput. J." and the like. % No font change, but don't do end-of-sentence spacing. % \def\abbr#1{\doabbr #1,,\finish} \def\doabbr#1,#2,#3\finish{% {\plainfrenchspacing #1}% \def\temp{#2}% \ifx\temp\empty \else \space ({\unsepspaces \ignorespaces \temp \unskip})% \fi \null % reset \spacefactor=1000 } % @asis just yields its argument. Used with @table, for example. % \def\asis#1{#1} % @math outputs its argument in math mode. % % One complication: _ usually means subscripts, but it could also mean % an actual _ character, as in @math{@var{some_variable} + 1}. So make % _ active, and distinguish by seeing if the current family is \slfam, % which is what @var uses. { \catcode`\_ = \active \gdef\mathunderscore{% \catcode`\_=\active \def_{\ifnum\fam=\slfam \_\else\sb\fi}% } } % Another complication: we want \\ (and @\) to output a math (or tt) \. % FYI, plain.tex uses \\ as a temporary control sequence (for no % particular reason), but this is not advertised and we don't care. % % The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. \def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} % \def\math{% \tex \mathunderscore \let\\ = \mathbackslash \mathactive % make the texinfo accent commands work in math mode \let\"=\ddot \let\'=\acute \let\==\bar \let\^=\hat \let\`=\grave \let\u=\breve \let\v=\check \let\~=\tilde \let\dotaccent=\dot $\finishmath } \def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. % Some active characters (such as <) are spaced differently in math. % We have to reset their definitions in case the @math was an argument % to a command which sets the catcodes (such as @item or @section). % { \catcode`^ = \active \catcode`< = \active \catcode`> = \active \catcode`+ = \active \catcode`' = \active \gdef\mathactive{% \let^ = \ptexhat \let< = \ptexless \let> = \ptexgtr \let+ = \ptexplus \let' = \ptexquoteright } } % ctrl is no longer a Texinfo command, but leave this definition for fun. \def\ctrl #1{{\tt \rawbackslash \hat}#1} % @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}. % Ignore unless FMTNAME == tex; then it is like @iftex and @tex, % except specified as a normal braced arg, so no newlines to worry about. % \def\outfmtnametex{tex} % \long\def\inlinefmt#1{\doinlinefmt #1,\finish} \long\def\doinlinefmt#1,#2,\finish{% \def\inlinefmtname{#1}% \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi } % For raw, must switch into @tex before parsing the argument, to avoid % setting catcodes prematurely. Doing it this way means that, for % example, @inlineraw{html, foo{bar} gets a parse error instead of being % ignored. But this isn't important because if people want a literal % *right* brace they would have to use a command anyway, so they may as % well use a command to get a left brace too. We could re-use the % delimiter character idea from \verb, but it seems like overkill. % \long\def\inlineraw{\tex \doinlineraw} \long\def\doinlineraw#1{\doinlinerawtwo #1,\finish} \def\doinlinerawtwo#1,#2,\finish{% \def\inlinerawname{#1}% \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi \endgroup % close group opened by \tex. } \message{glyphs,} % and logos. % @@ prints an @, as does @atchar{}. \def\@{\char64 } \let\atchar=\@ % @{ @} @lbracechar{} @rbracechar{} all generate brace characters. % Unless we're in typewriter, use \ecfont because the CM text fonts do % not have braces, and we don't want to switch into math. \def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}} \def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}} \let\{=\mylbrace \let\lbracechar=\{ \let\}=\myrbrace \let\rbracechar=\} \begingroup % Definitions to produce \{ and \} commands for indices, % and @{ and @} for the aux/toc files. \catcode`\{ = \other \catcode`\} = \other \catcode`\[ = 1 \catcode`\] = 2 \catcode`\! = 0 \catcode`\\ = \other !gdef!lbracecmd[\{]% !gdef!rbracecmd[\}]% !gdef!lbraceatcmd[@{]% !gdef!rbraceatcmd[@}]% !endgroup % @comma{} to avoid , parsing problems. \let\comma = , % Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent % Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. \let\, = \ptexc \let\dotaccent = \ptexdot \def\ringaccent#1{{\accent23 #1}} \let\tieaccent = \ptext \let\ubaraccent = \ptexb \let\udotaccent = \d % Other special characters: @questiondown @exclamdown @ordf @ordm % Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. \def\questiondown{?`} \def\exclamdown{!`} \def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} \def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} % Dotless i and dotless j, used for accents. \def\imacro{i} \def\jmacro{j} \def\dotless#1{% \def\temp{#1}% \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi \else \errmessage{@dotless can be used only with i or j}% \fi\fi } % The \TeX{} logo, as in plain, but resetting the spacing so that a % period following counts as ending a sentence. (Idea found in latex.) % \edef\TeX{\TeX \spacefactor=1000 } % @LaTeX{} logo. Not quite the same results as the definition in % latex.ltx, since we use a different font for the raised A; it's most % convenient for us to use an explicitly smaller font, rather than using % the \scriptstyle font (since we don't reset \scriptstyle and % \scriptscriptstyle). % \def\LaTeX{% L\kern-.36em {\setbox0=\hbox{T}% \vbox to \ht0{\hbox{% \ifx\textnominalsize\xwordpt % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX. % Revert to plain's \scriptsize, which is 7pt. \count255=\the\fam $\fam\count255 \scriptstyle A$% \else % For 11pt, we can use our lllsize. \selectfonts\lllsize A% \fi }% \vss }}% \kern-.15em \TeX } % Some math mode symbols. \def\bullet{$\ptexbullet$} \def\geq{\ifmmode \ge\else $\ge$\fi} \def\leq{\ifmmode \le\else $\le$\fi} \def\minus{\ifmmode -\else $-$\fi} % @dots{} outputs an ellipsis using the current font. % We do .5em per period so that it has the same spacing in the cm % typewriter fonts as three actual period characters; on the other hand, % in other typewriter fonts three periods are wider than 1.5em. So do % whichever is larger. % \def\dots{% \leavevmode \setbox0=\hbox{...}% get width of three periods \ifdim\wd0 > 1.5em \dimen0 = \wd0 \else \dimen0 = 1.5em \fi \hbox to \dimen0{% \hskip 0pt plus.25fil .\hskip 0pt plus1fil .\hskip 0pt plus1fil .\hskip 0pt plus.5fil }% } % @enddots{} is an end-of-sentence ellipsis. % \def\enddots{% \dots \spacefactor=\endofsentencespacefactor } % @point{}, @result{}, @expansion{}, @print{}, @equiv{}. % % Since these characters are used in examples, they should be an even number of % \tt widths. Each \tt character is 1en, so two makes it 1em. % \def\point{$\star$} \def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} \def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} \def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} \def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} \def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} % The @error{} command. % Adapted from the TeXbook's \boxit. % \newbox\errorbox % {\tentt \global\dimen0 = 3em}% Width of the box. \dimen2 = .55pt % Thickness of rules % The text. (`r' is open on the right, `e' somewhat less so on the left.) \setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt} % \setbox\errorbox=\hbox to \dimen0{\hfil \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. \advance\hsize by -2\dimen2 % Rules. \vbox{% \hrule height\dimen2 \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. \kern3pt\vrule width\dimen2}% Space to right. \hrule height\dimen2} \hfil} % \def\error{\leavevmode\lower.7ex\copy\errorbox} % @pounds{} is a sterling sign, which Knuth put in the CM italic font. % \def\pounds{{\it\$}} % @euro{} comes from a separate font, depending on the current style. % We use the free feym* fonts from the eurosym package by Henrik % Theiling, which support regular, slanted, bold and bold slanted (and % "outlined" (blackboard board, sort of) versions, which we don't need). % It is available from http://www.ctan.org/tex-archive/fonts/eurosym. % % Although only regular is the truly official Euro symbol, we ignore % that. The Euro is designed to be slightly taller than the regular % font height. % % feymr - regular % feymo - slanted % feybr - bold % feybo - bold slanted % % There is no good (free) typewriter version, to my knowledge. % A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. % Hmm. % % Also doesn't work in math. Do we need to do math with euro symbols? % Hope not. % % \def\euro{{\eurofont e}} \def\eurofont{% % We set the font at each command, rather than predefining it in % \textfonts and the other font-switching commands, so that % installations which never need the symbol don't have to have the % font installed. % % There is only one designed size (nominal 10pt), so we always scale % that to the current nominal size. % % By the way, simply using "at 1em" works for cmr10 and the like, but % does not work for cmbx10 and other extended/shrunken fonts. % \def\eurosize{\csname\curfontsize nominalsize\endcsname}% % \ifx\curfontstyle\bfstylename % bold: \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize \else % regular: \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize \fi \thiseurofont } % Glyphs from the EC fonts. We don't use \let for the aliases, because % sometimes we redefine the original macro, and the alias should reflect % the redefinition. % % Use LaTeX names for the Icelandic letters. \def\DH{{\ecfont \char"D0}} % Eth \def\dh{{\ecfont \char"F0}} % eth \def\TH{{\ecfont \char"DE}} % Thorn \def\th{{\ecfont \char"FE}} % thorn % \def\guillemetleft{{\ecfont \char"13}} \def\guillemotleft{\guillemetleft} \def\guillemetright{{\ecfont \char"14}} \def\guillemotright{\guillemetright} \def\guilsinglleft{{\ecfont \char"0E}} \def\guilsinglright{{\ecfont \char"0F}} \def\quotedblbase{{\ecfont \char"12}} \def\quotesinglbase{{\ecfont \char"0D}} % % This positioning is not perfect (see the ogonek LaTeX package), but % we have the precomposed glyphs for the most common cases. We put the % tests to use those glyphs in the single \ogonek macro so we have fewer % dummy definitions to worry about for index entries, etc. % % ogonek is also used with other letters in Lithuanian (IOU), but using % the precomposed glyphs for those is not so easy since they aren't in % the same EC font. \def\ogonek#1{{% \def\temp{#1}% \ifx\temp\macrocharA\Aogonek \else\ifx\temp\macrochara\aogonek \else\ifx\temp\macrocharE\Eogonek \else\ifx\temp\macrochare\eogonek \else \ecfont \setbox0=\hbox{#1}% \ifdim\ht0=1ex\accent"0C #1% \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% \fi \fi\fi\fi\fi }% } \def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} \def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} \def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} \def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} % % Use the ec* fonts (cm-super in outline format) for non-CM glyphs. \def\ecfont{% % We can't distinguish serif/sans and italic/slanted, but this % is used for crude hacks anyway (like adding French and German % quotes to documents typeset with CM, where we lose kerning), so % hopefully nobody will notice/care. \edef\ecsize{\csname\curfontsize ecsize\endcsname}% \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% \ifmonospace % typewriter: \font\thisecfont = ectt\ecsize \space at \nominalsize \else \ifx\curfontstyle\bfstylename % bold: \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize \else % regular: \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize \fi \fi \thisecfont } % @registeredsymbol - R in a circle. The font for the R should really % be smaller yet, but lllsize is the best we can do for now. % Adapted from the plain.tex definition of \copyright. % \def\registeredsymbol{% $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% \hfil\crcr\Orb}}% }$% } % @textdegree - the normal degrees sign. % \def\textdegree{$^\circ$} % Laurent Siebenmann reports \Orb undefined with: % Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 % so we'll define it if necessary. % \ifx\Orb\thisisundefined \def\Orb{\mathhexbox20D} \fi % Quotes. \chardef\quotedblleft="5C \chardef\quotedblright=`\" \chardef\quoteleft=`\` \chardef\quoteright=`\' \message{page headings,} \newskip\titlepagetopglue \titlepagetopglue = 1.5in \newskip\titlepagebottomglue \titlepagebottomglue = 2pc % First the title page. Must do @settitle before @titlepage. \newif\ifseenauthor \newif\iffinishedtitlepage % Do an implicit @contents or @shortcontents after @end titlepage if the % user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. % \newif\ifsetcontentsaftertitlepage \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue \newif\ifsetshortcontentsaftertitlepage \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue \parseargdef\shorttitlepage{% \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}% \endgroup\page\hbox{}\page} \envdef\titlepage{% % Open one extra group, as we want to close it in the middle of \Etitlepage. \begingroup \parindent=0pt \textfonts % Leave some space at the very top of the page. \vglue\titlepagetopglue % No rule at page bottom unless we print one at the top with @title. \finishedtitlepagetrue % % Most title ``pages'' are actually two pages long, with space % at the top of the second. We don't want the ragged left on the second. \let\oldpage = \page \def\page{% \iffinishedtitlepage\else \finishtitlepage \fi \let\page = \oldpage \page \null }% } \def\Etitlepage{% \iffinishedtitlepage\else \finishtitlepage \fi % It is important to do the page break before ending the group, % because the headline and footline are only empty inside the group. % If we use the new definition of \page, we always get a blank page % after the title page, which we certainly don't want. \oldpage \endgroup % % Need this before the \...aftertitlepage checks so that if they are % in effect the toc pages will come out with page numbers. \HEADINGSon % % If they want short, they certainly want long too. \ifsetshortcontentsaftertitlepage \shortcontents \contents \global\let\shortcontents = \relax \global\let\contents = \relax \fi % \ifsetcontentsaftertitlepage \contents \global\let\contents = \relax \global\let\shortcontents = \relax \fi } \def\finishtitlepage{% \vskip4pt \hrule height 2pt width \hsize \vskip\titlepagebottomglue \finishedtitlepagetrue } % Settings used for typesetting titles: no hyphenation, no indentation, % don't worry much about spacing, ragged right. This should be used % inside a \vbox, and fonts need to be set appropriately first. Because % it is always used for titles, nothing else, we call \rmisbold. \par % should be specified before the end of the \vbox, since a vbox is a group. % \def\raggedtitlesettings{% \rmisbold \hyphenpenalty=10000 \parindent=0pt \tolerance=5000 \ptexraggedright } % Macros to be used within @titlepage: \let\subtitlerm=\tenrm \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} \parseargdef\title{% \checkenv\titlepage \vbox{\titlefonts \raggedtitlesettings #1\par}% % print a rule at the page bottom also. \finishedtitlepagefalse \vskip4pt \hrule height 4pt width \hsize \vskip4pt } \parseargdef\subtitle{% \checkenv\titlepage {\subtitlefont \rightline{#1}}% } % @author should come last, but may come many times. % It can also be used inside @quotation. % \parseargdef\author{% \def\temp{\quotation}% \ifx\thisenv\temp \def\quotationauthor{#1}% printed in \Equotation. \else \checkenv\titlepage \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi {\secfonts\rmisbold \leftline{#1}}% \fi } % Set up page headings and footings. \let\thispage=\folio \newtoks\evenheadline % headline on even pages \newtoks\oddheadline % headline on odd pages \newtoks\evenfootline % footline on even pages \newtoks\oddfootline % footline on odd pages % Now make TeX use those variables \headline={{\textfonts\rm \ifodd\pageno \the\oddheadline \else \the\evenheadline \fi}} \footline={{\textfonts\rm \ifodd\pageno \the\oddfootline \else \the\evenfootline \fi}\HEADINGShook} \let\HEADINGShook=\relax % Commands to set those variables. % For example, this is what @headings on does % @evenheading @thistitle|@thispage|@thischapter % @oddheading @thischapter|@thispage|@thistitle % @evenfooting @thisfile|| % @oddfooting ||@thisfile \def\evenheading{\parsearg\evenheadingxxx} \def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} \def\evenheadingyyy #1\|#2\|#3\|#4\finish{% \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddheading{\parsearg\oddheadingxxx} \def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} \def\oddheadingyyy #1\|#2\|#3\|#4\finish{% \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% \def\evenfooting{\parsearg\evenfootingxxx} \def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} \def\evenfootingyyy #1\|#2\|#3\|#4\finish{% \global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} \def\oddfooting{\parsearg\oddfootingxxx} \def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} \def\oddfootingyyy #1\|#2\|#3\|#4\finish{% \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% % % Leave some space for the footline. Hopefully ok to assume % @evenfooting will not be used by itself. \global\advance\pageheight by -12pt \global\advance\vsize by -12pt } \parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} % @evenheadingmarks top \thischapter <- chapter at the top of a page % @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page % % The same set of arguments for: % % @oddheadingmarks % @evenfootingmarks % @oddfootingmarks % @everyheadingmarks % @everyfootingmarks \def\evenheadingmarks{\headingmarks{even}{heading}} \def\oddheadingmarks{\headingmarks{odd}{heading}} \def\evenfootingmarks{\headingmarks{even}{footing}} \def\oddfootingmarks{\headingmarks{odd}{footing}} \def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} \headingmarks{odd}{heading}{#1} } \def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} \headingmarks{odd}{footing}{#1} } % #1 = even/odd, #2 = heading/footing, #3 = top/bottom. \def\headingmarks#1#2#3 {% \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname \global\expandafter\let\csname get#1#2marks\endcsname \temp } \everyheadingmarks bottom \everyfootingmarks bottom % @headings double turns headings on for double-sided printing. % @headings single turns headings on for single-sided printing. % @headings off turns them off. % @headings on same as @headings double, retained for compatibility. % @headings after turns on double-sided headings after this page. % @headings doubleafter turns on double-sided headings after this page. % @headings singleafter turns on single-sided headings after this page. % By default, they are off at the start of a document, % and turned `on' after @end titlepage. \def\headings #1 {\csname HEADINGS#1\endcsname} \def\headingsoff{% non-global headings elimination \evenheadline={\hfil}\evenfootline={\hfil}% \oddheadline={\hfil}\oddfootline={\hfil}% } \def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting \HEADINGSoff % it's the default % When we turn headings on, set the page number to 1. % For double-sided printing, put current file name in lower left corner, % chapter name on inside top of right hand pages, document % title on inside top of left hand pages, and page numbers on outside top % edge of all pages. \def\HEADINGSdouble{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \let\contentsalignmacro = \chappager % For single-sided printing, chapter title goes across top left of page, % page number on top right. \def\HEADINGSsingle{% \global\pageno=1 \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } \def\HEADINGSon{\HEADINGSdouble} \def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} \let\HEADINGSdoubleafter=\HEADINGSafter \def\HEADINGSdoublex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\folio\hfil\thistitle}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chapoddpage } \def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} \def\HEADINGSsinglex{% \global\evenfootline={\hfil} \global\oddfootline={\hfil} \global\evenheadline={\line{\thischapter\hfil\folio}} \global\oddheadline={\line{\thischapter\hfil\folio}} \global\let\contentsalignmacro = \chappager } % Subroutines used in generating headings % This produces Day Month Year style of output. % Only define if not already defined, in case a txi-??.tex file has set % up a different format (e.g., txi-cs.tex does this). \ifx\today\thisisundefined \def\today{% \number\day\space \ifcase\month \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec \fi \space\number\year} \fi % @settitle line... specifies the title of the document, for headings. % It generates no output of its own. \def\thistitle{\putwordNoTitle} \def\settitle{\parsearg{\gdef\thistitle}} \message{tables,} % Tables -- @table, @ftable, @vtable, @item(x). % default indentation of table text \newdimen\tableindent \tableindent=.8in % default indentation of @itemize and @enumerate text \newdimen\itemindent \itemindent=.3in % margin between end of table item and start of table text. \newdimen\itemmargin \itemmargin=.1in % used internally for \itemindent minus \itemmargin \newdimen\itemmax % Note @table, @ftable, and @vtable define @item, @itemx, etc., with % these defs. % They also define \itemindex % to index the item name in whatever manner is desired (perhaps none). \newif\ifitemxneedsnegativevskip \def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} \def\internalBitem{\smallbreak \parsearg\itemzzz} \def\internalBitemx{\itemxpar \parsearg\itemzzz} \def\itemzzz #1{\begingroup % \advance\hsize by -\rightskip \advance\hsize by -\tableindent \setbox0=\hbox{\itemindicate{#1}}% \itemindex{#1}% \nobreak % This prevents a break before @itemx. % % If the item text does not fit in the space we have, put it on a line % by itself, and do not allow a page break either before or after that % line. We do not start a paragraph here because then if the next % command is, e.g., @kindex, the whatsit would get put into the % horizontal list on a line by itself, resulting in extra blank space. \ifdim \wd0>\itemmax % % Make this a paragraph so we get the \parskip glue and wrapping, % but leave it ragged-right. \begingroup \advance\leftskip by-\tableindent \advance\hsize by\tableindent \advance\rightskip by0pt plus1fil\relax \leavevmode\unhbox0\par \endgroup % % We're going to be starting a paragraph, but we don't want the % \parskip glue -- logically it's part of the @item we just started. \nobreak \vskip-\parskip % % Stop a page break at the \parskip glue coming up. However, if % what follows is an environment such as @example, there will be no % \parskip glue; then the negative vskip we just inserted would % cause the example and the item to crash together. So we use this % bizarre value of 10001 as a signal to \aboveenvbreak to insert % \parskip glue after all. Section titles are handled this way also. % \penalty 10001 \endgroup \itemxneedsnegativevskipfalse \else % The item text fits into the space. Start a paragraph, so that the % following text (if any) will end up on the same line. \noindent % Do this with kerns and \unhbox so that if there is a footnote in % the item text, it can migrate to the main vertical list and % eventually be printed. \nobreak\kern-\tableindent \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 \unhbox0 \nobreak\kern\dimen0 \endgroup \itemxneedsnegativevskiptrue \fi } \def\item{\errmessage{@item while not in a list environment}} \def\itemx{\errmessage{@itemx while not in a list environment}} % @table, @ftable, @vtable. \envdef\table{% \let\itemindex\gobble \tablecheck{table}% } \envdef\ftable{% \def\itemindex ##1{\doind {fn}{\code{##1}}}% \tablecheck{ftable}% } \envdef\vtable{% \def\itemindex ##1{\doind {vr}{\code{##1}}}% \tablecheck{vtable}% } \def\tablecheck#1{% \ifnum \the\catcode`\^^M=\active \endgroup \errmessage{This command won't work in this context; perhaps the problem is that we are \inenvironment\thisenv}% \def\next{\doignore{#1}}% \else \let\next\tablex \fi \next } \def\tablex#1{% \def\itemindicate{#1}% \parsearg\tabley } \def\tabley#1{% {% \makevalueexpandable \edef\temp{\noexpand\tablez #1\space\space\space}% \expandafter }\temp \endtablez } \def\tablez #1 #2 #3 #4\endtablez{% \aboveenvbreak \ifnum 0#1>0 \advance \leftskip by #1\mil \fi \ifnum 0#2>0 \tableindent=#2\mil \fi \ifnum 0#3>0 \advance \rightskip by #3\mil \fi \itemmax=\tableindent \advance \itemmax by -\itemmargin \advance \leftskip by \tableindent \exdentamount=\tableindent \parindent = 0pt \parskip = \smallskipamount \ifdim \parskip=0pt \parskip=2pt \fi \let\item = \internalBitem \let\itemx = \internalBitemx } \def\Etable{\endgraf\afterenvbreak} \let\Eftable\Etable \let\Evtable\Etable \let\Eitemize\Etable \let\Eenumerate\Etable % This is the counter used by @enumerate, which is really @itemize \newcount \itemno \envdef\itemize{\parsearg\doitemize} \def\doitemize#1{% \aboveenvbreak \itemmax=\itemindent \advance\itemmax by -\itemmargin \advance\leftskip by \itemindent \exdentamount=\itemindent \parindent=0pt \parskip=\smallskipamount \ifdim\parskip=0pt \parskip=2pt \fi % % Try typesetting the item mark that if the document erroneously says % something like @itemize @samp (intending @table), there's an error % right away at the @itemize. It's not the best error message in the % world, but it's better than leaving it to the @item. This means if % the user wants an empty mark, they have to say @w{} not just @w. \def\itemcontents{#1}% \setbox0 = \hbox{\itemcontents}% % % @itemize with no arg is equivalent to @itemize @bullet. \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi % \let\item=\itemizeitem } % Definition of @item while inside @itemize and @enumerate. % \def\itemizeitem{% \advance\itemno by 1 % for enumerations {\let\par=\endgraf \smallbreak}% reasonable place to break {% % If the document has an @itemize directly after a section title, a % \nobreak will be last on the list, and \sectionheading will have % done a \vskip-\parskip. In that case, we don't want to zero % parskip, or the item text will crash with the heading. On the % other hand, when there is normal text preceding the item (as there % usually is), we do want to zero parskip, or there would be too much % space. In that case, we won't have a \nobreak before. At least % that's the theory. \ifnum\lastpenalty<10000 \parskip=0in \fi \noindent \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% % \vadjust{\penalty 1200}}% not good to break after first line of item. \flushcr } % \splitoff TOKENS\endmark defines \first to be the first token in % TOKENS, and \rest to be the remainder. % \def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% % Allow an optional argument of an uppercase letter, lowercase letter, % or number, to specify the first label in the enumerated list. No % argument is the same as `1'. % \envparseargdef\enumerate{\enumeratey #1 \endenumeratey} \def\enumeratey #1 #2\endenumeratey{% % If we were given no argument, pretend we were given `1'. \def\thearg{#1}% \ifx\thearg\empty \def\thearg{1}\fi % % Detect if the argument is a single token. If so, it might be a % letter. Otherwise, the only valid thing it can be is a number. % (We will always have one token, because of the test we just made. % This is a good thing, since \splitoff doesn't work given nothing at % all -- the first parameter is undelimited.) \expandafter\splitoff\thearg\endmark \ifx\rest\empty % Only one token in the argument. It could still be anything. % A ``lowercase letter'' is one whose \lccode is nonzero. % An ``uppercase letter'' is one whose \lccode is both nonzero, and % not equal to itself. % Otherwise, we assume it's a number. % % We need the \relax at the end of the \ifnum lines to stop TeX from % continuing to look for a . % \ifnum\lccode\expandafter`\thearg=0\relax \numericenumerate % a number (we hope) \else % It's a letter. \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax \lowercaseenumerate % lowercase letter \else \uppercaseenumerate % uppercase letter \fi \fi \else % Multiple tokens in the argument. We hope it's a number. \numericenumerate \fi } % An @enumerate whose labels are integers. The starting integer is % given in \thearg. % \def\numericenumerate{% \itemno = \thearg \startenumeration{\the\itemno}% } % The starting (lowercase) letter is in \thearg. \def\lowercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more lowercase letters in @enumerate; get a bigger alphabet}% \fi \char\lccode\itemno }% } % The starting (uppercase) letter is in \thearg. \def\uppercaseenumerate{% \itemno = \expandafter`\thearg \startenumeration{% % Be sure we're not beyond the end of the alphabet. \ifnum\itemno=0 \errmessage{No more uppercase letters in @enumerate; get a bigger alphabet} \fi \char\uccode\itemno }% } % Call \doitemize, adding a period to the first argument and supplying the % common last two arguments. Also subtract one from the initial value in % \itemno, since @item increments \itemno. % \def\startenumeration#1{% \advance\itemno by -1 \doitemize{#1.}\flushcr } % @alphaenumerate and @capsenumerate are abbreviations for giving an arg % to @enumerate. % \def\alphaenumerate{\enumerate{a}} \def\capsenumerate{\enumerate{A}} \def\Ealphaenumerate{\Eenumerate} \def\Ecapsenumerate{\Eenumerate} % @multitable macros % Amy Hendrickson, 8/18/94, 3/6/96 % % @multitable ... @end multitable will make as many columns as desired. % Contents of each column will wrap at width given in preamble. Width % can be specified either with sample text given in a template line, % or in percent of \hsize, the current width of text on page. % Table can continue over pages but will only break between lines. % To make preamble: % % Either define widths of columns in terms of percent of \hsize: % @multitable @columnfractions .25 .3 .45 % @item ... % % Numbers following @columnfractions are the percent of the total % current hsize to be used for each column. You may use as many % columns as desired. % Or use a template: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item ... % using the widest term desired in each column. % Each new table line starts with @item, each subsequent new column % starts with @tab. Empty columns may be produced by supplying @tab's % with nothing between them for as many times as empty columns are needed, % ie, @tab@tab@tab will produce two empty columns. % @item, @tab do not need to be on their own lines, but it will not hurt % if they are. % Sample multitable: % @multitable {Column 1 template} {Column 2 template} {Column 3 template} % @item first col stuff @tab second col stuff @tab third col % @item % first col stuff % @tab % second col stuff % @tab % third col % @item first col stuff @tab second col stuff % @tab Many paragraphs of text may be used in any column. % % They will wrap at the width determined by the template. % @item@tab@tab This will be in third column. % @end multitable % Default dimensions may be reset by user. % @multitableparskip is vertical space between paragraphs in table. % @multitableparindent is paragraph indent in table. % @multitablecolmargin is horizontal space to be left between columns. % @multitablelinespace is space to leave between table items, baseline % to baseline. % 0pt means it depends on current normal line spacing. % \newskip\multitableparskip \newskip\multitableparindent \newdimen\multitablecolspace \newskip\multitablelinespace \multitableparskip=0pt \multitableparindent=6pt \multitablecolspace=12pt \multitablelinespace=0pt % Macros used to set up halign preamble: % \let\endsetuptable\relax \def\xendsetuptable{\endsetuptable} \let\columnfractions\relax \def\xcolumnfractions{\columnfractions} \newif\ifsetpercent % #1 is the @columnfraction, usually a decimal number like .5, but might % be just 1. We just use it, whatever it is. % \def\pickupwholefraction#1 {% \global\advance\colcount by 1 \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% \setuptable } \newcount\colcount \def\setuptable#1{% \def\firstarg{#1}% \ifx\firstarg\xendsetuptable \let\go = \relax \else \ifx\firstarg\xcolumnfractions \global\setpercenttrue \else \ifsetpercent \let\go\pickupwholefraction \else \global\advance\colcount by 1 \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a % separator; typically that is always in the input, anyway. \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% \fi \fi \ifx\go\pickupwholefraction % Put the argument back for the \pickupwholefraction call, so % we'll always have a period there to be parsed. \def\go{\pickupwholefraction#1}% \else \let\go = \setuptable \fi% \fi \go } % multitable-only commands. % % @headitem starts a heading row, which we typeset in bold. % Assignments have to be global since we are inside the implicit group % of an alignment entry. \everycr resets \everytab so we don't have to % undo it ourselves. \def\headitemfont{\b}% for people to use in the template row; not changeable \def\headitem{% \checkenv\multitable \crcr \global\everytab={\bf}% can't use \headitemfont since the parsing differs \the\everytab % for the first item }% % % A \tab used to include \hskip1sp. But then the space in a template % line is not enough. That is bad. So let's go back to just `&' until % we again encounter the problem the 1sp was intended to solve. % --karl, nathan@acm.org, 20apr99. \def\tab{\checkenv\multitable &\the\everytab}% % @multitable ... @end multitable definitions: % \newtoks\everytab % insert after every tab. % \envdef\multitable{% \vskip\parskip \startsavinginserts % % @item within a multitable starts a normal row. % We use \def instead of \let so that if one of the multitable entries % contains an @itemize, we don't choke on the \item (seen as \crcr aka % \endtemplate) expanding \doitemize. \def\item{\crcr}% % \tolerance=9500 \hbadness=9500 \setmultitablespacing \parskip=\multitableparskip \parindent=\multitableparindent \overfullrule=0pt \global\colcount=0 % \everycr = {% \noalign{% \global\everytab={}% \global\colcount=0 % Reset the column counter. % Check for saved footnotes, etc. \checkinserts % Keeps underfull box messages off when table breaks over pages. %\filbreak % Maybe so, but it also creates really weird page breaks when the % table breaks over pages. Wouldn't \vfil be better? Wait until the % problem manifests itself, so it can be fixed for real --karl. }% }% % \parsearg\domultitable } \def\domultitable#1{% % To parse everything between @multitable and @item: \setuptable#1 \endsetuptable % % This preamble sets up a generic column definition, which will % be used as many times as user calls for columns. % \vtop will set a single line and will also let text wrap and % continue for many paragraphs if desired. \halign\bgroup &% \global\advance\colcount by 1 \multistrut \vtop{% % Use the current \colcount to find the correct column width: \hsize=\expandafter\csname col\the\colcount\endcsname % % In order to keep entries from bumping into each other % we will add a \leftskip of \multitablecolspace to all columns after % the first one. % % If a template has been used, we will add \multitablecolspace % to the width of each template entry. % % If the user has set preamble in terms of percent of \hsize we will % use that dimension as the width of the column, and the \leftskip % will keep entries from bumping into each other. Table will start at % left margin and final column will justify at right margin. % % Make sure we don't inherit \rightskip from the outer environment. \rightskip=0pt \ifnum\colcount=1 % The first column will be indented with the surrounding text. \advance\hsize by\leftskip \else \ifsetpercent \else % If user has not set preamble in terms of percent of \hsize % we will advance \hsize by \multitablecolspace. \advance\hsize by \multitablecolspace \fi % In either case we will make \leftskip=\multitablecolspace: \leftskip=\multitablecolspace \fi % Ignoring space at the beginning and end avoids an occasional spurious % blank line, when TeX decides to break the line at the space before the % box from the multistrut, so the strut ends up on a line by itself. % For example: % @multitable @columnfractions .11 .89 % @item @code{#} % @tab Legal holiday which is valid in major parts of the whole country. % Is automatically provided with highlighting sequences respectively % marking characters. \noindent\ignorespaces##\unskip\multistrut }\cr } \def\Emultitable{% \crcr \egroup % end the \halign \global\setpercentfalse } \def\setmultitablespacing{% \def\multistrut{\strut}% just use the standard line spacing % % Compute \multitablelinespace (if not defined by user) for use in % \multitableparskip calculation. We used define \multistrut based on % this, but (ironically) that caused the spacing to be off. % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. \ifdim\multitablelinespace=0pt \setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip \global\advance\multitablelinespace by-\ht0 \fi % Test to see if parskip is larger than space between lines of % table. If not, do nothing. % If so, set to same dimension as multitablelinespace. \ifdim\multitableparskip>\multitablelinespace \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi% \ifdim\multitableparskip=0pt \global\multitableparskip=\multitablelinespace \global\advance\multitableparskip-7pt % to keep parskip somewhat smaller % than skip between lines in the table. \fi} \message{conditionals,} % @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, % @ifnotxml always succeed. They currently do nothing; we don't % attempt to check whether the conditionals are properly nested. But we % have to remember that they are conditionals, so that @end doesn't % attempt to close an environment group. % \def\makecond#1{% \expandafter\let\csname #1\endcsname = \relax \expandafter\let\csname iscond.#1\endcsname = 1 } \makecond{iftex} \makecond{ifnotdocbook} \makecond{ifnothtml} \makecond{ifnotinfo} \makecond{ifnotplaintext} \makecond{ifnotxml} % Ignore @ignore, @ifhtml, @ifinfo, and the like. % \def\direntry{\doignore{direntry}} \def\documentdescription{\doignore{documentdescription}} \def\docbook{\doignore{docbook}} \def\html{\doignore{html}} \def\ifdocbook{\doignore{ifdocbook}} \def\ifhtml{\doignore{ifhtml}} \def\ifinfo{\doignore{ifinfo}} \def\ifnottex{\doignore{ifnottex}} \def\ifplaintext{\doignore{ifplaintext}} \def\ifxml{\doignore{ifxml}} \def\ignore{\doignore{ignore}} \def\menu{\doignore{menu}} \def\xml{\doignore{xml}} % Ignore text until a line `@end #1', keeping track of nested conditionals. % % A count to remember the depth of nesting. \newcount\doignorecount \def\doignore#1{\begingroup % Scan in ``verbatim'' mode: \obeylines \catcode`\@ = \other \catcode`\{ = \other \catcode`\} = \other % % Make sure that spaces turn into tokens that match what \doignoretext wants. \spaceisspace % % Count number of #1's that we've seen. \doignorecount = 0 % % Swallow text until we reach the matching `@end #1'. \dodoignore{#1}% } { \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. \obeylines % % \gdef\dodoignore#1{% % #1 contains the command name as a string, e.g., `ifinfo'. % % Define a command to find the next `@end #1'. \long\def\doignoretext##1^^M@end #1{% \doignoretextyyy##1^^M@#1\_STOP_}% % % And this command to find another #1 command, at the beginning of a % line. (Otherwise, we would consider a line `@c @ifset', for % example, to count as an @ifset for nesting.) \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% % % And now expand that command. \doignoretext ^^M% }% } \def\doignoreyyy#1{% \def\temp{#1}% \ifx\temp\empty % Nothing found. \let\next\doignoretextzzz \else % Found a nested condition, ... \advance\doignorecount by 1 \let\next\doignoretextyyy % ..., look for another. % If we're here, #1 ends with ^^M\ifinfo (for example). \fi \next #1% the token \_STOP_ is present just after this macro. } % We have to swallow the remaining "\_STOP_". % \def\doignoretextzzz#1{% \ifnum\doignorecount = 0 % We have just found the outermost @end. \let\next\enddoignore \else % Still inside a nested condition. \advance\doignorecount by -1 \let\next\doignoretext % Look for the next @end. \fi \next } % Finish off ignored text. { \obeylines% % Ignore anything after the last `@end #1'; this matters in verbatim % environments, where otherwise the newline after an ignored conditional % would result in a blank line in the output. \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% } % @set VAR sets the variable VAR to an empty value. % @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. % % Since we want to separate VAR from REST-OF-LINE (which might be % empty), we can't just use \parsearg; we have to insert a space of our % own to delimit the rest of the line, and then take it out again if we % didn't need it. % We rely on the fact that \parsearg sets \catcode`\ =10. % \parseargdef\set{\setyyy#1 \endsetyyy} \def\setyyy#1 #2\endsetyyy{% {% \makevalueexpandable \def\temp{#2}% \edef\next{\gdef\makecsname{SET#1}}% \ifx\temp\empty \next{}% \else \setzzz#2\endsetzzz \fi }% } % Remove the trailing space \setxxx inserted. \def\setzzz#1 \endsetzzz{\next{#1}} % @clear VAR clears (i.e., unsets) the variable VAR. % \parseargdef\clear{% {% \makevalueexpandable \global\expandafter\let\csname SET#1\endcsname=\relax }% } % @value{foo} gets the text saved in variable foo. \def\value{\begingroup\makevalueexpandable\valuexxx} \def\valuexxx#1{\expandablevalue{#1}\endgroup} { \catcode`\- = \active \catcode`\_ = \active % \gdef\makevalueexpandable{% \let\value = \expandablevalue % We don't want these characters active, ... \catcode`\-=\other \catcode`\_=\other % ..., but we might end up with active ones in the argument if % we're called from @code, as @code{@value{foo-bar_}}, though. % So \let them to their normal equivalents. \let-\normaldash \let_\normalunderscore } } % We have this subroutine so that we can handle at least some @value's % properly in indexes (we call \makevalueexpandable in \indexdummies). % The command has to be fully expandable (if the variable is set), since % the result winds up in the index file. This means that if the % variable's value contains other Texinfo commands, it's almost certain % it will fail (although perhaps we could fix that with sufficient work % to do a one-level expansion on the result, instead of complete). % \def\expandablevalue#1{% \expandafter\ifx\csname SET#1\endcsname\relax {[No value for ``#1'']}% \message{Variable `#1', used in @value, is not set.}% \else \csname SET#1\endcsname \fi } % @ifset VAR ... @end ifset reads the `...' iff VAR has been defined % with @set. % % To get special treatment of `@end ifset,' call \makeond and the redefine. % \makecond{ifset} \def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} \def\doifset#1#2{% {% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname SET#2\endcsname\relax #1% If not set, redefine \next. \fi \expandafter }\next } \def\ifsetfail{\doignore{ifset}} % @ifclear VAR ... @end executes the `...' iff VAR has never been % defined with @set, or has been undefined with @clear. % % The `\else' inside the `\doifset' parameter is a trick to reuse the % above code: if the variable is not set, do nothing, if it is set, % then redefine \next to \ifclearfail. % \makecond{ifclear} \def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} \def\ifclearfail{\doignore{ifclear}} % @ifcommandisdefined CMD ... @end executes the `...' if CMD (written % without the @) is in fact defined. We can only feasibly check at the % TeX level, so something like `mathcode' is going to considered % defined even though it is not a Texinfo command. % \makecond{ifcommanddefined} \def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}} % \def\doifcmddefined#1#2{{% \makevalueexpandable \let\next=\empty \expandafter\ifx\csname #2\endcsname\relax #1% If not defined, \let\next as above. \fi \expandafter }\next } \def\ifcmddefinedfail{\doignore{ifcommanddefined}} % @ifcommandnotdefined CMD ... handled similar to @ifclear above. \makecond{ifcommandnotdefined} \def\ifcommandnotdefined{% \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}} \def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}} % Set the `txicommandconditionals' variable, so documents have a way to % test if the @ifcommand...defined conditionals are available. \set txicommandconditionals % @dircategory CATEGORY -- specify a category of the dir file % which this file should belong to. Ignore this in TeX. \let\dircategory=\comment % @defininfoenclose. \let\definfoenclose=\comment \message{indexing,} % Index generation facilities % Define \newwrite to be identical to plain tex's \newwrite % except not \outer, so it can be used within macros and \if's. \edef\newwrite{\makecsname{ptexnewwrite}} % \newindex {foo} defines an index named foo. % It automatically defines \fooindex such that % \fooindex ...rest of line... puts an entry in the index foo. % It also defines \fooindfile to be the number of the output channel for % the file that accumulates this index. The file's extension is foo. % The name of an index should be no more than 2 characters long % for the sake of vms. % \def\newindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 % Open the file \fi \expandafter\xdef\csname#1index\endcsname{% % Define @#1index \noexpand\doindex{#1}} } % @defindex foo == \newindex{foo} % \def\defindex{\parsearg\newindex} % Define @defcodeindex, like @defindex except put all entries in @code. % \def\defcodeindex{\parsearg\newcodeindex} % \def\newcodeindex#1{% \iflinks \expandafter\newwrite \csname#1indfile\endcsname \openout \csname#1indfile\endcsname \jobname.#1 \fi \expandafter\xdef\csname#1index\endcsname{% \noexpand\docodeindex{#1}}% } % @synindex foo bar makes index foo feed into index bar. % Do this instead of @defindex foo if you don't want it as a separate index. % % @syncodeindex foo bar similar, but put all entries made for index foo % inside @code. % \def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} \def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} % #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), % #3 the target index (bar). \def\dosynindex#1#2#3{% % Only do \closeout if we haven't already done it, else we'll end up % closing the target index. \expandafter \ifx\csname donesynindex#2\endcsname \relax % The \closeout helps reduce unnecessary open files; the limit on the % Acorn RISC OS is a mere 16 files. \expandafter\closeout\csname#2indfile\endcsname \expandafter\let\csname donesynindex#2\endcsname = 1 \fi % redefine \fooindfile: \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname \expandafter\let\csname#2indfile\endcsname=\temp % redefine \fooindex: \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% } % Define \doindex, the driver for all \fooindex macros. % Argument #1 is generated by the calling \fooindex macro, % and it is "foo", the name of the index. % \doindex just uses \parsearg; it calls \doind for the actual work. % This is because \doind is more useful to call from other macros. % There is also \dosubind {index}{topic}{subtopic} % which makes an entry in a two-level index such as the operation index. \def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} \def\singleindexer #1{\doind{\indexname}{#1}} % like the previous two, but they put @code around the argument. \def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} \def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} % Take care of Texinfo commands that can appear in an index entry. % Since there are some commands we want to expand, and others we don't, % we have to laboriously prevent expansion for those that we don't. % \def\indexdummies{% \escapechar = `\\ % use backslash in output files. \def\@{@}% change to @@ when we switch to @ as escape char in index files. \def\ {\realbackslash\space }% % % Need these unexpandable (because we define \tt as a dummy) % definitions when @{ or @} appear in index entry text. Also, more % complicated, when \tex is in effect and \{ is a \delimiter again. % We can't use \lbracecmd and \rbracecmd because texindex assumes % braces and backslashes are used only as delimiters. Perhaps we % should define @lbrace and @rbrace commands a la @comma. \def\{{{\tt\char123}}% \def\}{{\tt\char125}}% % % I don't entirely understand this, but when an index entry is % generated from a macro call, the \endinput which \scanmacro inserts % causes processing to be prematurely terminated. This is, % apparently, because \indexsorttmp is fully expanded, and \endinput % is an expandable command. The redefinition below makes \endinput % disappear altogether for that purpose -- although logging shows that % processing continues to some further point. On the other hand, it % seems \endinput does not hurt in the printed index arg, since that % is still getting written without apparent harm. % % Sample source (mac-idx3.tex, reported by Graham Percival to % help-texinfo, 22may06): % @macro funindex {WORD} % @findex xyz % @end macro % ... % @funindex commtest % % The above is not enough to reproduce the bug, but it gives the flavor. % % Sample whatsit resulting: % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} % % So: \let\endinput = \empty % % Do the redefinitions. \commondummies } % For the aux and toc files, @ is the escape character. So we want to % redefine everything using @ as the escape character (instead of % \realbackslash, still used for index files). When everything uses @, % this will be simpler. % \def\atdummies{% \def\@{@@}% \def\ {@ }% \let\{ = \lbraceatcmd \let\} = \rbraceatcmd % % Do the redefinitions. \commondummies \otherbackslash } % Called from \indexdummies and \atdummies. % \def\commondummies{% % % \definedummyword defines \#1 as \string\#1\space, thus effectively % preventing its expansion. This is used only for control words, % not control letters, because the \space would be incorrect for % control characters, but is needed to separate the control word % from whatever follows. % % For control letters, we have \definedummyletter, which omits the % space. % % These can be used both for control words that take an argument and % those that do not. If it is followed by {arg} in the input, then % that will dutifully get written to the index (or wherever). % \def\definedummyword ##1{\def##1{\string##1\space}}% \def\definedummyletter##1{\def##1{\string##1}}% \let\definedummyaccent\definedummyletter % \commondummiesnofonts % \definedummyletter\_% \definedummyletter\-% % % Non-English letters. \definedummyword\AA \definedummyword\AE \definedummyword\DH \definedummyword\L \definedummyword\O \definedummyword\OE \definedummyword\TH \definedummyword\aa \definedummyword\ae \definedummyword\dh \definedummyword\exclamdown \definedummyword\l \definedummyword\o \definedummyword\oe \definedummyword\ordf \definedummyword\ordm \definedummyword\questiondown \definedummyword\ss \definedummyword\th % % Although these internal commands shouldn't show up, sometimes they do. \definedummyword\bf \definedummyword\gtr \definedummyword\hat \definedummyword\less \definedummyword\sf \definedummyword\sl \definedummyword\tclose \definedummyword\tt % \definedummyword\LaTeX \definedummyword\TeX % % Assorted special characters. \definedummyword\arrow \definedummyword\bullet \definedummyword\comma \definedummyword\copyright \definedummyword\registeredsymbol \definedummyword\dots \definedummyword\enddots \definedummyword\entrybreak \definedummyword\equiv \definedummyword\error \definedummyword\euro \definedummyword\expansion \definedummyword\geq \definedummyword\guillemetleft \definedummyword\guillemetright \definedummyword\guilsinglleft \definedummyword\guilsinglright \definedummyword\lbracechar \definedummyword\leq \definedummyword\minus \definedummyword\ogonek \definedummyword\pounds \definedummyword\point \definedummyword\print \definedummyword\quotedblbase \definedummyword\quotedblleft \definedummyword\quotedblright \definedummyword\quoteleft \definedummyword\quoteright \definedummyword\quotesinglbase \definedummyword\rbracechar \definedummyword\result \definedummyword\textdegree % % We want to disable all macros so that they are not expanded by \write. \macrolist % \normalturnoffactive % % Handle some cases of @value -- where it does not contain any % (non-fully-expandable) commands. \makevalueexpandable } % \commondummiesnofonts: common to \commondummies and \indexnofonts. % \def\commondummiesnofonts{% % Control letters and accents. \definedummyletter\!% \definedummyaccent\"% \definedummyaccent\'% \definedummyletter\*% \definedummyaccent\,% \definedummyletter\.% \definedummyletter\/% \definedummyletter\:% \definedummyaccent\=% \definedummyletter\?% \definedummyaccent\^% \definedummyaccent\`% \definedummyaccent\~% \definedummyword\u \definedummyword\v \definedummyword\H \definedummyword\dotaccent \definedummyword\ogonek \definedummyword\ringaccent \definedummyword\tieaccent \definedummyword\ubaraccent \definedummyword\udotaccent \definedummyword\dotless % % Texinfo font commands. \definedummyword\b \definedummyword\i \definedummyword\r \definedummyword\sansserif \definedummyword\sc \definedummyword\slanted \definedummyword\t % % Commands that take arguments. \definedummyword\abbr \definedummyword\acronym \definedummyword\anchor \definedummyword\cite \definedummyword\code \definedummyword\command \definedummyword\dfn \definedummyword\dmn \definedummyword\email \definedummyword\emph \definedummyword\env \definedummyword\file \definedummyword\image \definedummyword\indicateurl \definedummyword\inforef \definedummyword\kbd \definedummyword\key \definedummyword\math \definedummyword\option \definedummyword\pxref \definedummyword\ref \definedummyword\samp \definedummyword\strong \definedummyword\tie \definedummyword\uref \definedummyword\url \definedummyword\var \definedummyword\verb \definedummyword\w \definedummyword\xref } % \indexnofonts is used when outputting the strings to sort the index % by, and when constructing control sequence names. It eliminates all % control sequences and just writes whatever the best ASCII sort string % would be for a given command (usually its argument). % \def\indexnofonts{% % Accent commands should become @asis. \def\definedummyaccent##1{\let##1\asis}% % We can just ignore other control letters. \def\definedummyletter##1{\let##1\empty}% % All control words become @asis by default; overrides below. \let\definedummyword\definedummyaccent % \commondummiesnofonts % % Don't no-op \tt, since it isn't a user-level command % and is used in the definitions of the active chars like <, >, |, etc. % Likewise with the other plain tex font commands. %\let\tt=\asis % \def\ { }% \def\@{@}% \def\_{\normalunderscore}% \def\-{}% @- shouldn't affect sorting % % Unfortunately, texindex is not prepared to handle braces in the % content at all. So for index sorting, we map @{ and @} to strings % starting with |, since that ASCII character is between ASCII { and }. \def\{{|a}% \def\lbracechar{|a}% % \def\}{|b}% \def\rbracechar{|b}% % % Non-English letters. \def\AA{AA}% \def\AE{AE}% \def\DH{DZZ}% \def\L{L}% \def\OE{OE}% \def\O{O}% \def\TH{ZZZ}% \def\aa{aa}% \def\ae{ae}% \def\dh{dzz}% \def\exclamdown{!}% \def\l{l}% \def\oe{oe}% \def\ordf{a}% \def\ordm{o}% \def\o{o}% \def\questiondown{?}% \def\ss{ss}% \def\th{zzz}% % \def\LaTeX{LaTeX}% \def\TeX{TeX}% % % Assorted special characters. % (The following {} will end up in the sort string, but that's ok.) \def\arrow{->}% \def\bullet{bullet}% \def\comma{,}% \def\copyright{copyright}% \def\dots{...}% \def\enddots{...}% \def\equiv{==}% \def\error{error}% \def\euro{euro}% \def\expansion{==>}% \def\geq{>=}% \def\guillemetleft{<<}% \def\guillemetright{>>}% \def\guilsinglleft{<}% \def\guilsinglright{>}% \def\leq{<=}% \def\minus{-}% \def\point{.}% \def\pounds{pounds}% \def\print{-|}% \def\quotedblbase{"}% \def\quotedblleft{"}% \def\quotedblright{"}% \def\quoteleft{`}% \def\quoteright{'}% \def\quotesinglbase{,}% \def\registeredsymbol{R}% \def\result{=>}% \def\textdegree{o}% % \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax \else \indexlquoteignore \fi % % We need to get rid of all macros, leaving only the arguments (if present). % Of course this is not nearly correct, but it is the best we can do for now. % makeinfo does not expand macros in the argument to @deffn, which ends up % writing an index entry, and texindex isn't prepared for an index sort entry % that starts with \. % % Since macro invocations are followed by braces, we can just redefine them % to take a single TeX argument. The case of a macro invocation that % goes to end-of-line is not handled. % \macrolist } % Undocumented (for FSFS 2nd ed.): @set txiindexlquoteignore makes us % ignore left quotes in the sort term. {\catcode`\`=\active \gdef\indexlquoteignore{\let`=\empty}} \let\indexbackslash=0 %overridden during \printindex. \let\SETmarginindex=\relax % put index entries in margin (undocumented)? % Most index entries go through here, but \dosubind is the general case. % #1 is the index name, #2 is the entry text. \def\doind#1#2{\dosubind{#1}{#2}{}} % Workhorse for all \fooindexes. % #1 is name of index, #2 is stuff to put there, #3 is subentry -- % empty if called from \doind, as we usually are (the main exception % is with most defuns, which call us directly). % \def\dosubind#1#2#3{% \iflinks {% % Store the main index entry text (including the third arg). \toks0 = {#2}% % If third arg is present, precede it with a space. \def\thirdarg{#3}% \ifx\thirdarg\empty \else \toks0 = \expandafter{\the\toks0 \space #3}% \fi % \edef\writeto{\csname#1indfile\endcsname}% % \safewhatsit\dosubindwrite }% \fi } % Write the entry in \toks0 to the index file: % \def\dosubindwrite{% % Put the index entry in the margin if desired. \ifx\SETmarginindex\relax\else \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% \fi % % Remember, we are within a group. \indexdummies % Must do this here, since \bf, etc expand at this stage \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now % so it will be output as is; and it will print as backslash. % % Process the index entry with all font commands turned off, to % get the string to sort by. {\indexnofonts \edef\temp{\the\toks0}% need full expansion \xdef\indexsorttmp{\temp}% }% % % Set up the complete index entry, with both the sort key and % the original text, including any font commands. We write % three arguments to \entry to the .?? file (four in the % subentry case), texindex reduces to two when writing the .??s % sorted result. \edef\temp{% \write\writeto{% \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% }% \temp } % Take care of unwanted page breaks/skips around a whatsit: % % If a skip is the last thing on the list now, preserve it % by backing up by \lastskip, doing the \write, then inserting % the skip again. Otherwise, the whatsit generated by the % \write or \pdfdest will make \lastskip zero. The result is that % sequences like this: % @end defun % @tindex whatever % @defun ... % will have extra space inserted, because the \medbreak in the % start of the @defun won't see the skip inserted by the @end of % the previous defun. % % But don't do any of this if we're not in vertical mode. We % don't want to do a \vskip and prematurely end a paragraph. % % Avoid page breaks due to these extra skips, too. % % But wait, there is a catch there: % We'll have to check whether \lastskip is zero skip. \ifdim is not % sufficient for this purpose, as it ignores stretch and shrink parts % of the skip. The only way seems to be to check the textual % representation of the skip. % % The following is almost like \def\zeroskipmacro{0.0pt} except that % the ``p'' and ``t'' characters have catcode \other, not 11 (letter). % \edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} % \newskip\whatsitskip \newcount\whatsitpenalty % % ..., ready, GO: % \def\safewhatsit#1{\ifhmode #1% \else % \lastskip and \lastpenalty cannot both be nonzero simultaneously. \whatsitskip = \lastskip \edef\lastskipmacro{\the\lastskip}% \whatsitpenalty = \lastpenalty % % If \lastskip is nonzero, that means the last item was a % skip. And since a skip is discardable, that means this % -\whatsitskip glue we're inserting is preceded by a % non-discardable item, therefore it is not a potential % breakpoint, therefore no \nobreak needed. \ifx\lastskipmacro\zeroskipmacro \else \vskip-\whatsitskip \fi % #1% % \ifx\lastskipmacro\zeroskipmacro % If \lastskip was zero, perhaps the last item was a penalty, and % perhaps it was >=10000, e.g., a \nobreak. In that case, we want % to re-insert the same penalty (values >10000 are used for various % signals); since we just inserted a non-discardable item, any % following glue (such as a \parskip) would be a breakpoint. For example: % @deffn deffn-whatever % @vindex index-whatever % Description. % would allow a break between the index-whatever whatsit % and the "Description." paragraph. \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi \else % On the other hand, if we had a nonzero \lastskip, % this make-up glue would be preceded by a non-discardable item % (the whatsit from the \write), so we must insert a \nobreak. \nobreak\vskip\whatsitskip \fi \fi} % The index entry written in the file actually looks like % \entry {sortstring}{page}{topic} % or % \entry {sortstring}{page}{topic}{subtopic} % The texindex program reads in these files and writes files % containing these kinds of lines: % \initial {c} % before the first topic whose initial is c % \entry {topic}{pagelist} % for a topic that is used without subtopics % \primary {topic} % for the beginning of a topic that is used with subtopics % \secondary {subtopic}{pagelist} % for each subtopic. % Define the user-accessible indexing commands % @findex, @vindex, @kindex, @cindex. \def\findex {\fnindex} \def\kindex {\kyindex} \def\cindex {\cpindex} \def\vindex {\vrindex} \def\tindex {\tpindex} \def\pindex {\pgindex} \def\cindexsub {\begingroup\obeylines\cindexsub} {\obeylines % \gdef\cindexsub "#1" #2^^M{\endgroup % \dosubind{cp}{#2}{#1}}} % Define the macros used in formatting output of the sorted index material. % @printindex causes a particular index (the ??s file) to get printed. % It does not print any chapter heading (usually an @unnumbered). % \parseargdef\printindex{\begingroup \dobreak \chapheadingskip{10000}% % \smallfonts \rm \tolerance = 9500 \plainfrenchspacing \everypar = {}% don't want the \kern\-parindent from indentation suppression. % % See if the index file exists and is nonempty. % Change catcode of @ here so that if the index file contains % \initial {@} % as its first line, TeX doesn't complain about mismatched braces % (because it thinks @} is a control sequence). \catcode`\@ = 11 \openin 1 \jobname.#1s \ifeof 1 % \enddoublecolumns gets confused if there is no text in the index, % and it loses the chapter title and the aux file entries for the % index. The easiest way to prevent this problem is to make sure % there is some text. \putwordIndexNonexistent \else % % If the index file exists but is empty, then \openin leaves \ifeof % false. We have to make TeX try to read something from the file, so % it can discover if there is anything in it. \read 1 to \temp \ifeof 1 \putwordIndexIsEmpty \else % Index files are almost Texinfo source, but we use \ as the escape % character. It would be better to use @, but that's too big a change % to make right now. \def\indexbackslash{\backslashcurfont}% \catcode`\\ = 0 \escapechar = `\\ \begindoublecolumns \input \jobname.#1s \enddoublecolumns \fi \fi \closein 1 \endgroup} % These macros are used by the sorted index file itself. % Change them to control the appearance of the index. \def\initial#1{{% % Some minor font changes for the special characters. \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt % % Remove any glue we may have, we'll be inserting our own. \removelastskip % % We like breaks before the index initials, so insert a bonus. \nobreak \vskip 0pt plus 3\baselineskip \penalty 0 \vskip 0pt plus -3\baselineskip % % Typeset the initial. Making this add up to a whole number of % baselineskips increases the chance of the dots lining up from column % to column. It still won't often be perfect, because of the stretch % we need before each entry, but it's better. % % No shrink because it confuses \balancecolumns. \vskip 1.67\baselineskip plus .5\baselineskip \leftline{\secbf #1}% % Do our best not to break after the initial. \nobreak \vskip .33\baselineskip plus .1\baselineskip }} % \entry typesets a paragraph consisting of the text (#1), dot leaders, and % then page number (#2) flushed to the right margin. It is used for index % and table of contents entries. The paragraph is indented by \leftskip. % % A straightforward implementation would start like this: % \def\entry#1#2{... % But this freezes the catcodes in the argument, and can cause problems to % @code, which sets - active. This problem was fixed by a kludge--- % ``-'' was active throughout whole index, but this isn't really right. % The right solution is to prevent \entry from swallowing the whole text. % --kasal, 21nov03 \def\entry{% \begingroup % % Start a new paragraph if necessary, so our assignments below can't % affect previous text. \par % % Do not fill out the last line with white space. \parfillskip = 0in % % No extra space above this paragraph. \parskip = 0in % % Do not prefer a separate line ending with a hyphen to fewer lines. \finalhyphendemerits = 0 % % \hangindent is only relevant when the entry text and page number % don't both fit on one line. In that case, bob suggests starting the % dots pretty far over on the line. Unfortunately, a large % indentation looks wrong when the entry text itself is broken across % lines. So we use a small indentation and put up with long leaders. % % \hangafter is reset to 1 (which is the value we want) at the start % of each paragraph, so we need not do anything with that. \hangindent = 2em % % When the entry text needs to be broken, just fill out the first line % with blank space. \rightskip = 0pt plus1fil % % A bit of stretch before each entry for the benefit of balancing % columns. \vskip 0pt plus1pt % % When reading the text of entry, convert explicit line breaks % from @* into spaces. The user might give these in long section % titles, for instance. \def\*{\unskip\space\ignorespaces}% \def\entrybreak{\hfil\break}% % % Swallow the left brace of the text (first parameter): \afterassignment\doentry \let\temp = } \def\entrybreak{\unskip\space\ignorespaces}% \def\doentry{% \bgroup % Instead of the swallowed brace. \noindent \aftergroup\finishentry % And now comes the text of the entry. } \def\finishentry#1{% % #1 is the page number. % % The following is kludged to not output a line of dots in the index if % there are no page numbers. The next person who breaks this will be % cursed by a Unix daemon. \setbox\boxA = \hbox{#1}% \ifdim\wd\boxA = 0pt \ % \else % % If we must, put the page number on a line of its own, and fill out % this line with blank space. (The \hfil is overwhelmed with the % fill leaders glue in \indexdotfill if the page number does fit.) \hfil\penalty50 \null\nobreak\indexdotfill % Have leaders before the page number. % % The `\ ' here is removed by the implicit \unskip that TeX does as % part of (the primitive) \par. Without it, a spurious underfull % \hbox ensues. \ifpdf \pdfgettoks#1.% \ \the\toksA \else \ #1% \fi \fi \par \endgroup } % Like plain.tex's \dotfill, except uses up at least 1 em. \def\indexdotfill{\cleaders \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} \def\primary #1{\line{#1\hfil}} \newskip\secondaryindent \secondaryindent=0.5cm \def\secondary#1#2{{% \parfillskip=0in \parskip=0in \hangindent=1in \hangafter=1 \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill \ifpdf \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. \else #2 \fi \par }} % Define two-column mode, which we use to typeset indexes. % Adapted from the TeXbook, page 416, which is to say, % the manmac.tex format used to print the TeXbook itself. \catcode`\@=11 \newbox\partialpage \newdimen\doublecolumnhsize \def\begindoublecolumns{\begingroup % ended by \enddoublecolumns % Grab any single-column material above us. \output = {% % % Here is a possibility not foreseen in manmac: if we accumulate a % whole lot of material, we might end up calling this \output % routine twice in a row (see the doublecol-lose test, which is % essentially a couple of indexes with @setchapternewpage off). In % that case we just ship out what is in \partialpage with the normal % output routine. Generally, \partialpage will be empty when this % runs and this will be a no-op. See the indexspread.tex test case. \ifvoid\partialpage \else \onepageout{\pagecontents\partialpage}% \fi % \global\setbox\partialpage = \vbox{% % Unvbox the main output page. \unvbox\PAGE \kern-\topskip \kern\baselineskip }% }% \eject % run that output routine to set \partialpage % % Use the double-column output routine for subsequent pages. \output = {\doublecolumnout}% % % Change the page size parameters. We could do this once outside this % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 % format, but then we repeat the same computation. Repeating a couple % of assignments once per index is clearly meaningless for the % execution time, so we may as well do it in one place. % % First we halve the line length, less a little for the gutter between % the columns. We compute the gutter based on the line length, so it % changes automatically with the paper format. The magic constant % below is chosen so that the gutter has the same value (well, +-<1pt) % as it did when we hard-coded it. % % We put the result in a separate register, \doublecolumhsize, so we % can restore it in \pagesofar, after \hsize itself has (potentially) % been clobbered. % \doublecolumnhsize = \hsize \advance\doublecolumnhsize by -.04154\hsize \divide\doublecolumnhsize by 2 \hsize = \doublecolumnhsize % % Double the \vsize as well. (We don't need a separate register here, % since nobody clobbers \vsize.) \vsize = 2\vsize } % The double-column output routine for all double-column pages except % the last. % \def\doublecolumnout{% \splittopskip=\topskip \splitmaxdepth=\maxdepth % Get the available space for the double columns -- the normal % (undoubled) page height minus any material left over from the % previous page. \dimen@ = \vsize \divide\dimen@ by 2 \advance\dimen@ by -\ht\partialpage % % box0 will be the left-hand column, box2 the right. \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ \onepageout\pagesofar \unvbox255 \penalty\outputpenalty } % % Re-output the contents of the output page -- any previous material, % followed by the two boxes we just split, in box0 and box2. \def\pagesofar{% \unvbox\partialpage % \hsize = \doublecolumnhsize \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% } % % All done with double columns. \def\enddoublecolumns{% % The following penalty ensures that the page builder is exercised % _before_ we change the output routine. This is necessary in the % following situation: % % The last section of the index consists only of a single entry. % Before this section, \pagetotal is less than \pagegoal, so no % break occurs before the last section starts. However, the last % section, consisting of \initial and the single \entry, does not % fit on the page and has to be broken off. Without the following % penalty the page builder will not be exercised until \eject % below, and by that time we'll already have changed the output % routine to the \balancecolumns version, so the next-to-last % double-column page will be processed with \balancecolumns, which % is wrong: The two columns will go to the main vertical list, with % the broken-off section in the recent contributions. As soon as % the output routine finishes, TeX starts reconsidering the page % break. The two columns and the broken-off section both fit on the % page, because the two columns now take up only half of the page % goal. When TeX sees \eject from below which follows the final % section, it invokes the new output routine that we've set after % \balancecolumns below; \onepageout will try to fit the two columns % and the final section into the vbox of \pageheight (see % \pagebody), causing an overfull box. % % Note that glue won't work here, because glue does not exercise the % page builder, unlike penalties (see The TeXbook, pp. 280-281). \penalty0 % \output = {% % Split the last of the double-column material. Leave it on the % current page, no automatic page break. \balancecolumns % % If we end up splitting too much material for the current page, % though, there will be another page break right after this \output % invocation ends. Having called \balancecolumns once, we do not % want to call it again. Therefore, reset \output to its normal % definition right away. (We hope \balancecolumns will never be % called on to balance too much material, but if it is, this makes % the output somewhat more palatable.) \global\output = {\onepageout{\pagecontents\PAGE}}% }% \eject \endgroup % started in \begindoublecolumns % % \pagegoal was set to the doubled \vsize above, since we restarted % the current page. We're now back to normal single-column % typesetting, so reset \pagegoal to the normal \vsize (after the % \endgroup where \vsize got restored). \pagegoal = \vsize } % % Called at the end of the double column material. \def\balancecolumns{% \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. \dimen@ = \ht0 \advance\dimen@ by \topskip \advance\dimen@ by-\baselineskip \divide\dimen@ by 2 % target to split to %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% \splittopskip = \topskip % Loop until we get a decent breakpoint. {% \vbadness = 10000 \loop \global\setbox3 = \copy0 \global\setbox1 = \vsplit3 to \dimen@ \ifdim\ht3>\dimen@ \global\advance\dimen@ by 1pt \repeat }% %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% \setbox0=\vbox to\dimen@{\unvbox1}% \setbox2=\vbox to\dimen@{\unvbox3}% % \pagesofar } \catcode`\@ = \other \message{sectioning,} % Chapters, sections, etc. % Let's start with @part. \outer\parseargdef\part{\partzzz{#1}} \def\partzzz#1{% \chapoddpage \null \vskip.3\vsize % move it down on the page a bit \begingroup \noindent \titlefonts\rmisbold #1\par % the text \let\lastnode=\empty % no node to associate with \writetocentry{part}{#1}{}% but put it in the toc \headingsoff % no headline or footline on the part page \chapoddpage \endgroup } % \unnumberedno is an oxymoron. But we count the unnumbered % sections so that we can refer to them unambiguously in the pdf % outlines by their "section number". We avoid collisions with chapter % numbers by starting them at 10000. (If a document ever has 10000 % chapters, we're in trouble anyway, I'm sure.) \newcount\unnumberedno \unnumberedno = 10000 \newcount\chapno \newcount\secno \secno=0 \newcount\subsecno \subsecno=0 \newcount\subsubsecno \subsubsecno=0 % This counter is funny since it counts through charcodes of letters A, B, ... \newcount\appendixno \appendixno = `\@ % % \def\appendixletter{\char\the\appendixno} % We do the following ugly conditional instead of the above simple % construct for the sake of pdftex, which needs the actual % letter in the expansion, not just typeset. % \def\appendixletter{% \ifnum\appendixno=`A A% \else\ifnum\appendixno=`B B% \else\ifnum\appendixno=`C C% \else\ifnum\appendixno=`D D% \else\ifnum\appendixno=`E E% \else\ifnum\appendixno=`F F% \else\ifnum\appendixno=`G G% \else\ifnum\appendixno=`H H% \else\ifnum\appendixno=`I I% \else\ifnum\appendixno=`J J% \else\ifnum\appendixno=`K K% \else\ifnum\appendixno=`L L% \else\ifnum\appendixno=`M M% \else\ifnum\appendixno=`N N% \else\ifnum\appendixno=`O O% \else\ifnum\appendixno=`P P% \else\ifnum\appendixno=`Q Q% \else\ifnum\appendixno=`R R% \else\ifnum\appendixno=`S S% \else\ifnum\appendixno=`T T% \else\ifnum\appendixno=`U U% \else\ifnum\appendixno=`V V% \else\ifnum\appendixno=`W W% \else\ifnum\appendixno=`X X% \else\ifnum\appendixno=`Y Y% \else\ifnum\appendixno=`Z Z% % The \the is necessary, despite appearances, because \appendixletter is % expanded while writing the .toc file. \char\appendixno is not % expandable, thus it is written literally, thus all appendixes come out % with the same letter (or @) in the toc without it. \else\char\the\appendixno \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} % Each @chapter defines these (using marks) as the number+name, number % and name of the chapter. Page headings and footings can use % these. @section does likewise. \def\thischapter{} \def\thischapternum{} \def\thischaptername{} \def\thissection{} \def\thissectionnum{} \def\thissectionname{} \newcount\absseclevel % used to calculate proper heading level \newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count % @raisesections: treat @section as chapter, @subsection as section, etc. \def\raisesections{\global\advance\secbase by -1} \let\up=\raisesections % original BFox name % @lowersections: treat @chapter as section, @section as subsection, etc. \def\lowersections{\global\advance\secbase by 1} \let\down=\lowersections % original BFox name % we only have subsub. \chardef\maxseclevel = 3 % % A numbered section within an unnumbered changes to unnumbered too. % To achieve this, remember the "biggest" unnum. sec. we are currently in: \chardef\unnlevel = \maxseclevel % % Trace whether the current chapter is an appendix or not: % \chapheadtype is "N" or "A", unnumbered chapters are ignored. \def\chapheadtype{N} % Choose a heading macro % #1 is heading type % #2 is heading level % #3 is text for heading \def\genhead#1#2#3{% % Compute the abs. sec. level: \absseclevel=#2 \advance\absseclevel by \secbase % Make sure \absseclevel doesn't fall outside the range: \ifnum \absseclevel < 0 \absseclevel = 0 \else \ifnum \absseclevel > 3 \absseclevel = 3 \fi \fi % The heading type: \def\headtype{#1}% \if \headtype U% \ifnum \absseclevel < \unnlevel \chardef\unnlevel = \absseclevel \fi \else % Check for appendix sections: \ifnum \absseclevel = 0 \edef\chapheadtype{\headtype}% \else \if \headtype A\if \chapheadtype N% \errmessage{@appendix... within a non-appendix chapter}% \fi\fi \fi % Check for numbered within unnumbered: \ifnum \absseclevel > \unnlevel \def\headtype{U}% \else \chardef\unnlevel = 3 \fi \fi % Now print the heading: \if \headtype U% \ifcase\absseclevel \unnumberedzzz{#3}% \or \unnumberedseczzz{#3}% \or \unnumberedsubseczzz{#3}% \or \unnumberedsubsubseczzz{#3}% \fi \else \if \headtype A% \ifcase\absseclevel \appendixzzz{#3}% \or \appendixsectionzzz{#3}% \or \appendixsubseczzz{#3}% \or \appendixsubsubseczzz{#3}% \fi \else \ifcase\absseclevel \chapterzzz{#3}% \or \seczzz{#3}% \or \numberedsubseczzz{#3}% \or \numberedsubsubseczzz{#3}% \fi \fi \fi \suppressfirstparagraphindent } % an interface: \def\numhead{\genhead N} \def\apphead{\genhead A} \def\unnmhead{\genhead U} % @chapter, @appendix, @unnumbered. Increment top-level counter, reset % all lower-level sectioning counters to zero. % % Also set \chaplevelprefix, which we prepend to @float sequence numbers % (e.g., figures), q.v. By default (before any chapter), that is empty. \let\chaplevelprefix = \empty % \outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz \def\chapterzzz#1{% % section resetting is \global in case the chapter is in a group, such % as an @include file. \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\chapno by 1 % % Used for \float. \gdef\chaplevelprefix{\the\chapno.}% \resetallfloatnos % % \putwordChapter can contain complex things in translations. \toks0=\expandafter{\putwordChapter}% \message{\the\toks0 \space \the\chapno}% % % Write the actual heading. \chapmacro{#1}{Ynumbered}{\the\chapno}% % % So @section and the like are numbered underneath this chapter. \global\let\section = \numberedsec \global\let\subsection = \numberedsubsec \global\let\subsubsection = \numberedsubsubsec } \outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz % \def\appendixzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\appendixno by 1 \gdef\chaplevelprefix{\appendixletter.}% \resetallfloatnos % % \putwordAppendix can contain complex things in translations. \toks0=\expandafter{\putwordAppendix}% \message{\the\toks0 \space \appendixletter}% % \chapmacro{#1}{Yappendix}{\appendixletter}% % \global\let\section = \appendixsec \global\let\subsection = \appendixsubsec \global\let\subsubsection = \appendixsubsubsec } % normally unnmhead0 calls unnumberedzzz: \outer\parseargdef\unnumbered{\unnmhead0{#1}} \def\unnumberedzzz#1{% \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 \global\advance\unnumberedno by 1 % % Since an unnumbered has no number, no prefix for figures. \global\let\chaplevelprefix = \empty \resetallfloatnos % % This used to be simply \message{#1}, but TeX fully expands the % argument to \message. Therefore, if #1 contained @-commands, TeX % expanded them. For example, in `@unnumbered The @cite{Book}', TeX % expanded @cite (which turns out to cause errors because \cite is meant % to be executed, not expanded). % % Anyway, we don't want the fully-expanded definition of @cite to appear % as a result of the \message, we just want `@cite' itself. We use % \the to achieve this: TeX expands \the only once, % simply yielding the contents of . (We also do this for % the toc entries.) \toks0 = {#1}% \message{(\the\toks0)}% % \chapmacro{#1}{Ynothing}{\the\unnumberedno}% % \global\let\section = \unnumberedsec \global\let\subsection = \unnumberedsubsec \global\let\subsubsection = \unnumberedsubsubsec } % @centerchap is like @unnumbered, but the heading is centered. \outer\parseargdef\centerchap{% % Well, we could do the following in a group, but that would break % an assumption that \chapmacro is called at the outermost level. % Thus we are safer this way: --kasal, 24feb04 \let\centerparametersmaybe = \centerparameters \unnmhead0{#1}% \let\centerparametersmaybe = \relax } % @top is like @unnumbered. \let\top\unnumbered % Sections. % \outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz \def\seczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% } % normally calls appendixsectionzzz: \outer\parseargdef\appendixsection{\apphead1{#1}} \def\appendixsectionzzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% } \let\appendixsec\appendixsection % normally calls unnumberedseczzz: \outer\parseargdef\unnumberedsec{\unnmhead1{#1}} \def\unnumberedseczzz#1{% \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% } % Subsections. % % normally calls numberedsubseczzz: \outer\parseargdef\numberedsubsec{\numhead2{#1}} \def\numberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% } % normally calls appendixsubseczzz: \outer\parseargdef\appendixsubsec{\apphead2{#1}} \def\appendixsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno}% } % normally calls unnumberedsubseczzz: \outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} \def\unnumberedsubseczzz#1{% \global\subsubsecno=0 \global\advance\subsecno by 1 \sectionheading{#1}{subsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno}% } % Subsubsections. % % normally numberedsubsubseczzz: \outer\parseargdef\numberedsubsubsec{\numhead3{#1}} \def\numberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynumbered}% {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally appendixsubsubseczzz: \outer\parseargdef\appendixsubsubsec{\apphead3{#1}} \def\appendixsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Yappendix}% {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% } % normally unnumberedsubsubseczzz: \outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} \def\unnumberedsubsubseczzz#1{% \global\advance\subsubsecno by 1 \sectionheading{#1}{subsubsec}{Ynothing}% {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% } % These macros control what the section commands do, according % to what kind of chapter we are in (ordinary, appendix, or unnumbered). % Define them by default for a numbered chapter. \let\section = \numberedsec \let\subsection = \numberedsubsec \let\subsubsection = \numberedsubsubsec % Define @majorheading, @heading and @subheading \def\majorheading{% {\advance\chapheadingskip by 10pt \chapbreak }% \parsearg\chapheadingzzz } \def\chapheading{\chapbreak \parsearg\chapheadingzzz} \def\chapheadingzzz#1{% \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip \nobreak \suppressfirstparagraphindent } % @heading, @subheading, @subsubheading. \parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} \parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} \suppressfirstparagraphindent} % These macros generate a chapter, section, etc. heading only % (including whitespace, linebreaking, etc. around it), % given all the information in convenient, parsed form. % Args are the skip and penalty (usually negative) \def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} % Parameter controlling skip before chapter headings (if needed) \newskip\chapheadingskip % Define plain chapter starts, and page on/off switching for it. \def\chapbreak{\dobreak \chapheadingskip {-4000}} \def\chappager{\par\vfill\supereject} % Because \domark is called before \chapoddpage, the filler page will % get the headings for the next chapter, which is wrong. But we don't % care -- we just disable all headings on the filler page. \def\chapoddpage{% \chappager \ifodd\pageno \else \begingroup \headingsoff \null \chappager \endgroup \fi } \def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} \def\CHAPPAGoff{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chapbreak \global\let\pagealignmacro=\chappager} \def\CHAPPAGon{% \global\let\contentsalignmacro = \chappager \global\let\pchapsepmacro=\chappager \global\let\pagealignmacro=\chappager \global\def\HEADINGSon{\HEADINGSsingle}} \def\CHAPPAGodd{% \global\let\contentsalignmacro = \chapoddpage \global\let\pchapsepmacro=\chapoddpage \global\let\pagealignmacro=\chapoddpage \global\def\HEADINGSon{\HEADINGSdouble}} \CHAPPAGon % Chapter opening. % % #1 is the text, #2 is the section type (Ynumbered, Ynothing, % Yappendix, Yomitfromtoc), #3 the chapter number. % % To test against our argument. \def\Ynothingkeyword{Ynothing} \def\Yomitfromtockeyword{Yomitfromtoc} \def\Yappendixkeyword{Yappendix} % \def\chapmacro#1#2#3{% % Insert the first mark before the heading break (see notes for \domark). \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% \gdef\thissection{}}% % \def\temptype{#2}% \ifx\temptype\Ynothingkeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{\thischaptername}}% \else\ifx\temptype\Yomitfromtockeyword \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% \gdef\thischapter{}}% \else\ifx\temptype\Yappendixkeyword \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\appendixletter}% % \noexpand\putwordAppendix avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \else \toks0={#1}% \xdef\lastchapterdefs{% \gdef\noexpand\thischaptername{\the\toks0}% \gdef\noexpand\thischapternum{\the\chapno}% % \noexpand\putwordChapter avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thischapter{\noexpand\putwordChapter{} \noexpand\thischapternum: \noexpand\thischaptername}% }% \fi\fi\fi % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert the chapter heading break. \pchapsepmacro % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevchapterdefs=\lastchapterdefs \let\prevsectiondefs=\lastsectiondefs \domark % {% \chapfonts \rmisbold % % Have to define \lastsection before calling \donoderef, because the % xref code eventually uses it. On the other hand, it has to be called % after \pchapsepmacro, or the headline will change too soon. \gdef\lastsection{#1}% % % Only insert the separating space if we have a chapter/appendix % number, and don't print the unnumbered ``number''. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unnchap}% \else\ifx\temptype\Yomitfromtockeyword \setbox0 = \hbox{}% contents like unnumbered, but no toc entry \def\toctype{omit}% \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% \def\toctype{app}% \else \setbox0 = \hbox{#3\enspace}% \def\toctype{numchap}% \fi\fi\fi % % Write the toc entry for this chapter. Must come before the % \donoderef, because we include the current node name in the toc % entry, and \donoderef resets it to empty. \writetocentry{\toctype}{#1}{#3}% % % For pdftex, we have to write out the node definition (aka, make % the pdfdest) after any page break, but before the actual text has % been typeset. If the destination for the pdf outline is after the % text, then jumping from the outline may wind up with the text not % being visible, for instance under high magnification. \donoderef{#2}% % % Typeset the actual heading. \nobreak % Avoid page breaks at the interline glue. \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe \unhbox0 #1\par}% }% \nobreak\bigskip % no page break after a chapter title \nobreak } % @centerchap -- centered and unnumbered. \let\centerparametersmaybe = \relax \def\centerparameters{% \advance\rightskip by 3\rightskip \leftskip = \rightskip \parfillskip = 0pt } % I don't think this chapter style is supported any more, so I'm not % updating it with the new noderef stuff. We'll see. --karl, 11aug03. % \def\setchapterstyle #1 {\csname CHAPF#1\endcsname} % \def\unnchfopen #1{% \chapoddpage \vbox{\chapfonts \raggedtitlesettings #1\par}% \nobreak\bigskip\nobreak } \def\chfopen #1#2{\chapoddpage {\chapfonts \vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% \par\penalty 5000 % } \def\centerchfopen #1{% \chapoddpage \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}% \nobreak\bigskip \nobreak } \def\CHAPFopen{% \global\let\chapmacro=\chfopen \global\let\centerchapmacro=\centerchfopen} % Section titles. These macros combine the section number parts and % call the generic \sectionheading to do the printing. % \newskip\secheadingskip \def\secheadingbreak{\dobreak \secheadingskip{-1000}} % Subsection titles. \newskip\subsecheadingskip \def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} % Subsubsection titles. \def\subsubsecheadingskip{\subsecheadingskip} \def\subsubsecheadingbreak{\subsecheadingbreak} % Print any size, any type, section title. % % #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is % the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the % section number. % \def\seckeyword{sec} % \def\sectionheading#1#2#3#4{% {% \checkenv{}% should not be in an environment. % % Switch to the right set of fonts. \csname #2fonts\endcsname \rmisbold % \def\sectionlevel{#2}% \def\temptype{#3}% % % Insert first mark before the heading break (see notes for \domark). \let\prevsectiondefs=\lastsectiondefs \ifx\temptype\Ynothingkeyword \ifx\sectionlevel\seckeyword \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% \gdef\thissection{\thissectionname}}% \fi \else\ifx\temptype\Yomitfromtockeyword % Don't redefine \thissection. \else\ifx\temptype\Yappendixkeyword \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \else \ifx\sectionlevel\seckeyword \toks0={#1}% \xdef\lastsectiondefs{% \gdef\noexpand\thissectionname{\the\toks0}% \gdef\noexpand\thissectionnum{#4}% % \noexpand\putwordSection avoids expanding indigestible % commands in some of the translations. \gdef\noexpand\thissection{\noexpand\putwordSection{} \noexpand\thissectionnum: \noexpand\thissectionname}% }% \fi \fi\fi\fi % % Go into vertical mode. Usually we'll already be there, but we % don't want the following whatsit to end up in a preceding paragraph % if the document didn't happen to have a blank line. \par % % Output the mark. Pass it through \safewhatsit, to take care of % the preceding space. \safewhatsit\domark % % Insert space above the heading. \csname #2headingbreak\endcsname % % Now the second mark, after the heading break. No break points % between here and the heading. \let\prevsectiondefs=\lastsectiondefs \domark % % Only insert the space after the number if we have a section number. \ifx\temptype\Ynothingkeyword \setbox0 = \hbox{}% \def\toctype{unn}% \gdef\lastsection{#1}% \else\ifx\temptype\Yomitfromtockeyword % for @headings -- no section number, don't include in toc, % and don't redefine \lastsection. \setbox0 = \hbox{}% \def\toctype{omit}% \let\sectionlevel=\empty \else\ifx\temptype\Yappendixkeyword \setbox0 = \hbox{#4\enspace}% \def\toctype{app}% \gdef\lastsection{#1}% \else \setbox0 = \hbox{#4\enspace}% \def\toctype{num}% \gdef\lastsection{#1}% \fi\fi\fi % % Write the toc entry (before \donoderef). See comments in \chapmacro. \writetocentry{\toctype\sectionlevel}{#1}{#4}% % % Write the node reference (= pdf destination for pdftex). % Again, see comments in \chapmacro. \donoderef{#3}% % % Interline glue will be inserted when the vbox is completed. % That glue will be a valid breakpoint for the page, since it'll be % preceded by a whatsit (usually from the \donoderef, or from the % \writetocentry if there was no node). We don't want to allow that % break, since then the whatsits could end up on page n while the % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. \nobreak % % Output the actual section heading. \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright \hangindent=\wd0 % zero if no section number \unhbox0 #1}% }% % Add extra space after the heading -- half of whatever came above it. % Don't allow stretch, though. \kern .5 \csname #2headingskip\endcsname % % Do not let the kern be a potential breakpoint, as it would be if it % was followed by glue. \nobreak % % We'll almost certainly start a paragraph next, so don't let that % glue accumulate. (Not a breakpoint because it's preceded by a % discardable item.) However, when a paragraph is not started next % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out % or the negative glue will cause weirdly wrong output, typically % obscuring the section heading with something else. \vskip-\parskip % % This is so the last item on the main vertical list is a known % \penalty > 10000, so \startdefun, etc., can recognize the situation % and do the needful. \penalty 10001 } \message{toc,} % Table of contents. \newwrite\tocfile % Write an entry to the toc file, opening it if necessary. % Called from @chapter, etc. % % Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} % We append the current node name (if any) and page number as additional % arguments for the \{chap,sec,...}entry macros which will eventually % read this. The node name is used in the pdf outlines as the % destination to jump to. % % We open the .toc file for writing here instead of at @setfilename (or % any other fixed time) so that @contents can be anywhere in the document. % But if #1 is `omit', then we don't do anything. This is used for the % table of contents chapter openings themselves. % \newif\iftocfileopened \def\omitkeyword{omit}% % \def\writetocentry#1#2#3{% \edef\writetoctype{#1}% \ifx\writetoctype\omitkeyword \else \iftocfileopened\else \immediate\openout\tocfile = \jobname.toc \global\tocfileopenedtrue \fi % \iflinks {\atdummies \edef\temp{% \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% \temp }% \fi \fi % % Tell \shipout to create a pdf destination on each page, if we're % writing pdf. These are used in the table of contents. We can't % just write one on every page because the title pages are numbered % 1 and 2 (the page numbers aren't printed), and so are the first % two pages of the document. Thus, we'd have two destinations named % `1', and two named `2'. \ifpdf \global\pdfmakepagedesttrue \fi } % These characters do not print properly in the Computer Modern roman % fonts, so we must take special care. This is more or less redundant % with the Texinfo input format setup at the end of this file. % \def\activecatcodes{% \catcode`\"=\active \catcode`\$=\active \catcode`\<=\active \catcode`\>=\active \catcode`\\=\active \catcode`\^=\active \catcode`\_=\active \catcode`\|=\active \catcode`\~=\active } % Read the toc file, which is essentially Texinfo input. \def\readtocfile{% \setupdatafile \activecatcodes \input \tocreadfilename } \newskip\contentsrightmargin \contentsrightmargin=1in \newcount\savepageno \newcount\lastnegativepageno \lastnegativepageno = -1 % Prepare to read what we've written to \tocfile. % \def\startcontents#1{% % If @setchapternewpage on, and @headings double, the contents should % start on an odd page, unlike chapters. Thus, we maintain % \contentsalignmacro in parallel with \pagealignmacro. % From: Torbjorn Granlund \contentsalignmacro \immediate\closeout\tocfile % % Don't need to put `Contents' or `Short Contents' in the headline. % It is abundantly clear what they are. \chapmacro{#1}{Yomitfromtoc}{}% % \savepageno = \pageno \begingroup % Set up to handle contents files properly. \raggedbottom % Worry more about breakpoints than the bottom. \advance\hsize by -\contentsrightmargin % Don't use the full line length. % % Roman numerals for page numbers. \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi } % redefined for the two-volume lispref. We always output on % \jobname.toc even if this is redefined. % \def\tocreadfilename{\jobname.toc} % Normal (long) toc. % \def\contents{% \startcontents{\putwordTOC}% \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \ifeof 1 \else \pdfmakeoutlines \fi \closein 1 \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } % And just the chapters. \def\summarycontents{% \startcontents{\putwordShortTOC}% % \let\partentry = \shortpartentry \let\numchapentry = \shortchapentry \let\appentry = \shortchapentry \let\unnchapentry = \shortunnchapentry % We want a true roman here for the page numbers. \secfonts \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl \let\tt=\shortconttt \rm \hyphenpenalty = 10000 \advance\baselineskip by 1pt % Open it up a little. \def\numsecentry##1##2##3##4{} \let\appsecentry = \numsecentry \let\unnsecentry = \numsecentry \let\numsubsecentry = \numsecentry \let\appsubsecentry = \numsecentry \let\unnsubsecentry = \numsecentry \let\numsubsubsecentry = \numsecentry \let\appsubsubsecentry = \numsecentry \let\unnsubsubsecentry = \numsecentry \openin 1 \tocreadfilename\space \ifeof 1 \else \readtocfile \fi \closein 1 \vfill \eject \contentsalignmacro % in case @setchapternewpage odd is in effect \endgroup \lastnegativepageno = \pageno \global\pageno = \savepageno } \let\shortcontents = \summarycontents % Typeset the label for a chapter or appendix for the short contents. % The arg is, e.g., `A' for an appendix, or `3' for a chapter. % \def\shortchaplabel#1{% % This space should be enough, since a single number is .5em, and the % widest letter (M) is 1em, at least in the Computer Modern fonts. % But use \hss just in case. % (This space doesn't include the extra space that gets added after % the label; that gets put in by \shortchapentry above.) % % We'd like to right-justify chapter numbers, but that looks strange % with appendix letters. And right-justifying numbers and % left-justifying letters looks strange when there is less than 10 % chapters. Have to read the whole toc once to know how many chapters % there are before deciding ... \hbox to 1em{#1\hss}% } % These macros generate individual entries in the table of contents. % The first argument is the chapter or section name. % The last argument is the page number. % The arguments in between are the chapter number, section number, ... % Parts, in the main contents. Replace the part number, which doesn't % exist, with an empty box. Let's hope all the numbers have the same width. % Also ignore the page number, which is conventionally not printed. \def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}} \def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}} % % Parts, in the short toc. \def\shortpartentry#1#2#3#4{% \penalty-300 \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip \shortchapentry{{\bf #1}}{\numeralbox}{}{}% } % Chapters, in the main contents. \def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} % % Chapters, in the short toc. % See comments in \dochapentry re vbox and related settings. \def\shortchapentry#1#2#3#4{% \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% } % Appendices, in the main contents. % Need the word Appendix, and a fixed-size box. % \def\appendixbox#1{% % We use M since it's probably the widest letter. \setbox0 = \hbox{\putwordAppendix{} M}% \hbox to \wd0{\putwordAppendix{} #1\hss}} % \def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} % Unnumbered chapters. \def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} \def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} % Sections. \def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} \let\appsecentry=\numsecentry \def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} % Subsections. \def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} \let\appsubsecentry=\numsubsecentry \def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} % And subsubsections. \def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} \let\appsubsubsecentry=\numsubsubsecentry \def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} % This parameter controls the indentation of the various levels. % Same as \defaultparindent. \newdimen\tocindent \tocindent = 15pt % Now for the actual typesetting. In all these, #1 is the text and #2 is the % page number. % % If the toc has to be broken over pages, we want it to be at chapters % if at all possible; hence the \penalty. \def\dochapentry#1#2{% \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip \begingroup \chapentryfonts \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup \nobreak\vskip .25\baselineskip plus.1\baselineskip } \def\dosecentry#1#2{\begingroup \secentryfonts \leftskip=\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsecentry#1#2{\begingroup \subsecentryfonts \leftskip=2\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} \def\dosubsubsecentry#1#2{\begingroup \subsubsecentryfonts \leftskip=3\tocindent \tocentry{#1}{\dopageno\bgroup#2\egroup}% \endgroup} % We use the same \entry macro as for the index entries. \let\tocentry = \entry % Space between chapter (or whatever) number and the title. \def\labelspace{\hskip1em \relax} \def\dopageno#1{{\rm #1}} \def\doshortpageno#1{{\rm #1}} \def\chapentryfonts{\secfonts \rm} \def\secentryfonts{\textfonts} \def\subsecentryfonts{\textfonts} \def\subsubsecentryfonts{\textfonts} \message{environments,} % @foo ... @end foo. % @tex ... @end tex escapes into raw TeX temporarily. % One exception: @ is still an escape character, so that @end tex works. % But \@ or @@ will get a plain @ character. \envdef\tex{% \setupmarkupstyle{tex}% \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie \catcode `\%=14 \catcode `\+=\other \catcode `\"=\other \catcode `\|=\other \catcode `\<=\other \catcode `\>=\other \catcode`\`=\other \catcode`\'=\other \escapechar=`\\ % % ' is active in math mode (mathcode"8000). So reset it, and all our % other math active characters (just in case), to plain's definitions. \mathactive % \let\b=\ptexb \let\bullet=\ptexbullet \let\c=\ptexc \let\,=\ptexcomma \let\.=\ptexdot \let\dots=\ptexdots \let\equiv=\ptexequiv \let\!=\ptexexclam \let\i=\ptexi \let\indent=\ptexindent \let\noindent=\ptexnoindent \let\{=\ptexlbrace \let\+=\tabalign \let\}=\ptexrbrace \let\/=\ptexslash \let\*=\ptexstar \let\t=\ptext \expandafter \let\csname top\endcsname=\ptextop % outer \let\frenchspacing=\plainfrenchspacing % \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% \def\@{@}% } % There is no need to define \Etex. % Define @lisp ... @end lisp. % @lisp environment forms a group so it can rebind things, % including the definition of @end lisp (which normally is erroneous). % Amount to narrow the margins by for @lisp. \newskip\lispnarrowing \lispnarrowing=0.4in % This is the definition that ^^M gets inside @lisp, @example, and other % such environments. \null is better than a space, since it doesn't % have any width. \def\lisppar{\null\endgraf} % This space is always present above and below environments. \newskip\envskipamount \envskipamount = 0pt % Make spacing and below environment symmetrical. We use \parskip here % to help in doing that, since in @example-like environments \parskip % is reset to zero; thus the \afterenvbreak inserts no space -- but the % start of the next paragraph will insert \parskip. % \def\aboveenvbreak{{% % =10000 instead of <10000 because of a special case in \itemzzz and % \sectionheading, q.v. \ifnum \lastpenalty=10000 \else \advance\envskipamount by \parskip \endgraf \ifdim\lastskip<\envskipamount \removelastskip % it's not a good place to break if the last penalty was \nobreak % or better ... \ifnum\lastpenalty<10000 \penalty-50 \fi \vskip\envskipamount \fi \fi }} \let\afterenvbreak = \aboveenvbreak % \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will % also clear it, so that its embedded environments do the narrowing again. \let\nonarrowing=\relax % @cartouche ... @end cartouche: draw rectangle w/rounded corners around % environment contents. \font\circle=lcircle10 \newdimen\circthick \newdimen\cartouter\newdimen\cartinner \newskip\normbskip\newskip\normpskip\newskip\normlskip \circthick=\fontdimen8\circle % \def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth \def\ctr{{\hskip 6pt\circle\char'010}} \def\cbl{{\circle\char'012\hskip -6pt}} \def\cbr{{\hskip 6pt\circle\char'011}} \def\carttop{\hbox to \cartouter{\hskip\lskip \ctl\leaders\hrule height\circthick\hfil\ctr \hskip\rskip}} \def\cartbot{\hbox to \cartouter{\hskip\lskip \cbl\leaders\hrule height\circthick\hfil\cbr \hskip\rskip}} % \newskip\lskip\newskip\rskip \envdef\cartouche{% \ifhmode\par\fi % can't be in the midst of a paragraph. \startsavinginserts \lskip=\leftskip \rskip=\rightskip \leftskip=0pt\rightskip=0pt % we want these *outside*. \cartinner=\hsize \advance\cartinner by-\lskip \advance\cartinner by-\rskip \cartouter=\hsize \advance\cartouter by 18.4pt % allow for 3pt kerns on either % side, and for 6pt waste from % each corner char, and rule thickness \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip % Flag to tell @lisp, etc., not to narrow margin. \let\nonarrowing = t% % % If this cartouche directly follows a sectioning command, we need the % \parskip glue (backspaced over by default) or the cartouche can % collide with the section heading. \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi % \vbox\bgroup \baselineskip=0pt\parskip=0pt\lineskip=0pt \carttop \hbox\bgroup \hskip\lskip \vrule\kern3pt \vbox\bgroup \kern3pt \hsize=\cartinner \baselineskip=\normbskip \lineskip=\normlskip \parskip=\normpskip \vskip -\parskip \comment % For explanation, see the end of def\group. } \def\Ecartouche{% \ifhmode\par\fi \kern3pt \egroup \kern3pt\vrule \hskip\rskip \egroup \cartbot \egroup \checkinserts } % This macro is called at the beginning of all the @example variants, % inside a group. \newdimen\nonfillparindent \def\nonfillstart{% \aboveenvbreak \hfuzz = 12pt % Don't be fussy \sepspaces % Make spaces be word-separators rather than space tokens. \let\par = \lisppar % don't ignore blank lines \obeylines % each line of input is a line of output \parskip = 0pt % Turn off paragraph indentation but redefine \indent to emulate % the normal \indent. \nonfillparindent=\parindent \parindent = 0pt \let\indent\nonfillindent % \emergencystretch = 0pt % don't try to avoid overfull boxes \ifx\nonarrowing\relax \advance \leftskip by \lispnarrowing \exdentamount=\lispnarrowing \else \let\nonarrowing = \relax \fi \let\exdent=\nofillexdent } \begingroup \obeyspaces % We want to swallow spaces (but not other tokens) after the fake % @indent in our nonfill-environments, where spaces are normally % active and set to @tie, resulting in them not being ignored after % @indent. \gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% \gdef\nonfillindentcheck{% \ifx\temp % \expandafter\nonfillindentgobble% \else% \leavevmode\nonfillindentbox% \fi% }% \endgroup \def\nonfillindentgobble#1{\nonfillindent} \def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} % If you want all examples etc. small: @set dispenvsize small. % If you want even small examples the full size: @set dispenvsize nosmall. % This affects the following displayed environments: % @example, @display, @format, @lisp % \def\smallword{small} \def\nosmallword{nosmall} \let\SETdispenvsize\relax \def\setnormaldispenv{% \ifx\SETdispenvsize\smallword % end paragraph for sake of leading, in case document has no blank % line. This is redundant with what happens in \aboveenvbreak, but % we need to do it before changing the fonts, and it's inconvenient % to change the fonts afterward. \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } \def\setsmalldispenv{% \ifx\SETdispenvsize\nosmallword \else \ifnum \lastpenalty=10000 \else \endgraf \fi \smallexamplefonts \rm \fi } % We often define two environments, @foo and @smallfoo. % Let's do it in one command. #1 is the env name, #2 the definition. \def\makedispenvdef#1#2{% \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}% \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}% \expandafter\let\csname E#1\endcsname \afterenvbreak \expandafter\let\csname Esmall#1\endcsname \afterenvbreak } % Define two environment synonyms (#1 and #2) for an environment. \def\maketwodispenvdef#1#2#3{% \makedispenvdef{#1}{#3}% \makedispenvdef{#2}{#3}% } % % @lisp: indented, narrowed, typewriter font; % @example: same as @lisp. % % @smallexample and @smalllisp: use smaller fonts. % Originally contributed by Pavel@xerox. % \maketwodispenvdef{lisp}{example}{% \nonfillstart \tt\setupmarkupstyle{example}% \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. \gobble % eat return } % @display/@smalldisplay: same as @lisp except keep current font. % \makedispenvdef{display}{% \nonfillstart \gobble } % @format/@smallformat: same as @display except don't narrow margins. % \makedispenvdef{format}{% \let\nonarrowing = t% \nonfillstart \gobble } % @flushleft: same as @format, but doesn't obey \SETdispenvsize. \envdef\flushleft{% \let\nonarrowing = t% \nonfillstart \gobble } \let\Eflushleft = \afterenvbreak % @flushright. % \envdef\flushright{% \let\nonarrowing = t% \nonfillstart \advance\leftskip by 0pt plus 1fill\relax \gobble } \let\Eflushright = \afterenvbreak % @raggedright does more-or-less normal line breaking but no right % justification. From plain.tex. \envdef\raggedright{% \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax } \let\Eraggedright\par \envdef\raggedleft{% \parindent=0pt \leftskip0pt plus2em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedleft\par \envdef\raggedcenter{% \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt \hbadness=10000 % Last line will usually be underfull, so turn off % badness reporting. } \let\Eraggedcenter\par % @quotation does normal linebreaking (hence we can't use \nonfillstart) % and narrows the margins. We keep \parskip nonzero in general, since % we're doing normal filling. So, when using \aboveenvbreak and % \afterenvbreak, temporarily make \parskip 0. % \makedispenvdef{quotation}{\quotationstart} % \def\quotationstart{% \indentedblockstart % same as \indentedblock, but increase right margin too. \ifx\nonarrowing\relax \advance\rightskip by \lispnarrowing \fi \parsearg\quotationlabel } % We have retained a nonzero parskip for the environment, since we're % doing normal filling. % \def\Equotation{% \par \ifx\quotationauthor\thisisundefined\else % indent a bit. \leftline{\kern 2\leftskip \sl ---\quotationauthor}% \fi {\parskip=0pt \afterenvbreak}% } \def\Esmallquotation{\Equotation} % If we're given an argument, typeset it in bold with a colon after. \def\quotationlabel#1{% \def\temp{#1}% \ifx\temp\empty \else {\bf #1: }% \fi } % @indentedblock is like @quotation, but indents only on the left and % has no optional argument. % \makedispenvdef{indentedblock}{\indentedblockstart} % \def\indentedblockstart{% {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip \parindent=0pt % % @cartouche defines \nonarrowing to inhibit narrowing at next level down. \ifx\nonarrowing\relax \advance\leftskip by \lispnarrowing \exdentamount = \lispnarrowing \else \let\nonarrowing = \relax \fi } % Keep a nonzero parskip for the environment, since we're doing normal filling. % \def\Eindentedblock{% \par {\parskip=0pt \afterenvbreak}% } \def\Esmallindentedblock{\Eindentedblock} % LaTeX-like @verbatim...@end verbatim and @verb{...} % If we want to allow any as delimiter, % we need the curly braces so that makeinfo sees the @verb command, eg: % `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org % % [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. % % [Knuth] p.344; only we need to do the other characters Texinfo sets % active too. Otherwise, they get lost as the first character on a % verbatim line. \def\dospecials{% \do\ \do\\\do\{\do\}\do\$\do\&% \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% \do\<\do\>\do\|\do\@\do+\do\"% % Don't do the quotes -- if we do, @set txicodequoteundirected and % @set txicodequotebacktick will not have effect on @verb and % @verbatim, and ?` and !` ligatures won't get disabled. %\do\`\do\'% } % % [Knuth] p. 380 \def\uncatcodespecials{% \def\do##1{\catcode`##1=\other}\dospecials} % % Setup for the @verb command. % % Eight spaces for a tab \begingroup \catcode`\^^I=\active \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} \endgroup % \def\setupverb{% \tt % easiest (and conventionally used) font for verbatim \def\par{\leavevmode\endgraf}% \setupmarkupstyle{verb}% \tabeightspaces % Respect line breaks, % print special symbols as themselves, and % make each space count % must do in this order: \obeylines \uncatcodespecials \sepspaces } % Setup for the @verbatim environment % % Real tab expansion. \newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount % % We typeset each line of the verbatim in an \hbox, so we can handle % tabs. The \global is in case the verbatim line starts with an accent, % or some other command that starts with a begin-group. Otherwise, the % entire \verbbox would disappear at the corresponding end-group, before % it is typeset. Meanwhile, we can't have nested verbatim commands % (can we?), so the \global won't be overwriting itself. \newbox\verbbox \def\starttabbox{\global\setbox\verbbox=\hbox\bgroup} % \begingroup \catcode`\^^I=\active \gdef\tabexpand{% \catcode`\^^I=\active \def^^I{\leavevmode\egroup \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab \divide\dimen\verbbox by\tabw \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox }% } \endgroup % start the verbatim environment. \def\setupverbatim{% \let\nonarrowing = t% \nonfillstart \tt % easiest (and conventionally used) font for verbatim % The \leavevmode here is for blank lines. Otherwise, we would % never \starttabox and the \egroup would end verbatim mode. \def\par{\leavevmode\egroup\box\verbbox\endgraf}% \tabexpand \setupmarkupstyle{verbatim}% % Respect line breaks, % print special symbols as themselves, and % make each space count. % Must do in this order: \obeylines \uncatcodespecials \sepspaces \everypar{\starttabbox}% } % Do the @verb magic: verbatim text is quoted by unique % delimiter characters. Before first delimiter expect a % right brace, after last delimiter expect closing brace: % % \def\doverb'{'#1'}'{#1} % % [Knuth] p. 382; only eat outer {} \begingroup \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] \endgroup % \def\verb{\begingroup\setupverb\doverb} % % % Do the @verbatim magic: define the macro \doverbatim so that % the (first) argument ends when '@end verbatim' is reached, ie: % % \def\doverbatim#1@end verbatim{#1} % % For Texinfo it's a lot easier than for LaTeX, % because texinfo's \verbatim doesn't stop at '\end{verbatim}': % we need not redefine '\', '{' and '}'. % % Inspired by LaTeX's verbatim command set [latex.ltx] % \begingroup \catcode`\ =\active \obeylines % % ignore everything up to the first ^^M, that's the newline at the end % of the @verbatim input line itself. Otherwise we get an extra blank % line in the output. \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% % We really want {...\end verbatim} in the body of the macro, but % without the active space; thus we have to use \xdef and \gobble. \endgroup % \envdef\verbatim{% \setupverbatim\doverbatim } \let\Everbatim = \afterenvbreak % @verbatiminclude FILE - insert text of file in verbatim environment. % \def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} % \def\doverbatiminclude#1{% {% \makevalueexpandable \setupverbatim \indexnofonts % Allow `@@' and other weird things in file names. \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}% \input #1 \afterenvbreak }% } % @copying ... @end copying. % Save the text away for @insertcopying later. % % We save the uninterpreted tokens, rather than creating a box. % Saving the text in a box would be much easier, but then all the % typesetting commands (@smallbook, font changes, etc.) have to be done % beforehand -- and a) we want @copying to be done first in the source % file; b) letting users define the frontmatter in as flexible order as % possible is very desirable. % \def\copying{\checkenv{}\begingroup\scanargctxt\docopying} \def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} % \def\insertcopying{% \begingroup \parindent = 0pt % paragraph indentation looks wrong on title page \scanexp\copyingtext \endgroup } \message{defuns,} % @defun etc. \newskip\defbodyindent \defbodyindent=.4in \newskip\defargsindent \defargsindent=50pt \newskip\deflastargmargin \deflastargmargin=18pt \newcount\defunpenalty % Start the processing of @deffn: \def\startdefun{% \ifnum\lastpenalty<10000 \medbreak \defunpenalty=10003 % Will keep this @deffn together with the % following @def command, see below. \else % If there are two @def commands in a row, we'll have a \nobreak, % which is there to keep the function description together with its % header. But if there's nothing but headers, we need to allow a % break somewhere. Check specifically for penalty 10002, inserted % by \printdefunline, instead of 10000, since the sectioning % commands also insert a nobreak penalty, and we don't want to allow % a break between a section heading and a defun. % % As a further refinement, we avoid "club" headers by signalling % with penalty of 10003 after the very first @deffn in the % sequence (see above), and penalty of 10002 after any following % @def command. \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi % % Similarly, after a section heading, do not allow a break. % But do insert the glue. \medskip % preceded by discardable penalty, so not a breakpoint \fi % \parindent=0in \advance\leftskip by \defbodyindent \exdentamount=\defbodyindent } \def\dodefunx#1{% % First, check whether we are in the right environment: \checkenv#1% % % As above, allow line break if we have multiple x headers in a row. % It's not a great place, though. \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi % % And now, it's time to reuse the body of the original defun: \expandafter\gobbledefun#1% } \def\gobbledefun#1\startdefun{} % \printdefunline \deffnheader{text} % \def\printdefunline#1#2{% \begingroup % call \deffnheader: #1#2 \endheader % common ending: \interlinepenalty = 10000 \advance\rightskip by 0pt plus 1fil\relax \endgraf \nobreak\vskip -\parskip \penalty\defunpenalty % signal to \startdefun and \dodefunx % Some of the @defun-type tags do not enable magic parentheses, % rendering the following check redundant. But we don't optimize. \checkparencounts \endgroup } \def\Edefun{\endgraf\medbreak} % \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; % the only thing remaining is to define \deffnheader. % \def\makedefun#1{% \expandafter\let\csname E#1\endcsname = \Edefun \edef\temp{\noexpand\domakedefun \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% \temp } % \domakedefun \deffn \deffnx \deffnheader % % Define \deffn and \deffnx, without parameters. % \deffnheader has to be defined explicitly. % \def\domakedefun#1#2#3{% \envdef#1{% \startdefun \doingtypefnfalse % distinguish typed functions from all else \parseargusing\activeparens{\printdefunline#3}% }% \def#2{\dodefunx#1}% \def#3% } \newif\ifdoingtypefn % doing typed function? \newif\ifrettypeownline % typeset return type on its own line? % @deftypefnnewline on|off says whether the return type of typed functions % are printed on their own line. This affects @deftypefn, @deftypefun, % @deftypeop, and @deftypemethod. % \parseargdef\deftypefnnewline{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETtxideftypefnnl\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETtxideftypefnnl\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @txideftypefnnl value `\temp', must be on|off}% \fi\fi } % Untyped functions: % @deffn category name args \makedefun{deffn}{\deffngeneral{}} % @deffn category class name args \makedefun{defop}#1 {\defopon{#1\ \putwordon}} % \defopon {category on}class name args \def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deffngeneral {subind}category name args % \def\deffngeneral#1#2 #3 #4\endheader{% % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. \dosubind{fn}{\code{#3}}{#1}% \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% } % Typed functions: % @deftypefn category type name args \makedefun{deftypefn}{\deftypefngeneral{}} % @deftypeop category class type name args \makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} % \deftypeopon {category on}class type name args \def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } % \deftypefngeneral {subind}category type name args % \def\deftypefngeneral#1#2 #3 #4 #5\endheader{% \dosubind{fn}{\code{#4}}{#1}% \doingtypefntrue \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Typed variables: % @deftypevr category type var args \makedefun{deftypevr}{\deftypecvgeneral{}} % @deftypecv category class type var args \makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} % \deftypecvof {category of}class type var args \def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } % \deftypecvgeneral {subind}category type var args % \def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% \dosubind{vr}{\code{#4}}{#1}% \defname{#2}{#3}{#4}\defunargs{#5\unskip}% } % Untyped variables: % @defvr category var args \makedefun{defvr}#1 {\deftypevrheader{#1} {} } % @defcv category class var args \makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} % \defcvof {category of}class var args \def\defcvof#1#2 {\deftypecvof{#1}#2 {} } % Types: % @deftp category name args \makedefun{deftp}#1 #2 #3\endheader{% \doind{tp}{\code{#2}}% \defname{#1}{}{#2}\defunargs{#3\unskip}% } % Remaining @defun-like shortcuts: \makedefun{defun}{\deffnheader{\putwordDeffunc} } \makedefun{defmac}{\deffnheader{\putwordDefmac} } \makedefun{defspec}{\deffnheader{\putwordDefspec} } \makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } \makedefun{defvar}{\defvrheader{\putwordDefvar} } \makedefun{defopt}{\defvrheader{\putwordDefopt} } \makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } \makedefun{defmethod}{\defopon\putwordMethodon} \makedefun{deftypemethod}{\deftypeopon\putwordMethodon} \makedefun{defivar}{\defcvof\putwordInstanceVariableof} \makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} % \defname, which formats the name of the @def (not the args). % #1 is the category, such as "Function". % #2 is the return type, if any. % #3 is the function name. % % We are followed by (but not passed) the arguments, if any. % \def\defname#1#2#3{% \par % Get the values of \leftskip and \rightskip as they were outside the @def... \advance\leftskip by -\defbodyindent % % Determine if we are typesetting the return type of a typed function % on a line by itself. \rettypeownlinefalse \ifdoingtypefn % doing a typed function specifically? % then check user option for putting return type on its own line: \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else \rettypeownlinetrue \fi \fi % % How we'll format the category name. Putting it in brackets helps % distinguish it from the body text that may end up on the next line % just below it. \def\temp{#1}% \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} % % Figure out line sizes for the paragraph shape. We'll always have at % least two. \tempnum = 2 % % The first line needs space for \box0; but if \rightskip is nonzero, % we need only space for the part of \box0 which exceeds it: \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip % % If doing a return type on its own line, we'll have another line. \ifrettypeownline \advance\tempnum by 1 \def\maybeshapeline{0in \hsize}% \else \def\maybeshapeline{}% \fi % % The continuations: \dimen2=\hsize \advance\dimen2 by -\defargsindent % % The final paragraph shape: \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2 % % Put the category name at the right margin. \noindent \hbox to 0pt{% \hfil\box0 \kern-\hsize % \hsize has to be shortened this way: \kern\leftskip % Intentionally do not respect \rightskip, since we need the space. }% % % Allow all lines to be underfull without complaint: \tolerance=10000 \hbadness=10000 \exdentamount=\defbodyindent {% % defun fonts. We use typewriter by default (used to be bold) because: % . we're printing identifiers, they should be in tt in principle. % . in languages with many accents, such as Czech or French, it's % common to leave accents off identifiers. The result looks ok in % tt, but exceedingly strange in rm. % . we don't want -- and --- to be treated as ligatures. % . this still does not fix the ?` and !` ligatures, but so far no % one has made identifiers using them :). \df \tt \def\temp{#2}% text of the return type \ifx\temp\empty\else \tclose{\temp}% typeset the return type \ifrettypeownline % put return type on its own line; prohibit line break following: \hfil\vadjust{\nobreak}\break \else \space % type on same line, so just followed by a space \fi \fi % no return type #3% output function name }% {\rm\enskip}% hskip 0.5 em of \tenrm % \boldbrax % arguments will be output next, if any. } % Print arguments in slanted roman (not ttsl), inconsistently with using % tt for the name. This is because literal text is sometimes needed in % the argument list (groff manual), and ttsl and tt are not very % distinguishable. Prevent hyphenation at `-' chars. % \def\defunargs#1{% % use sl by default (not ttsl), % tt for the names. \df \sl \hyphenchar\font=0 % % On the other hand, if an argument has two dashes (for instance), we % want a way to get ttsl. We used to recommend @var for that, so % leave the code in, but it's strange for @var to lead to typewriter. % Nowadays we recommend @code, since the difference between a ttsl hyphen % and a tt hyphen is pretty tiny. @code also disables ?` !`. \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% #1% \sl\hyphenchar\font=45 } % We want ()&[] to print specially on the defun line. % \def\activeparens{% \catcode`\(=\active \catcode`\)=\active \catcode`\[=\active \catcode`\]=\active \catcode`\&=\active } % Make control sequences which act like normal parenthesis chars. \let\lparen = ( \let\rparen = ) % Be sure that we always have a definition for `(', etc. For example, % if the fn name has parens in it, \boldbrax will not be in effect yet, % so TeX would otherwise complain about undefined control sequence. { \activeparens \global\let(=\lparen \global\let)=\rparen \global\let[=\lbrack \global\let]=\rbrack \global\let& = \& \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} \gdef\magicamp{\let&=\amprm} } \newcount\parencount % If we encounter &foo, then turn on ()-hacking afterwards \newif\ifampseen \def\amprm#1 {\ampseentrue{\bf\ }} \def\parenfont{% \ifampseen % At the first level, print parens in roman, % otherwise use the default font. \ifnum \parencount=1 \rm \fi \else % The \sf parens (in \boldbrax) actually are a little bolder than % the contained text. This is especially needed for [ and ] . \sf \fi } \def\infirstlevel#1{% \ifampseen \ifnum\parencount=1 #1% \fi \fi } \def\bfafterword#1 {#1 \bf} \def\opnr{% \global\advance\parencount by 1 {\parenfont(}% \infirstlevel \bfafterword } \def\clnr{% {\parenfont)}% \infirstlevel \sl \global\advance\parencount by -1 } \newcount\brackcount \def\lbrb{% \global\advance\brackcount by 1 {\bf[}% } \def\rbrb{% {\bf]}% \global\advance\brackcount by -1 } \def\checkparencounts{% \ifnum\parencount=0 \else \badparencount \fi \ifnum\brackcount=0 \else \badbrackcount \fi } % these should not use \errmessage; the glibc manual, at least, actually % has such constructs (when documenting function pointers). \def\badparencount{% \message{Warning: unbalanced parentheses in @def...}% \global\parencount=0 } \def\badbrackcount{% \message{Warning: unbalanced square brackets in @def...}% \global\brackcount=0 } \message{macros,} % @macro. % To do this right we need a feature of e-TeX, \scantokens, % which we arrange to emulate with a temporary file in ordinary TeX. \ifx\eTeXversion\thisisundefined \newwrite\macscribble \def\scantokens#1{% \toks0={#1}% \immediate\openout\macscribble=\jobname.tmp \immediate\write\macscribble{\the\toks0}% \immediate\closeout\macscribble \input \jobname.tmp } \fi \def\scanmacro#1{\begingroup \newlinechar`\^^M \let\xeatspaces\eatspaces % % Undo catcode changes of \startcontents and \doprintindex % When called from @insertcopying or (short)caption, we need active % backslash to get it printed correctly. Previously, we had % \catcode`\\=\other instead. We'll see whether a problem appears % with macro expansion. --kasal, 19aug04 \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ % % ... and for \example: \spaceisspace % % The \empty here causes a following catcode 5 newline to be eaten as % part of reading whitespace after a control sequence. It does not % eat a catcode 13 newline. There's no good way to handle the two % cases (untried: maybe e-TeX's \everyeof could help, though plain TeX % would then have different behavior). See the Macro Details node in % the manual for the workaround we recommend for macros and % line-oriented commands. % \scantokens{#1\empty}% \endgroup} \def\scanexp#1{% \edef\temp{\noexpand\scanmacro{#1}}% \temp } \newcount\paramno % Count of parameters \newtoks\macname % Macro name \newif\ifrecursive % Is it recursive? % List of all defined macros in the form % \definedummyword\macro1\definedummyword\macro2... % Currently is also contains all @aliases; the list can be split % if there is a need. \def\macrolist{} % Add the macro to \macrolist \def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} \def\addtomacrolistxxx#1{% \toks0 = \expandafter{\macrolist\definedummyword#1}% \xdef\macrolist{\the\toks0}% } % Utility routines. % This does \let #1 = #2, with \csnames; that is, % \let \csname#1\endcsname = \csname#2\endcsname % (except of course we have to play expansion games). % \def\cslet#1#2{% \expandafter\let \csname#1\expandafter\endcsname \csname#2\endcsname } % Trim leading and trailing spaces off a string. % Concepts from aro-bend problem 15 (see CTAN). {\catcode`\@=11 \gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} \gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} \gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} \def\unbrace#1{#1} \unbrace{\gdef\trim@@@ #1 } #2@{#1} } % Trim a single trailing ^^M off a string. {\catcode`\^^M=\other \catcode`\Q=3% \gdef\eatcr #1{\eatcra #1Q^^MQ}% \gdef\eatcra#1^^MQ{\eatcrb#1Q}% \gdef\eatcrb#1Q#2Q{#1}% } % Macro bodies are absorbed as an argument in a context where % all characters are catcode 10, 11 or 12, except \ which is active % (as in normal texinfo). It is necessary to change the definition of \ % to recognize macro arguments; this is the job of \mbodybackslash. % % Non-ASCII encodings make 8-bit characters active, so un-activate % them to avoid their expansion. Must do this non-globally, to % confine the change to the current group. % % It's necessary to have hard CRs when the macro is executed. This is % done by making ^^M (\endlinechar) catcode 12 when reading the macro % body, and then making it the \newlinechar in \scanmacro. % \def\scanctxt{% used as subroutine \catcode`\"=\other \catcode`\+=\other \catcode`\<=\other \catcode`\>=\other \catcode`\@=\other \catcode`\^=\other \catcode`\_=\other \catcode`\|=\other \catcode`\~=\other \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi } \def\scanargctxt{% used for copying and captions, not macros. \scanctxt \catcode`\\=\other \catcode`\^^M=\other } \def\macrobodyctxt{% used for @macro definitions \scanctxt \catcode`\{=\other \catcode`\}=\other \catcode`\^^M=\other \usembodybackslash } \def\macroargctxt{% used when scanning invocations \scanctxt \catcode`\\=0 } % why catcode 0 for \ in the above? To recognize \\ \{ \} as "escapes" % for the single characters \ { }. Thus, we end up with the "commands" % that would be written @\ @{ @} in a Texinfo document. % % We already have @{ and @}. For @\, we define it here, and only for % this purpose, to produce a typewriter backslash (so, the @\ that we % define for @math can't be used with @macro calls): % \def\\{\normalbackslash}% % % We would like to do this for \, too, since that is what makeinfo does. % But it is not possible, because Texinfo already has a command @, for a % cedilla accent. Documents must use @comma{} instead. % % \anythingelse will almost certainly be an error of some kind. % \mbodybackslash is the definition of \ in @macro bodies. % It maps \foo\ => \csname macarg.foo\endcsname => #N % where N is the macro parameter number. % We define \csname macarg.\endcsname to be \realbackslash, so % \\ in macro replacement text gets you a backslash. % {\catcode`@=0 @catcode`@\=@active @gdef@usembodybackslash{@let\=@mbodybackslash} @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} } \expandafter\def\csname macarg.\endcsname{\realbackslash} \def\margbackslash#1{\char`\#1 } \def\macro{\recursivefalse\parsearg\macroxxx} \def\rmacro{\recursivetrue\parsearg\macroxxx} \def\macroxxx#1{% \getargs{#1}% now \macname is the macname and \argl the arglist \ifx\argl\empty % no arguments \paramno=0\relax \else \expandafter\parsemargdef \argl;% \if\paramno>256\relax \ifx\eTeXversion\thisisundefined \errhelp = \EMsimple \errmessage{You need eTeX to compile a file with macros with more than 256 arguments} \fi \fi \fi \if1\csname ismacro.\the\macname\endcsname \message{Warning: redefining \the\macname}% \else \expandafter\ifx\csname \the\macname\endcsname \relax \else \errmessage{Macro name \the\macname\space already defined}\fi \global\cslet{macsave.\the\macname}{\the\macname}% \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% \addtomacrolist{\the\macname}% \fi \begingroup \macrobodyctxt \ifrecursive \expandafter\parsermacbody \else \expandafter\parsemacbody \fi} \parseargdef\unmacro{% \if1\csname ismacro.#1\endcsname \global\cslet{#1}{macsave.#1}% \global\expandafter\let \csname ismacro.#1\endcsname=0% % Remove the macro name from \macrolist: \begingroup \expandafter\let\csname#1\endcsname \relax \let\definedummyword\unmacrodo \xdef\macrolist{\macrolist}% \endgroup \else \errmessage{Macro #1 not defined}% \fi } % Called by \do from \dounmacro on each macro. The idea is to omit any % macro definitions that have been changed to \relax. % \def\unmacrodo#1{% \ifx #1\relax % remove this \else \noexpand\definedummyword \noexpand#1% \fi } % This makes use of the obscure feature that if the last token of a % is #, then the preceding argument is delimited by % an opening brace, and that opening brace is not consumed. \def\getargs#1{\getargsxxx#1{}} \def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} \def\getmacname#1 #2\relax{\macname={#1}} \def\getmacargs#1{\def\argl{#1}} % For macro processing make @ a letter so that we can make Texinfo private macro names. \edef\texiatcatcode{\the\catcode`\@} \catcode `@=11\relax % Parse the optional {params} list. Set up \paramno and \paramlist % so \defmacro knows what to do. Define \macarg.BLAH for each BLAH % in the params list to some hook where the argument si to be expanded. If % there are less than 10 arguments that hook is to be replaced by ##N where N % is the position in that list, that is to say the macro arguments are to be % defined `a la TeX in the macro body. % % That gets used by \mbodybackslash (above). % % We need to get `macro parameter char #' into several definitions. % The technique used is stolen from LaTeX: let \hash be something % unexpandable, insert that wherever you need a #, and then redefine % it to # just before using the token list produced. % % The same technique is used to protect \eatspaces till just before % the macro is used. % % If there are 10 or more arguments, a different technique is used, where the % hook remains in the body, and when macro is to be expanded the body is % processed again to replace the arguments. % % In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the % argument N value and then \edef the body (nothing else will expand because of % the catcode regime underwhich the body was input). % % If you compile with TeX (not eTeX), and you have macros with 10 or more % arguments, you need that no macro has more than 256 arguments, otherwise an % error is produced. \def\parsemargdef#1;{% \paramno=0\def\paramlist{}% \let\hash\relax \let\xeatspaces\relax \parsemargdefxxx#1,;,% % In case that there are 10 or more arguments we parse again the arguments % list to set new definitions for the \macarg.BLAH macros corresponding to % each BLAH argument. It was anyhow needed to parse already once this list % in order to count the arguments, and as macros with at most 9 arguments % are by far more frequent than macro with 10 or more arguments, defining % twice the \macarg.BLAH macros does not cost too much processing power. \ifnum\paramno<10\relax\else \paramno0\relax \parsemmanyargdef@@#1,;,% 10 or more arguments \fi } \def\parsemargdefxxx#1,{% \if#1;\let\next=\relax \else \let\next=\parsemargdefxxx \advance\paramno by 1 \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname {\xeatspaces{\hash\the\paramno}}% \edef\paramlist{\paramlist\hash\the\paramno,}% \fi\next} \def\parsemmanyargdef@@#1,{% \if#1;\let\next=\relax \else \let\next=\parsemmanyargdef@@ \edef\tempb{\eatspaces{#1}}% \expandafter\def\expandafter\tempa \expandafter{\csname macarg.\tempb\endcsname}% % Note that we need some extra \noexpand\noexpand, this is because we % don't want \the to be expanded in the \parsermacbody as it uses an % \xdef . \expandafter\edef\tempa {\noexpand\noexpand\noexpand\the\toks\the\paramno}% \advance\paramno by 1\relax \fi\next} % These two commands read recursive and nonrecursive macro bodies. % (They're different since rec and nonrec macros end differently.) % \catcode `\@\texiatcatcode \long\def\parsemacbody#1@end macro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \long\def\parsermacbody#1@end rmacro% {\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% \catcode `\@=11\relax \let\endargs@\relax \let\nil@\relax \def\nilm@{\nil@}% \long\def\nillm@{\nil@}% % This macro is expanded during the Texinfo macro expansion, not during its % definition. It gets all the arguments values and assigns them to macros % macarg.ARGNAME % % #1 is the macro name % #2 is the list of argument names % #3 is the list of argument values \def\getargvals@#1#2#3{% \def\macargdeflist@{}% \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion. \def\paramlist{#2,\nil@}% \def\macroname{#1}% \begingroup \macroargctxt \def\argvaluelist{#3,\nil@}% \def\@tempa{#3}% \ifx\@tempa\empty \setemptyargvalues@ \else \getargvals@@ \fi } % \def\getargvals@@{% \ifx\paramlist\nilm@ % Some sanity check needed here that \argvaluelist is also empty. \ifx\argvaluelist\nillm@ \else \errhelp = \EMsimple \errmessage{Too many arguments in macro `\macroname'!}% \fi \let\next\macargexpandinbody@ \else \ifx\argvaluelist\nillm@ % No more arguments values passed to macro. Set remaining named-arg % macros to empty. \let\next\setemptyargvalues@ \else % pop current arg name into \@tempb \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}% \expandafter\@tempa\expandafter{\paramlist}% % pop current argument value into \@tempc \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}% \expandafter\@tempa\expandafter{\argvaluelist}% % Here \@tempb is the current arg name and \@tempc is the current arg value. % First place the new argument macro definition into \@tempd \expandafter\macname\expandafter{\@tempc}% \expandafter\let\csname macarg.\@tempb\endcsname\relax \expandafter\def\expandafter\@tempe\expandafter{% \csname macarg.\@tempb\endcsname}% \edef\@tempd{\long\def\@tempe{\the\macname}}% \push@\@tempd\macargdeflist@ \let\next\getargvals@@ \fi \fi \next } \def\push@#1#2{% \expandafter\expandafter\expandafter\def \expandafter\expandafter\expandafter#2% \expandafter\expandafter\expandafter{% \expandafter#1#2}% } % Replace arguments by their values in the macro body, and place the result % in macro \@tempa \def\macvalstoargs@{% % To do this we use the property that token registers that are \the'ed % within an \edef expand only once. So we are going to place all argument % values into respective token registers. % % First we save the token context, and initialize argument numbering. \begingroup \paramno0\relax % Then, for each argument number #N, we place the corresponding argument % value into a new token list register \toks#N \expandafter\putargsintokens@\saveparamlist@,;,% % Then, we expand the body so that argument are replaced by their % values. The trick for values not to be expanded themselves is that they % are within tokens and that tokens expand only once in an \edef . \edef\@tempc{\csname mac.\macroname .body\endcsname}% % Now we restore the token stack pointer to free the token list registers % which we have used, but we make sure that expanded body is saved after % group. \expandafter \endgroup \expandafter\def\expandafter\@tempa\expandafter{\@tempc}% } \def\macargexpandinbody@{% %% Define the named-macro outside of this group and then close this group. \expandafter \endgroup \macargdeflist@ % First the replace in body the macro arguments by their values, the result % is in \@tempa . \macvalstoargs@ % Then we point at the \norecurse or \gobble (for recursive) macro value % with \@tempb . \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname % Depending on whether it is recursive or not, we need some tailing % \egroup . \ifx\@tempb\gobble \let\@tempc\relax \else \let\@tempc\egroup \fi % And now we do the real job: \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}% \@tempd } \def\putargsintokens@#1,{% \if#1;\let\next\relax \else \let\next\putargsintokens@ % First we allocate the new token list register, and give it a temporary % alias \@tempb . \toksdef\@tempb\the\paramno % Then we place the argument value into that token list register. \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname \expandafter\@tempb\expandafter{\@tempa}% \advance\paramno by 1\relax \fi \next } % Save the token stack pointer into macro #1 \def\texisavetoksstackpoint#1{\edef#1{\the\@cclvi}} % Restore the token stack pointer from number in macro #1 \def\texirestoretoksstackpoint#1{\expandafter\mathchardef\expandafter\@cclvi#1\relax} % newtoks that can be used non \outer . \def\texinonouternewtoks{\alloc@ 5\toks \toksdef \@cclvi} % Tailing missing arguments are set to empty \def\setemptyargvalues@{% \ifx\paramlist\nilm@ \let\next\macargexpandinbody@ \else \expandafter\setemptyargvaluesparser@\paramlist\endargs@ \let\next\setemptyargvalues@ \fi \next } \def\setemptyargvaluesparser@#1,#2\endargs@{% \expandafter\def\expandafter\@tempa\expandafter{% \expandafter\def\csname macarg.#1\endcsname{}}% \push@\@tempa\macargdeflist@ \def\paramlist{#2}% } % #1 is the element target macro % #2 is the list macro % #3,#4\endargs@ is the list value \def\pop@#1#2#3,#4\endargs@{% \def#1{#3}% \def#2{#4}% } \long\def\longpop@#1#2#3,#4\endargs@{% \long\def#1{#3}% \long\def#2{#4}% } % This defines a Texinfo @macro. There are eight cases: recursive and % nonrecursive macros of zero, one, up to nine, and many arguments. % Much magic with \expandafter here. % \xdef is used so that macro definitions will survive the file % they're defined in; @include reads the file inside a group. % \def\defmacro{% \let\hash=##% convert placeholders to macro parameter chars \ifrecursive \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\scanmacro{\temp}}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup\noexpand\scanmacro{\temp}}% \else \ifnum\paramno<10\relax % at most 9 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{\egroup\noexpand\scanmacro{\temp}}% \else % 10 or more \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble \fi \fi \else \ifcase\paramno % 0 \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \or % 1 \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \noexpand\braceorline \expandafter\noexpand\csname\the\macname xxx\endcsname}% \expandafter\xdef\csname\the\macname xxx\endcsname##1{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % at most 9 \ifnum\paramno<10\relax \expandafter\xdef\csname\the\macname\endcsname{% \bgroup\noexpand\macroargctxt \expandafter\noexpand\csname\the\macname xx\endcsname}% \expandafter\xdef\csname\the\macname xx\endcsname##1{% \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% \expandafter\expandafter \expandafter\xdef \expandafter\expandafter \csname\the\macname xxx\endcsname \paramlist{% \egroup \noexpand\norecurse{\the\macname}% \noexpand\scanmacro{\temp}\egroup}% \else % 10 or more: \expandafter\xdef\csname\the\macname\endcsname{% \noexpand\getargvals@{\the\macname}{\argl}% }% \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse \fi \fi \fi} \catcode `\@\texiatcatcode\relax \def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} % \braceorline decides whether the next nonwhitespace character is a % {. If so it reads up to the closing }, if not, it reads the whole % line. Whatever was read is then fed to the next control sequence % as an argument (by \parsebrace or \parsearg). % \def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} \def\braceorlinexxx{% \ifx\nchar\bgroup\else \expandafter\parsearg \fi \macnamexxx} % @alias. % We need some trickery to remove the optional spaces around the equal % sign. Make them active and then expand them all to nothing. % \def\alias{\parseargusing\obeyspaces\aliasxxx} \def\aliasxxx #1{\aliasyyy#1\relax} \def\aliasyyy #1=#2\relax{% {% \expandafter\let\obeyedspace=\empty \addtomacrolist{#1}% \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% }% \next } \message{cross references,} \newwrite\auxfile \newif\ifhavexrefs % True if xref values are known. \newif\ifwarnedxrefs % True if we warned once that they aren't known. % @inforef is relatively simple. \def\inforef #1{\inforefzzz #1,,,,**} \def\inforefzzz #1,#2,#3,#4**{% \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, node \samp{\ignorespaces#1{}}} % @node's only job in TeX is to define \lastnode, which is used in % cross-references. The @node line might or might not have commas, and % might or might not have spaces before the first comma, like: % @node foo , bar , ... % We don't want such trailing spaces in the node name. % \parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} % % also remove a trailing comma, in case of something like this: % @node Help-Cross, , , Cross-refs \def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} \def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} \let\nwnode=\node \let\lastnode=\empty % Write a cross-reference definition for the current node. #1 is the % type (Ynumbered, Yappendix, Ynothing). % \def\donoderef#1{% \ifx\lastnode\empty\else \setref{\lastnode}{#1}% \global\let\lastnode=\empty \fi } % @anchor{NAME} -- define xref target at arbitrary point. % \newcount\savesfregister % \def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} \def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} \def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} % \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an % anchor), which consists of three parts: % 1) NAME-title - the current sectioning name taken from \lastsection, % or the anchor name. % 2) NAME-snt - section number and type, passed as the SNT arg, or % empty for anchors. % 3) NAME-pg - the page number. % % This is called from \donoderef, \anchor, and \dofloat. In the case of % floats, there is an additional part, which is not written here: % 4) NAME-lof - the text as it should appear in a @listoffloats. % \def\setref#1#2{% \pdfmkdest{#1}% \iflinks {% \atdummies % preserve commands, but don't expand them \edef\writexrdef##1##2{% \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef ##1}{##2}}% these are parameters of \writexrdef }% \toks0 = \expandafter{\lastsection}% \immediate \writexrdef{title}{\the\toks0 }% \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout }% \fi } % @xrefautosectiontitle on|off says whether @section(ing) names are used % automatically in xrefs, if the third arg is not explicitly specified. % This was provided as a "secret" @set xref-automatic-section-title % variable, now it's official. % \parseargdef\xrefautomaticsectiontitle{% \def\temp{#1}% \ifx\temp\onword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \empty \else\ifx\temp\offword \expandafter\let\csname SETxref-automatic-section-title\endcsname = \relax \else \errhelp = \EMsimple \errmessage{Unknown @xrefautomaticsectiontitle value `\temp', must be on|off}% \fi\fi } % % @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is % the node name, #2 the name of the Info cross-reference, #3 the printed % node name, #4 the name of the Info file, #5 the name of the printed % manual. All but the node name can be omitted. % \def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} \def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} \def\ref#1{\xrefX[#1,,,,,,,]} % \newbox\toprefbox \newbox\printedrefnamebox \newbox\infofilenamebox \newbox\printedmanualbox % \def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup \unsepspaces % % Get args without leading/trailing spaces. \def\printedrefname{\ignorespaces #3}% \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}% % \def\infofilename{\ignorespaces #4}% \setbox\infofilenamebox = \hbox{\infofilename\unskip}% % \def\printedmanual{\ignorespaces #5}% \setbox\printedmanualbox = \hbox{\printedmanual\unskip}% % % If the printed reference name (arg #3) was not explicitly given in % the @xref, figure out what we want to use. \ifdim \wd\printedrefnamebox = 0pt % No printed node name was explicitly given. \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax % Not auto section-title: use node name inside the square brackets. \def\printedrefname{\ignorespaces #1}% \else % Auto section-title: use chapter/section title inside % the square brackets if we have it. \ifdim \wd\printedmanualbox > 0pt % It is in another manual, so we don't have it; use node name. \def\printedrefname{\ignorespaces #1}% \else \ifhavexrefs % We (should) know the real title if we have the xref values. \def\printedrefname{\refx{#1-title}{}}% \else % Otherwise just copy the Info node name. \def\printedrefname{\ignorespaces #1}% \fi% \fi \fi \fi % % Make link in pdf output. \ifpdf {\indexnofonts \turnoffactive \makevalueexpandable % This expands tokens, so do it after making catcode changes, so _ % etc. don't get their TeX definitions. This ignores all spaces in % #4, including (wrongly) those in the middle of the filename. \getfilename{#4}% % % This (wrongly) does not take account of leading or trailing % spaces in #1, which should be ignored. \edef\pdfxrefdest{#1}% \ifx\pdfxrefdest\empty \def\pdfxrefdest{Top}% no empty targets \else \txiescapepdf\pdfxrefdest % escape PDF special chars \fi % \leavevmode \startlink attr{/Border [0 0 0]}% \ifnum\filenamelength>0 goto file{\the\filename.pdf} name{\pdfxrefdest}% \else goto name{\pdfmkpgn{\pdfxrefdest}}% \fi }% \setcolor{\linkcolor}% \fi % % Float references are printed completely differently: "Figure 1.2" % instead of "[somenode], p.3". We distinguish them by the % LABEL-title being set to a magic string. {% % Have to otherify everything special to allow the \csname to % include an _ in the xref name, etc. \indexnofonts \turnoffactive \expandafter\global\expandafter\let\expandafter\Xthisreftitle \csname XR#1-title\endcsname }% \iffloat\Xthisreftitle % If the user specified the print name (third arg) to the ref, % print it instead of our usual "Figure 1.2". \ifdim\wd\printedrefnamebox = 0pt \refx{#1-snt}{}% \else \printedrefname \fi % % If the user also gave the printed manual name (fifth arg), append % "in MANUALNAME". \ifdim \wd\printedmanualbox > 0pt \space \putwordin{} \cite{\printedmanual}% \fi \else % node/anchor (non-float) references. % % If we use \unhbox to print the node names, TeX does not insert % empty discretionaries after hyphens, which means that it will not % find a line break at a hyphen in a node names. Since some manuals % are best written with fairly long node names, containing hyphens, % this is a loss. Therefore, we give the text of the node name % again, so it is as if TeX is seeing it for the first time. % \ifdim \wd\printedmanualbox > 0pt % Cross-manual reference with a printed manual name. % \crossmanualxref{\cite{\printedmanual\unskip}}% % \else\ifdim \wd\infofilenamebox > 0pt % Cross-manual reference with only an info filename (arg 4), no % printed manual name (arg 5). This is essentially the same as % the case above; we output the filename, since we have nothing else. % \crossmanualxref{\code{\infofilename\unskip}}% % \else % Reference within this manual. % % _ (for example) has to be the character _ for the purposes of the % control sequence corresponding to the node, but it has to expand % into the usual \leavevmode...\vrule stuff for purposes of % printing. So we \turnoffactive for the \refx-snt, back on for the % printing, back off for the \refx-pg. {\turnoffactive % Only output a following space if the -snt ref is nonempty; for % @unnumbered and @anchor, it won't be. \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi }% % output the `[mynode]' via the macro below so it can be overridden. \xrefprintnodename\printedrefname % % But we always want a comma and a space: ,\space % % output the `page 3'. \turnoffactive \putwordpage\tie\refx{#1-pg}{}% \fi\fi \fi \endlink \endgroup} % Output a cross-manual xref to #1. Used just above (twice). % % Only include the text "Section ``foo'' in" if the foo is neither % missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply % "see The Foo Manual", the idea being to refer to the whole manual. % % But, this being TeX, we can't easily compare our node name against the % string "Top" while ignoring the possible spaces before and after in % the input. By adding the arbitrary 7sp below, we make it much less % likely that a real node name would have the same width as "Top" (e.g., % in a monospaced font). Hopefully it will never happen in practice. % % For the same basic reason, we retypeset the "Top" at every % reference, since the current font is indeterminate. % \def\crossmanualxref#1{% \setbox\toprefbox = \hbox{Top\kern7sp}% \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}% \ifdim \wd2 > 7sp % nonempty? \ifdim \wd2 = \wd\toprefbox \else % same as Top? \putwordSection{} ``\printedrefname'' \putwordin{}\space \fi \fi #1% } % This macro is called from \xrefX for the `[nodename]' part of xref % output. It's a separate macro only so it can be changed more easily, % since square brackets don't work well in some documents. Particularly % one that Bob is working on :). % \def\xrefprintnodename#1{[#1]} % Things referred to by \setref. % \def\Ynothing{} \def\Yomitfromtoc{} \def\Ynumbered{% \ifnum\secno=0 \putwordChapter@tie \the\chapno \else \ifnum\subsecno=0 \putwordSection@tie \the\chapno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie \the\chapno.\the\secno.\the\subsecno \else \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } \def\Yappendix{% \ifnum\secno=0 \putwordAppendix@tie @char\the\appendixno{}% \else \ifnum\subsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno \else \ifnum\subsubsecno=0 \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno \else \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno \fi\fi\fi } % Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. % If its value is nonempty, SUFFIX is output afterward. % \def\refx#1#2{% {% \indexnofonts \otherbackslash \expandafter\global\expandafter\let\expandafter\thisrefX \csname XR#1\endcsname }% \ifx\thisrefX\relax % If not defined, say something at least. \angleleft un\-de\-fined\angleright \iflinks \ifhavexrefs {\toks0 = {#1}% avoid expansion of possibly-complex value \message{\linenumber Undefined cross reference `\the\toks0'.}}% \else \ifwarnedxrefs\else \global\warnedxrefstrue \message{Cross reference values unknown; you must run TeX again.}% \fi \fi \fi \else % It's defined, so just use it. \thisrefX \fi #2% Output the suffix in any case. } % This is the macro invoked by entries in the aux file. Usually it's % just a \def (we prepend XR to the control sequence name to avoid % collisions). But if this is a float type, we have more work to do. % \def\xrdef#1#2{% {% The node name might contain 8-bit characters, which in our current % implementation are changed to commands like @'e. Don't let these % mess up the control sequence name. \indexnofonts \turnoffactive \xdef\safexrefname{#1}% }% % \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref % % Was that xref control sequence that we just defined for a float? \expandafter\iffloat\csname XR\safexrefname\endcsname % it was a float, and we have the (safe) float type in \iffloattype. \expandafter\let\expandafter\floatlist \csname floatlist\iffloattype\endcsname % % Is this the first time we've seen this float type? \expandafter\ifx\floatlist\relax \toks0 = {\do}% yes, so just \do \else % had it before, so preserve previous elements in list. \toks0 = \expandafter{\floatlist\do}% \fi % % Remember this xref in the control sequence \floatlistFLOATTYPE, % for later use in \listoffloats. \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 {\safexrefname}}% \fi } % Read the last existing aux file, if any. No error if none exists. % \def\tryauxfile{% \openin 1 \jobname.aux \ifeof 1 \else \readdatafile{aux}% \global\havexrefstrue \fi \closein 1 } \def\setupdatafile{% \catcode`\^^@=\other \catcode`\^^A=\other \catcode`\^^B=\other \catcode`\^^C=\other \catcode`\^^D=\other \catcode`\^^E=\other \catcode`\^^F=\other \catcode`\^^G=\other \catcode`\^^H=\other \catcode`\^^K=\other \catcode`\^^L=\other \catcode`\^^N=\other \catcode`\^^P=\other \catcode`\^^Q=\other \catcode`\^^R=\other \catcode`\^^S=\other \catcode`\^^T=\other \catcode`\^^U=\other \catcode`\^^V=\other \catcode`\^^W=\other \catcode`\^^X=\other \catcode`\^^Z=\other \catcode`\^^[=\other \catcode`\^^\=\other \catcode`\^^]=\other \catcode`\^^^=\other \catcode`\^^_=\other % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. % in xref tags, i.e., node names. But since ^^e4 notation isn't % supported in the main text, it doesn't seem desirable. Furthermore, % that is not enough: for node names that actually contain a ^ % character, we would end up writing a line like this: 'xrdef {'hat % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first % argument, and \hat is not an expandable control sequence. It could % all be worked out, but why? Either we support ^^ or we don't. % % The other change necessary for this was to define \auxhat: % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter % and then to call \auxhat in \setq. % \catcode`\^=\other % % Special characters. Should be turned off anyway, but... \catcode`\~=\other \catcode`\[=\other \catcode`\]=\other \catcode`\"=\other \catcode`\_=\other \catcode`\|=\other \catcode`\<=\other \catcode`\>=\other \catcode`\$=\other \catcode`\#=\other \catcode`\&=\other \catcode`\%=\other \catcode`+=\other % avoid \+ for paranoia even though we've turned it off % % This is to support \ in node names and titles, since the \ % characters end up in a \csname. It's easier than % leaving it active and making its active definition an actual \ % character. What I don't understand is why it works in the *value* % of the xrdef. Seems like it should be a catcode12 \, and that % should not typeset properly. But it works, so I'm moving on for % now. --karl, 15jan04. \catcode`\\=\other % % Make the characters 128-255 be printing characters. {% \count1=128 \def\loop{% \catcode\count1=\other \advance\count1 by 1 \ifnum \count1<256 \loop \fi }% }% % % @ is our escape character in .aux files, and we need braces. \catcode`\{=1 \catcode`\}=2 \catcode`\@=0 } \def\readdatafile#1{% \begingroup \setupdatafile \input\jobname.#1 \endgroup} \message{insertions,} % including footnotes. \newcount \footnoteno % The trailing space in the following definition for supereject is % vital for proper filling; pages come out unaligned when you do a % pagealignmacro call if that space before the closing brace is % removed. (Generally, numeric constants should always be followed by a % space to prevent strange expansion errors.) \def\supereject{\par\penalty -20000\footnoteno =0 } % @footnotestyle is meaningful for Info output only. \let\footnotestyle=\comment {\catcode `\@=11 % % Auto-number footnotes. Otherwise like plain. \gdef\footnote{% \let\indent=\ptexindent \let\noindent=\ptexnoindent \global\advance\footnoteno by \@ne \edef\thisfootno{$^{\the\footnoteno}$}% % % In case the footnote comes at the end of a sentence, preserve the % extra spacing after we do the footnote number. \let\@sf\empty \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi % % Remove inadvertent blank space before typesetting the footnote number. \unskip \thisfootno\@sf \dofootnote }% % Don't bother with the trickery in plain.tex to not require the % footnote text as a parameter. Our footnotes don't need to be so general. % % Oh yes, they do; otherwise, @ifset (and anything else that uses % \parseargline) fails inside footnotes because the tokens are fixed when % the footnote is read. --karl, 16nov96. % \gdef\dofootnote{% \insert\footins\bgroup % We want to typeset this text as a normal paragraph, even if the % footnote reference occurs in (for example) a display environment. % So reset some parameters. \hsize=\pagewidth \interlinepenalty\interfootnotelinepenalty \splittopskip\ht\strutbox % top baseline for broken footnotes \splitmaxdepth\dp\strutbox \floatingpenalty\@MM \leftskip\z@skip \rightskip\z@skip \spaceskip\z@skip \xspaceskip\z@skip \parindent\defaultparindent % \smallfonts \rm % % Because we use hanging indentation in footnotes, a @noindent appears % to exdent this text, so make it be a no-op. makeinfo does not use % hanging indentation so @noindent can still be needed within footnote % text after an @example or the like (not that this is good style). \let\noindent = \relax % % Hang the footnote text off the number. Use \everypar in case the % footnote extends for more than one paragraph. \everypar = {\hang}% \textindent{\thisfootno}% % % Don't crash into the line above the footnote text. Since this % expands into a box, it must come within the paragraph, lest it % provide a place where TeX can split the footnote. \footstrut % % Invoke rest of plain TeX footnote routine. \futurelet\next\fo@t } }%end \catcode `\@=11 % In case a @footnote appears in a vbox, save the footnote text and create % the real \insert just after the vbox finished. Otherwise, the insertion % would be lost. % Similarly, if a @footnote appears inside an alignment, save the footnote % text to a box and make the \insert when a row of the table is finished. % And the same can be done for other insert classes. --kasal, 16nov03. % Replace the \insert primitive by a cheating macro. % Deeper inside, just make sure that the saved insertions are not spilled % out prematurely. % \def\startsavinginserts{% \ifx \insert\ptexinsert \let\insert\saveinsert \else \let\checkinserts\relax \fi } % This \insert replacement works for both \insert\footins{foo} and % \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. % \def\saveinsert#1{% \edef\next{\noexpand\savetobox \makeSAVEname#1}% \afterassignment\next % swallow the left brace \let\temp = } \def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} \def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} \def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} \def\placesaveins#1{% \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname {\box#1}% } % eat @SAVE -- beware, all of them have catcode \other: { \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) \gdef\gobblesave @SAVE{} } % initialization: \def\newsaveins #1{% \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% \next } \def\newsaveinsX #1{% \csname newbox\endcsname #1% \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts \checksaveins #1}% } % initialize: \let\checkinserts\empty \newsaveins\footins \newsaveins\margin % @image. We use the macros from epsf.tex to support this. % If epsf.tex is not installed and @image is used, we complain. % % Check for and read epsf.tex up front. If we read it only at @image % time, we might be inside a group, and then its definitions would get % undone and the next image would fail. \openin 1 = epsf.tex \ifeof 1 \else % Do not bother showing banner with epsf.tex v2.7k (available in % doc/epsf.tex and on ctan). \def\epsfannounce{\toks0 = }% \input epsf.tex \fi \closein 1 % % We will only complain once about lack of epsf.tex. \newif\ifwarnednoepsf \newhelp\noepsfhelp{epsf.tex must be installed for images to work. It is also included in the Texinfo distribution, or you can get it from ftp://tug.org/tex/epsf.tex.} % \def\image#1{% \ifx\epsfbox\thisisundefined \ifwarnednoepsf \else \errhelp = \noepsfhelp \errmessage{epsf.tex not found, images will be ignored}% \global\warnednoepsftrue \fi \else \imagexxx #1,,,,,\finish \fi } % % Arguments to @image: % #1 is (mandatory) image filename; we tack on .eps extension. % #2 is (optional) width, #3 is (optional) height. % #4 is (ignored optional) html alt text. % #5 is (ignored optional) extension. % #6 is just the usual extra ignored arg for parsing stuff. \newif\ifimagevmode \def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup \catcode`\^^M = 5 % in case we're inside an example \normalturnoffactive % allow _ et al. in names % If the image is by itself, center it. \ifvmode \imagevmodetrue \else \ifx\centersub\centerV % for @center @image, we need a vbox so we can have our vertical space \imagevmodetrue \vbox\bgroup % vbox has better behavior than vtop herev \fi\fi % \ifimagevmode \nobreak\medskip % Usually we'll have text after the image which will insert % \parskip glue, so insert it here too to equalize the space % above and below. \nobreak\vskip\parskip \nobreak \fi % % Leave vertical mode so that indentation from an enclosing % environment such as @quotation is respected. % However, if we're at the top level, we don't want the % normal paragraph indentation. % On the other hand, if we are in the case of @center @image, we don't % want to start a paragraph, which will create a hsize-width box and % eradicate the centering. \ifx\centersub\centerV\else \noindent \fi % % Output the image. \ifpdf \dopdfimage{#1}{#2}{#3}% \else % \epsfbox itself resets \epsf?size at each figure. \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi \epsfbox{#1.eps}% \fi % \ifimagevmode \medskip % space after a standalone image \fi \ifx\centersub\centerV \egroup \fi \endgroup} % @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, % etc. We don't actually implement floating yet, we always include the % float "here". But it seemed the best name for the future. % \envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} % There may be a space before second and/or third parameter; delete it. \def\eatcommaspace#1, {#1,} % #1 is the optional FLOATTYPE, the text label for this float, typically % "Figure", "Table", "Example", etc. Can't contain commas. If omitted, % this float will not be numbered and cannot be referred to. % % #2 is the optional xref label. Also must be present for the float to % be referable. % % #3 is the optional positioning argument; for now, it is ignored. It % will somehow specify the positions allowed to float to (here, top, bottom). % % We keep a separate counter for each FLOATTYPE, which we reset at each % chapter-level command. \let\resetallfloatnos=\empty % \def\dofloat#1,#2,#3,#4\finish{% \let\thiscaption=\empty \let\thisshortcaption=\empty % % don't lose footnotes inside @float. % % BEWARE: when the floats start float, we have to issue warning whenever an % insert appears inside a float which could possibly float. --kasal, 26may04 % \startsavinginserts % % We can't be used inside a paragraph. \par % \vtop\bgroup \def\floattype{#1}% \def\floatlabel{#2}% \def\floatloc{#3}% we do nothing with this yet. % \ifx\floattype\empty \let\safefloattype=\empty \else {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% \fi % % If label is given but no type, we handle that as the empty type. \ifx\floatlabel\empty \else % We want each FLOATTYPE to be numbered separately (Figure 1, % Table 1, Figure 2, ...). (And if no label, no number.) % \expandafter\getfloatno\csname\safefloattype floatno\endcsname \global\advance\floatno by 1 % {% % This magic value for \lastsection is output by \setref as the % XREFLABEL-title value. \xrefX uses it to distinguish float % labels (which have a completely different output format) from % node and anchor labels. And \xrdef uses it to construct the % lists of floats. % \edef\lastsection{\floatmagic=\safefloattype}% \setref{\floatlabel}{Yfloat}% }% \fi % % start with \parskip glue, I guess. \vskip\parskip % % Don't suppress indentation if a float happens to start a section. \restorefirstparagraphindent } % we have these possibilities: % @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap % @float Foo,lbl & no caption: Foo 1.1 % @float Foo & @caption{Cap}: Foo: Cap % @float Foo & no caption: Foo % @float ,lbl & Caption{Cap}: 1.1: Cap % @float ,lbl & no caption: 1.1 % @float & @caption{Cap}: Cap % @float & no caption: % \def\Efloat{% \let\floatident = \empty % % In all cases, if we have a float type, it comes first. \ifx\floattype\empty \else \def\floatident{\floattype}\fi % % If we have an xref label, the number comes next. \ifx\floatlabel\empty \else \ifx\floattype\empty \else % if also had float type, need tie first. \appendtomacro\floatident{\tie}% \fi % the number. \appendtomacro\floatident{\chaplevelprefix\the\floatno}% \fi % % Start the printed caption with what we've constructed in % \floatident, but keep it separate; we need \floatident again. \let\captionline = \floatident % \ifx\thiscaption\empty \else \ifx\floatident\empty \else \appendtomacro\captionline{: }% had ident, so need a colon between \fi % % caption text. \appendtomacro\captionline{\scanexp\thiscaption}% \fi % % If we have anything to print, print it, with space before. % Eventually this needs to become an \insert. \ifx\captionline\empty \else \vskip.5\parskip \captionline % % Space below caption. \vskip\parskip \fi % % If have an xref label, write the list of floats info. Do this % after the caption, to avoid chance of it being a breakpoint. \ifx\floatlabel\empty \else % Write the text that goes in the lof to the aux file as % \floatlabel-lof. Besides \floatident, we include the short % caption if specified, else the full caption if specified, else nothing. {% \atdummies % % since we read the caption text in the macro world, where ^^M % is turned into a normal character, we have to scan it back, so % we don't write the literal three characters "^^M" into the aux file. \scanexp{% \xdef\noexpand\gtemp{% \ifx\thisshortcaption\empty \thiscaption \else \thisshortcaption \fi }% }% \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident \ifx\gtemp\empty \else : \gtemp \fi}}% }% \fi \egroup % end of \vtop % % place the captured inserts % % BEWARE: when the floats start floating, we have to issue warning % whenever an insert appears inside a float which could possibly % float. --kasal, 26may04 % \checkinserts } % Append the tokens #2 to the definition of macro #1, not expanding either. % \def\appendtomacro#1#2{% \expandafter\def\expandafter#1\expandafter{#1#2}% } % @caption, @shortcaption % \def\caption{\docaption\thiscaption} \def\shortcaption{\docaption\thisshortcaption} \def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} \def\defcaption#1#2{\egroup \def#1{#2}} % The parameter is the control sequence identifying the counter we are % going to use. Create it if it doesn't exist and assign it to \floatno. \def\getfloatno#1{% \ifx#1\relax % Haven't seen this figure type before. \csname newcount\endcsname #1% % % Remember to reset this floatno at the next chap. \expandafter\gdef\expandafter\resetallfloatnos \expandafter{\resetallfloatnos #1=0 }% \fi \let\floatno#1% } % \setref calls this to get the XREFLABEL-snt value. We want an @xref % to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we % first read the @float command. % \def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% % Magic string used for the XREFLABEL-title value, so \xrefX can % distinguish floats from other xref types. \def\floatmagic{!!float!!} % #1 is the control sequence we are passed; we expand into a conditional % which is true if #1 represents a float ref. That is, the magic % \lastsection value which we \setref above. % \def\iffloat#1{\expandafter\doiffloat#1==\finish} % % #1 is (maybe) the \floatmagic string. If so, #2 will be the % (safe) float type for this float. We set \iffloattype to #2. % \def\doiffloat#1=#2=#3\finish{% \def\temp{#1}% \def\iffloattype{#2}% \ifx\temp\floatmagic } % @listoffloats FLOATTYPE - print a list of floats like a table of contents. % \parseargdef\listoffloats{% \def\floattype{#1}% floattype {% % the floattype might have accents or other special characters, % but we need to use it in a control sequence name. \indexnofonts \turnoffactive \xdef\safefloattype{\floattype}% }% % % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax \ifhavexrefs % if the user said @listoffloats foo but never @float foo. \message{\linenumber No `\safefloattype' floats to list.}% \fi \else \begingroup \leftskip=\tocindent % indent these entries like a toc \let\do=\listoffloatsdo \csname floatlist\safefloattype\endcsname \endgroup \fi } % This is called on each entry in a list of floats. We're passed the % xref label, in the form LABEL-title, which is how we save it in the % aux file. We strip off the -title and look up \XRLABEL-lof, which % has the text we're supposed to typeset here. % % Figures without xref labels will not be included in the list (since % they won't appear in the aux file). % \def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} \def\listoffloatsdoentry#1-title\finish{{% % Can't fully expand XR#1-lof because it can contain anything. Just % pass the control sequence. On the other hand, XR#1-pg is just the % page number, and we want to fully expand that so we can get a link % in pdf output. \toksA = \expandafter{\csname XR#1-lof\endcsname}% % % use the same \entry macro we use to generate the TOC and index. \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% \writeentry }} \message{localization,} % For single-language documents, @documentlanguage is usually given very % early, just after @documentencoding. Single argument is the language % (de) or locale (de_DE) abbreviation. % { \catcode`\_ = \active \globaldefs=1 \parseargdef\documentlanguage{\begingroup \let_=\normalunderscore % normal _ character for filenames \tex % read txi-??.tex file in plain TeX. % Read the file by the name they passed if it exists. \openin 1 txi-#1.tex \ifeof 1 \documentlanguagetrywithoutunderscore{#1_\finish}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 \endgroup % end raw TeX \endgroup} % % If they passed de_DE, and txi-de_DE.tex doesn't exist, % try txi-de.tex. % \gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% \openin 1 txi-#1.tex \ifeof 1 \errhelp = \nolanghelp \errmessage{Cannot read language file txi-#1.tex}% \else \globaldefs = 1 % everything in the txi-LL files needs to persist \input txi-#1.tex \fi \closein 1 } }% end of special _ catcode % \newhelp\nolanghelp{The given language definition file cannot be found or is empty. Maybe you need to install it? Putting it in the current directory should work if nowhere else does.} % This macro is called from txi-??.tex files; the first argument is the % \language name to set (without the "\lang@" prefix), the second and % third args are \{left,right}hyphenmin. % % The language names to pass are determined when the format is built. % See the etex.log file created at that time, e.g., % /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. % % With TeX Live 2008, etex now includes hyphenation patterns for all % available languages. This means we can support hyphenation in % Texinfo, at least to some extent. (This still doesn't solve the % accented characters problem.) % \catcode`@=11 \def\txisetlanguage#1#2#3{% % do not set the language if the name is undefined in the current TeX. \expandafter\ifx\csname lang@#1\endcsname \relax \message{no patterns for #1}% \else \global\language = \csname lang@#1\endcsname \fi % but there is no harm in adjusting the hyphenmin values regardless. \global\lefthyphenmin = #2\relax \global\righthyphenmin = #3\relax } % Helpers for encodings. % Set the catcode of characters 128 through 255 to the specified number. % \def\setnonasciicharscatcode#1{% \count255=128 \loop\ifnum\count255<256 \global\catcode\count255=#1\relax \advance\count255 by 1 \repeat } \def\setnonasciicharscatcodenonglobal#1{% \count255=128 \loop\ifnum\count255<256 \catcode\count255=#1\relax \advance\count255 by 1 \repeat } % @documentencoding sets the definition of non-ASCII characters % according to the specified encoding. % \parseargdef\documentencoding{% % Encoding being declared for the document. \def\declaredencoding{\csname #1.enc\endcsname}% % % Supported encodings: names converted to tokens in order to be able % to compare them with \ifx. \def\ascii{\csname US-ASCII.enc\endcsname}% \def\latnine{\csname ISO-8859-15.enc\endcsname}% \def\latone{\csname ISO-8859-1.enc\endcsname}% \def\lattwo{\csname ISO-8859-2.enc\endcsname}% \def\utfeight{\csname UTF-8.enc\endcsname}% % \ifx \declaredencoding \ascii \asciichardefs % \else \ifx \declaredencoding \lattwo \setnonasciicharscatcode\active \lattwochardefs % \else \ifx \declaredencoding \latone \setnonasciicharscatcode\active \latonechardefs % \else \ifx \declaredencoding \latnine \setnonasciicharscatcode\active \latninechardefs % \else \ifx \declaredencoding \utfeight \setnonasciicharscatcode\active \utfeightchardefs % \else \message{Unknown document encoding #1, ignoring.}% % \fi % utfeight \fi % latnine \fi % latone \fi % lattwo \fi % ascii } % A message to be logged when using a character that isn't available % the default font encoding (OT1). % \def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} % Take account of \c (plain) vs. \, (Texinfo) difference. \def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} % First, make active non-ASCII characters in order for them to be % correctly categorized when TeX reads the replacement text of % macros containing the character definitions. \setnonasciicharscatcode\active % % Latin1 (ISO-8859-1) character definitions. \def\latonechardefs{% \gdef^^a0{\tie} \gdef^^a1{\exclamdown} \gdef^^a2{\missingcharmsg{CENT SIGN}} \gdef^^a3{{\pounds}} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\missingcharmsg{YEN SIGN}} \gdef^^a6{\missingcharmsg{BROKEN BAR}} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\copyright} \gdef^^aa{\ordf} \gdef^^ab{\guillemetleft} \gdef^^ac{$\lnot$} \gdef^^ad{\-} \gdef^^ae{\registeredsymbol} \gdef^^af{\={}} % \gdef^^b0{\textdegree} \gdef^^b1{$\pm$} \gdef^^b2{$^2$} \gdef^^b3{$^3$} \gdef^^b4{\'{}} \gdef^^b5{$\mu$} \gdef^^b6{\P} % \gdef^^b7{$^.$} \gdef^^b8{\cedilla\ } \gdef^^b9{$^1$} \gdef^^ba{\ordm} % \gdef^^bb{\guillemetright} \gdef^^bc{$1\over4$} \gdef^^bd{$1\over2$} \gdef^^be{$3\over4$} \gdef^^bf{\questiondown} % \gdef^^c0{\`A} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\~A} \gdef^^c4{\"A} \gdef^^c5{\ringaccent A} \gdef^^c6{\AE} \gdef^^c7{\cedilla C} \gdef^^c8{\`E} \gdef^^c9{\'E} \gdef^^ca{\^E} \gdef^^cb{\"E} \gdef^^cc{\`I} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\"I} % \gdef^^d0{\DH} \gdef^^d1{\~N} \gdef^^d2{\`O} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\~O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\O} \gdef^^d9{\`U} \gdef^^da{\'U} \gdef^^db{\^U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\TH} \gdef^^df{\ss} % \gdef^^e0{\`a} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\~a} \gdef^^e4{\"a} \gdef^^e5{\ringaccent a} \gdef^^e6{\ae} \gdef^^e7{\cedilla c} \gdef^^e8{\`e} \gdef^^e9{\'e} \gdef^^ea{\^e} \gdef^^eb{\"e} \gdef^^ec{\`{\dotless i}} \gdef^^ed{\'{\dotless i}} \gdef^^ee{\^{\dotless i}} \gdef^^ef{\"{\dotless i}} % \gdef^^f0{\dh} \gdef^^f1{\~n} \gdef^^f2{\`o} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\~o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\o} \gdef^^f9{\`u} \gdef^^fa{\'u} \gdef^^fb{\^u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\th} \gdef^^ff{\"y} } % Latin9 (ISO-8859-15) encoding character definitions. \def\latninechardefs{% % Encoding is almost identical to Latin1. \latonechardefs % \gdef^^a4{\euro} \gdef^^a6{\v S} \gdef^^a8{\v s} \gdef^^b4{\v Z} \gdef^^b8{\v z} \gdef^^bc{\OE} \gdef^^bd{\oe} \gdef^^be{\"Y} } % Latin2 (ISO-8859-2) character definitions. \def\lattwochardefs{% \gdef^^a0{\tie} \gdef^^a1{\ogonek{A}} \gdef^^a2{\u{}} \gdef^^a3{\L} \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} \gdef^^a5{\v L} \gdef^^a6{\'S} \gdef^^a7{\S} \gdef^^a8{\"{}} \gdef^^a9{\v S} \gdef^^aa{\cedilla S} \gdef^^ab{\v T} \gdef^^ac{\'Z} \gdef^^ad{\-} \gdef^^ae{\v Z} \gdef^^af{\dotaccent Z} % \gdef^^b0{\textdegree} \gdef^^b1{\ogonek{a}} \gdef^^b2{\ogonek{ }} \gdef^^b3{\l} \gdef^^b4{\'{}} \gdef^^b5{\v l} \gdef^^b6{\'s} \gdef^^b7{\v{}} \gdef^^b8{\cedilla\ } \gdef^^b9{\v s} \gdef^^ba{\cedilla s} \gdef^^bb{\v t} \gdef^^bc{\'z} \gdef^^bd{\H{}} \gdef^^be{\v z} \gdef^^bf{\dotaccent z} % \gdef^^c0{\'R} \gdef^^c1{\'A} \gdef^^c2{\^A} \gdef^^c3{\u A} \gdef^^c4{\"A} \gdef^^c5{\'L} \gdef^^c6{\'C} \gdef^^c7{\cedilla C} \gdef^^c8{\v C} \gdef^^c9{\'E} \gdef^^ca{\ogonek{E}} \gdef^^cb{\"E} \gdef^^cc{\v E} \gdef^^cd{\'I} \gdef^^ce{\^I} \gdef^^cf{\v D} % \gdef^^d0{\DH} \gdef^^d1{\'N} \gdef^^d2{\v N} \gdef^^d3{\'O} \gdef^^d4{\^O} \gdef^^d5{\H O} \gdef^^d6{\"O} \gdef^^d7{$\times$} \gdef^^d8{\v R} \gdef^^d9{\ringaccent U} \gdef^^da{\'U} \gdef^^db{\H U} \gdef^^dc{\"U} \gdef^^dd{\'Y} \gdef^^de{\cedilla T} \gdef^^df{\ss} % \gdef^^e0{\'r} \gdef^^e1{\'a} \gdef^^e2{\^a} \gdef^^e3{\u a} \gdef^^e4{\"a} \gdef^^e5{\'l} \gdef^^e6{\'c} \gdef^^e7{\cedilla c} \gdef^^e8{\v c} \gdef^^e9{\'e} \gdef^^ea{\ogonek{e}} \gdef^^eb{\"e} \gdef^^ec{\v e} \gdef^^ed{\'{\dotless{i}}} \gdef^^ee{\^{\dotless{i}}} \gdef^^ef{\v d} % \gdef^^f0{\dh} \gdef^^f1{\'n} \gdef^^f2{\v n} \gdef^^f3{\'o} \gdef^^f4{\^o} \gdef^^f5{\H o} \gdef^^f6{\"o} \gdef^^f7{$\div$} \gdef^^f8{\v r} \gdef^^f9{\ringaccent u} \gdef^^fa{\'u} \gdef^^fb{\H u} \gdef^^fc{\"u} \gdef^^fd{\'y} \gdef^^fe{\cedilla t} \gdef^^ff{\dotaccent{}} } % UTF-8 character definitions. % % This code to support UTF-8 is based on LaTeX's utf8.def, with some % changes for Texinfo conventions. It is included here under the GPL by % permission from Frank Mittelbach and the LaTeX team. % \newcount\countUTFx \newcount\countUTFy \newcount\countUTFz \gdef\UTFviiiTwoOctets#1#2{\expandafter \UTFviiiDefined\csname u8:#1\string #2\endcsname} % \gdef\UTFviiiThreeOctets#1#2#3{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} % \gdef\UTFviiiFourOctets#1#2#3#4{\expandafter \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} \gdef\UTFviiiDefined#1{% \ifx #1\relax \message{\linenumber Unicode char \string #1 not defined for Texinfo}% \else \expandafter #1% \fi } \begingroup \catcode`\~13 \catcode`\"12 \def\UTFviiiLoop{% \global\catcode\countUTFx\active \uccode`\~\countUTFx \uppercase\expandafter{\UTFviiiTmp}% \advance\countUTFx by 1 \ifnum\countUTFx < \countUTFy \expandafter\UTFviiiLoop \fi} \countUTFx = "C2 \countUTFy = "E0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiTwoOctets\string~}} \UTFviiiLoop \countUTFx = "E0 \countUTFy = "F0 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiThreeOctets\string~}} \UTFviiiLoop \countUTFx = "F0 \countUTFy = "F4 \def\UTFviiiTmp{% \xdef~{\noexpand\UTFviiiFourOctets\string~}} \UTFviiiLoop \endgroup \begingroup \catcode`\"=12 \catcode`\<=12 \catcode`\.=12 \catcode`\,=12 \catcode`\;=12 \catcode`\!=12 \catcode`\~=13 \gdef\DeclareUnicodeCharacter#1#2{% \countUTFz = "#1\relax %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% \begingroup \parseXMLCharref \def\UTFviiiTwoOctets##1##2{% \csname u8:##1\string ##2\endcsname}% \def\UTFviiiThreeOctets##1##2##3{% \csname u8:##1\string ##2\string ##3\endcsname}% \def\UTFviiiFourOctets##1##2##3##4{% \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% \expandafter\expandafter\expandafter\expandafter \expandafter\expandafter\expandafter \gdef\UTFviiiTmp{#2}% \endgroup} \gdef\parseXMLCharref{% \ifnum\countUTFz < "A0\relax \errhelp = \EMsimple \errmessage{Cannot define Unicode char value < 00A0}% \else\ifnum\countUTFz < "800\relax \parseUTFviiiA,% \parseUTFviiiB C\UTFviiiTwoOctets.,% \else\ifnum\countUTFz < "10000\relax \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% \else \parseUTFviiiA;% \parseUTFviiiA,% \parseUTFviiiA!% \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% \fi\fi\fi } \gdef\parseUTFviiiA#1{% \countUTFx = \countUTFz \divide\countUTFz by 64 \countUTFy = \countUTFz \multiply\countUTFz by 64 \advance\countUTFx by -\countUTFz \advance\countUTFx by 128 \uccode `#1\countUTFx \countUTFz = \countUTFy} \gdef\parseUTFviiiB#1#2#3#4{% \advance\countUTFz by "#10\relax \uccode `#3\countUTFz \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} \endgroup \def\utfeightchardefs{% \DeclareUnicodeCharacter{00A0}{\tie} \DeclareUnicodeCharacter{00A1}{\exclamdown} \DeclareUnicodeCharacter{00A3}{\pounds} \DeclareUnicodeCharacter{00A8}{\"{ }} \DeclareUnicodeCharacter{00A9}{\copyright} \DeclareUnicodeCharacter{00AA}{\ordf} \DeclareUnicodeCharacter{00AB}{\guillemetleft} \DeclareUnicodeCharacter{00AD}{\-} \DeclareUnicodeCharacter{00AE}{\registeredsymbol} \DeclareUnicodeCharacter{00AF}{\={ }} \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} \DeclareUnicodeCharacter{00B4}{\'{ }} \DeclareUnicodeCharacter{00B8}{\cedilla{ }} \DeclareUnicodeCharacter{00BA}{\ordm} \DeclareUnicodeCharacter{00BB}{\guillemetright} \DeclareUnicodeCharacter{00BF}{\questiondown} \DeclareUnicodeCharacter{00C0}{\`A} \DeclareUnicodeCharacter{00C1}{\'A} \DeclareUnicodeCharacter{00C2}{\^A} \DeclareUnicodeCharacter{00C3}{\~A} \DeclareUnicodeCharacter{00C4}{\"A} \DeclareUnicodeCharacter{00C5}{\AA} \DeclareUnicodeCharacter{00C6}{\AE} \DeclareUnicodeCharacter{00C7}{\cedilla{C}} \DeclareUnicodeCharacter{00C8}{\`E} \DeclareUnicodeCharacter{00C9}{\'E} \DeclareUnicodeCharacter{00CA}{\^E} \DeclareUnicodeCharacter{00CB}{\"E} \DeclareUnicodeCharacter{00CC}{\`I} \DeclareUnicodeCharacter{00CD}{\'I} \DeclareUnicodeCharacter{00CE}{\^I} \DeclareUnicodeCharacter{00CF}{\"I} \DeclareUnicodeCharacter{00D0}{\DH} \DeclareUnicodeCharacter{00D1}{\~N} \DeclareUnicodeCharacter{00D2}{\`O} \DeclareUnicodeCharacter{00D3}{\'O} \DeclareUnicodeCharacter{00D4}{\^O} \DeclareUnicodeCharacter{00D5}{\~O} \DeclareUnicodeCharacter{00D6}{\"O} \DeclareUnicodeCharacter{00D8}{\O} \DeclareUnicodeCharacter{00D9}{\`U} \DeclareUnicodeCharacter{00DA}{\'U} \DeclareUnicodeCharacter{00DB}{\^U} \DeclareUnicodeCharacter{00DC}{\"U} \DeclareUnicodeCharacter{00DD}{\'Y} \DeclareUnicodeCharacter{00DE}{\TH} \DeclareUnicodeCharacter{00DF}{\ss} \DeclareUnicodeCharacter{00E0}{\`a} \DeclareUnicodeCharacter{00E1}{\'a} \DeclareUnicodeCharacter{00E2}{\^a} \DeclareUnicodeCharacter{00E3}{\~a} \DeclareUnicodeCharacter{00E4}{\"a} \DeclareUnicodeCharacter{00E5}{\aa} \DeclareUnicodeCharacter{00E6}{\ae} \DeclareUnicodeCharacter{00E7}{\cedilla{c}} \DeclareUnicodeCharacter{00E8}{\`e} \DeclareUnicodeCharacter{00E9}{\'e} \DeclareUnicodeCharacter{00EA}{\^e} \DeclareUnicodeCharacter{00EB}{\"e} \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} \DeclareUnicodeCharacter{00F0}{\dh} \DeclareUnicodeCharacter{00F1}{\~n} \DeclareUnicodeCharacter{00F2}{\`o} \DeclareUnicodeCharacter{00F3}{\'o} \DeclareUnicodeCharacter{00F4}{\^o} \DeclareUnicodeCharacter{00F5}{\~o} \DeclareUnicodeCharacter{00F6}{\"o} \DeclareUnicodeCharacter{00F8}{\o} \DeclareUnicodeCharacter{00F9}{\`u} \DeclareUnicodeCharacter{00FA}{\'u} \DeclareUnicodeCharacter{00FB}{\^u} \DeclareUnicodeCharacter{00FC}{\"u} \DeclareUnicodeCharacter{00FD}{\'y} \DeclareUnicodeCharacter{00FE}{\th} \DeclareUnicodeCharacter{00FF}{\"y} \DeclareUnicodeCharacter{0100}{\=A} \DeclareUnicodeCharacter{0101}{\=a} \DeclareUnicodeCharacter{0102}{\u{A}} \DeclareUnicodeCharacter{0103}{\u{a}} \DeclareUnicodeCharacter{0104}{\ogonek{A}} \DeclareUnicodeCharacter{0105}{\ogonek{a}} \DeclareUnicodeCharacter{0106}{\'C} \DeclareUnicodeCharacter{0107}{\'c} \DeclareUnicodeCharacter{0108}{\^C} \DeclareUnicodeCharacter{0109}{\^c} \DeclareUnicodeCharacter{0118}{\ogonek{E}} \DeclareUnicodeCharacter{0119}{\ogonek{e}} \DeclareUnicodeCharacter{010A}{\dotaccent{C}} \DeclareUnicodeCharacter{010B}{\dotaccent{c}} \DeclareUnicodeCharacter{010C}{\v{C}} \DeclareUnicodeCharacter{010D}{\v{c}} \DeclareUnicodeCharacter{010E}{\v{D}} \DeclareUnicodeCharacter{0112}{\=E} \DeclareUnicodeCharacter{0113}{\=e} \DeclareUnicodeCharacter{0114}{\u{E}} \DeclareUnicodeCharacter{0115}{\u{e}} \DeclareUnicodeCharacter{0116}{\dotaccent{E}} \DeclareUnicodeCharacter{0117}{\dotaccent{e}} \DeclareUnicodeCharacter{011A}{\v{E}} \DeclareUnicodeCharacter{011B}{\v{e}} \DeclareUnicodeCharacter{011C}{\^G} \DeclareUnicodeCharacter{011D}{\^g} \DeclareUnicodeCharacter{011E}{\u{G}} \DeclareUnicodeCharacter{011F}{\u{g}} \DeclareUnicodeCharacter{0120}{\dotaccent{G}} \DeclareUnicodeCharacter{0121}{\dotaccent{g}} \DeclareUnicodeCharacter{0124}{\^H} \DeclareUnicodeCharacter{0125}{\^h} \DeclareUnicodeCharacter{0128}{\~I} \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} \DeclareUnicodeCharacter{012A}{\=I} \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} \DeclareUnicodeCharacter{012C}{\u{I}} \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} \DeclareUnicodeCharacter{0130}{\dotaccent{I}} \DeclareUnicodeCharacter{0131}{\dotless{i}} \DeclareUnicodeCharacter{0132}{IJ} \DeclareUnicodeCharacter{0133}{ij} \DeclareUnicodeCharacter{0134}{\^J} \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} \DeclareUnicodeCharacter{0139}{\'L} \DeclareUnicodeCharacter{013A}{\'l} \DeclareUnicodeCharacter{0141}{\L} \DeclareUnicodeCharacter{0142}{\l} \DeclareUnicodeCharacter{0143}{\'N} \DeclareUnicodeCharacter{0144}{\'n} \DeclareUnicodeCharacter{0147}{\v{N}} \DeclareUnicodeCharacter{0148}{\v{n}} \DeclareUnicodeCharacter{014C}{\=O} \DeclareUnicodeCharacter{014D}{\=o} \DeclareUnicodeCharacter{014E}{\u{O}} \DeclareUnicodeCharacter{014F}{\u{o}} \DeclareUnicodeCharacter{0150}{\H{O}} \DeclareUnicodeCharacter{0151}{\H{o}} \DeclareUnicodeCharacter{0152}{\OE} \DeclareUnicodeCharacter{0153}{\oe} \DeclareUnicodeCharacter{0154}{\'R} \DeclareUnicodeCharacter{0155}{\'r} \DeclareUnicodeCharacter{0158}{\v{R}} \DeclareUnicodeCharacter{0159}{\v{r}} \DeclareUnicodeCharacter{015A}{\'S} \DeclareUnicodeCharacter{015B}{\'s} \DeclareUnicodeCharacter{015C}{\^S} \DeclareUnicodeCharacter{015D}{\^s} \DeclareUnicodeCharacter{015E}{\cedilla{S}} \DeclareUnicodeCharacter{015F}{\cedilla{s}} \DeclareUnicodeCharacter{0160}{\v{S}} \DeclareUnicodeCharacter{0161}{\v{s}} \DeclareUnicodeCharacter{0162}{\cedilla{t}} \DeclareUnicodeCharacter{0163}{\cedilla{T}} \DeclareUnicodeCharacter{0164}{\v{T}} \DeclareUnicodeCharacter{0168}{\~U} \DeclareUnicodeCharacter{0169}{\~u} \DeclareUnicodeCharacter{016A}{\=U} \DeclareUnicodeCharacter{016B}{\=u} \DeclareUnicodeCharacter{016C}{\u{U}} \DeclareUnicodeCharacter{016D}{\u{u}} \DeclareUnicodeCharacter{016E}{\ringaccent{U}} \DeclareUnicodeCharacter{016F}{\ringaccent{u}} \DeclareUnicodeCharacter{0170}{\H{U}} \DeclareUnicodeCharacter{0171}{\H{u}} \DeclareUnicodeCharacter{0174}{\^W} \DeclareUnicodeCharacter{0175}{\^w} \DeclareUnicodeCharacter{0176}{\^Y} \DeclareUnicodeCharacter{0177}{\^y} \DeclareUnicodeCharacter{0178}{\"Y} \DeclareUnicodeCharacter{0179}{\'Z} \DeclareUnicodeCharacter{017A}{\'z} \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} \DeclareUnicodeCharacter{017C}{\dotaccent{z}} \DeclareUnicodeCharacter{017D}{\v{Z}} \DeclareUnicodeCharacter{017E}{\v{z}} \DeclareUnicodeCharacter{01C4}{D\v{Z}} \DeclareUnicodeCharacter{01C5}{D\v{z}} \DeclareUnicodeCharacter{01C6}{d\v{z}} \DeclareUnicodeCharacter{01C7}{LJ} \DeclareUnicodeCharacter{01C8}{Lj} \DeclareUnicodeCharacter{01C9}{lj} \DeclareUnicodeCharacter{01CA}{NJ} \DeclareUnicodeCharacter{01CB}{Nj} \DeclareUnicodeCharacter{01CC}{nj} \DeclareUnicodeCharacter{01CD}{\v{A}} \DeclareUnicodeCharacter{01CE}{\v{a}} \DeclareUnicodeCharacter{01CF}{\v{I}} \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} \DeclareUnicodeCharacter{01D1}{\v{O}} \DeclareUnicodeCharacter{01D2}{\v{o}} \DeclareUnicodeCharacter{01D3}{\v{U}} \DeclareUnicodeCharacter{01D4}{\v{u}} \DeclareUnicodeCharacter{01E2}{\={\AE}} \DeclareUnicodeCharacter{01E3}{\={\ae}} \DeclareUnicodeCharacter{01E6}{\v{G}} \DeclareUnicodeCharacter{01E7}{\v{g}} \DeclareUnicodeCharacter{01E8}{\v{K}} \DeclareUnicodeCharacter{01E9}{\v{k}} \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} \DeclareUnicodeCharacter{01F1}{DZ} \DeclareUnicodeCharacter{01F2}{Dz} \DeclareUnicodeCharacter{01F3}{dz} \DeclareUnicodeCharacter{01F4}{\'G} \DeclareUnicodeCharacter{01F5}{\'g} \DeclareUnicodeCharacter{01F8}{\`N} \DeclareUnicodeCharacter{01F9}{\`n} \DeclareUnicodeCharacter{01FC}{\'{\AE}} \DeclareUnicodeCharacter{01FD}{\'{\ae}} \DeclareUnicodeCharacter{01FE}{\'{\O}} \DeclareUnicodeCharacter{01FF}{\'{\o}} \DeclareUnicodeCharacter{021E}{\v{H}} \DeclareUnicodeCharacter{021F}{\v{h}} \DeclareUnicodeCharacter{0226}{\dotaccent{A}} \DeclareUnicodeCharacter{0227}{\dotaccent{a}} \DeclareUnicodeCharacter{0228}{\cedilla{E}} \DeclareUnicodeCharacter{0229}{\cedilla{e}} \DeclareUnicodeCharacter{022E}{\dotaccent{O}} \DeclareUnicodeCharacter{022F}{\dotaccent{o}} \DeclareUnicodeCharacter{0232}{\=Y} \DeclareUnicodeCharacter{0233}{\=y} \DeclareUnicodeCharacter{0237}{\dotless{j}} \DeclareUnicodeCharacter{02DB}{\ogonek{ }} \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} \DeclareUnicodeCharacter{1E20}{\=G} \DeclareUnicodeCharacter{1E21}{\=g} \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} \DeclareUnicodeCharacter{1E26}{\"H} \DeclareUnicodeCharacter{1E27}{\"h} \DeclareUnicodeCharacter{1E30}{\'K} \DeclareUnicodeCharacter{1E31}{\'k} \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} \DeclareUnicodeCharacter{1E3E}{\'M} \DeclareUnicodeCharacter{1E3F}{\'m} \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} \DeclareUnicodeCharacter{1E54}{\'P} \DeclareUnicodeCharacter{1E55}{\'p} \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} \DeclareUnicodeCharacter{1E7C}{\~V} \DeclareUnicodeCharacter{1E7D}{\~v} \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} \DeclareUnicodeCharacter{1E80}{\`W} \DeclareUnicodeCharacter{1E81}{\`w} \DeclareUnicodeCharacter{1E82}{\'W} \DeclareUnicodeCharacter{1E83}{\'w} \DeclareUnicodeCharacter{1E84}{\"W} \DeclareUnicodeCharacter{1E85}{\"w} \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} \DeclareUnicodeCharacter{1E8C}{\"X} \DeclareUnicodeCharacter{1E8D}{\"x} \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} \DeclareUnicodeCharacter{1E90}{\^Z} \DeclareUnicodeCharacter{1E91}{\^z} \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} \DeclareUnicodeCharacter{1E97}{\"t} \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} \DeclareUnicodeCharacter{1EBC}{\~E} \DeclareUnicodeCharacter{1EBD}{\~e} \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} \DeclareUnicodeCharacter{1EF2}{\`Y} \DeclareUnicodeCharacter{1EF3}{\`y} \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} \DeclareUnicodeCharacter{1EF8}{\~Y} \DeclareUnicodeCharacter{1EF9}{\~y} \DeclareUnicodeCharacter{2013}{--} \DeclareUnicodeCharacter{2014}{---} \DeclareUnicodeCharacter{2018}{\quoteleft} \DeclareUnicodeCharacter{2019}{\quoteright} \DeclareUnicodeCharacter{201A}{\quotesinglbase} \DeclareUnicodeCharacter{201C}{\quotedblleft} \DeclareUnicodeCharacter{201D}{\quotedblright} \DeclareUnicodeCharacter{201E}{\quotedblbase} \DeclareUnicodeCharacter{2022}{\bullet} \DeclareUnicodeCharacter{2026}{\dots} \DeclareUnicodeCharacter{2039}{\guilsinglleft} \DeclareUnicodeCharacter{203A}{\guilsinglright} \DeclareUnicodeCharacter{20AC}{\euro} \DeclareUnicodeCharacter{2192}{\expansion} \DeclareUnicodeCharacter{21D2}{\result} \DeclareUnicodeCharacter{2212}{\minus} \DeclareUnicodeCharacter{2217}{\point} \DeclareUnicodeCharacter{2261}{\equiv} }% end of \utfeightchardefs % US-ASCII character definitions. \def\asciichardefs{% nothing need be done \relax } % Make non-ASCII characters printable again for compatibility with % existing Texinfo documents that may use them, even without declaring a % document encoding. % \setnonasciicharscatcode \other \message{formatting,} \newdimen\defaultparindent \defaultparindent = 15pt \chapheadingskip = 15pt plus 4pt minus 2pt \secheadingskip = 12pt plus 3pt minus 2pt \subsecheadingskip = 9pt plus 2pt minus 2pt % Prevent underfull vbox error messages. \vbadness = 10000 % Don't be very finicky about underfull hboxes, either. \hbadness = 6666 % Following George Bush, get rid of widows and orphans. \widowpenalty=10000 \clubpenalty=10000 % Use TeX 3.0's \emergencystretch to help line breaking, but if we're % using an old version of TeX, don't do anything. We want the amount of % stretch added to depend on the line length, hence the dependence on % \hsize. We call this whenever the paper size is set. % \def\setemergencystretch{% \ifx\emergencystretch\thisisundefined % Allow us to assign to \emergencystretch anyway. \def\emergencystretch{\dimen0}% \else \emergencystretch = .15\hsize \fi } % Parameters in order: 1) textheight; 2) textwidth; % 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; % 7) physical page height; 8) physical page width. % % We also call \setleading{\textleading}, so the caller should define % \textleading. The caller should also set \parskip. % \def\internalpagesizes#1#2#3#4#5#6#7#8{% \voffset = #3\relax \topskip = #6\relax \splittopskip = \topskip % \vsize = #1\relax \advance\vsize by \topskip \outervsize = \vsize \advance\outervsize by 2\topandbottommargin \pageheight = \vsize % \hsize = #2\relax \outerhsize = \hsize \advance\outerhsize by 0.5in \pagewidth = \hsize % \normaloffset = #4\relax \bindingoffset = #5\relax % \ifpdf \pdfpageheight #7\relax \pdfpagewidth #8\relax % if we don't reset these, they will remain at "1 true in" of % whatever layout pdftex was dumped with. \pdfhorigin = 1 true in \pdfvorigin = 1 true in \fi % \setleading{\textleading} % \parindent = \defaultparindent \setemergencystretch } % @letterpaper (the default). \def\letterpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % If page is nothing but text, make it come out even. \internalpagesizes{607.2pt}{6in}% that's 46 lines {\voffset}{.25in}% {\bindingoffset}{36pt}% {11in}{8.5in}% }} % Use @smallbook to reset parameters for 7x9.25 trim size. \def\smallbook{{\globaldefs = 1 \parskip = 2pt plus 1pt \textleading = 12pt % \internalpagesizes{7.5in}{5in}% {-.2in}{0in}% {\bindingoffset}{16pt}% {9.25in}{7in}% % \lispnarrowing = 0.3in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .5cm }} % Use @smallerbook to reset parameters for 6x9 trim size. % (Just testing, parameters still in flux.) \def\smallerbook{{\globaldefs = 1 \parskip = 1.5pt plus 1pt \textleading = 12pt % \internalpagesizes{7.4in}{4.8in}% {-.2in}{-.4in}% {0pt}{14pt}% {9in}{6in}% % \lispnarrowing = 0.25in \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = .4cm }} % Use @afourpaper to print on European A4 paper. \def\afourpaper{{\globaldefs = 1 \parskip = 3pt plus 2pt minus 1pt \textleading = 13.2pt % % Double-side printing via postscript on Laserjet 4050 % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. % To change the settings for a different printer or situation, adjust % \normaloffset until the front-side and back-side texts align. Then % do the same for \bindingoffset. You can set these for testing in % your texinfo source file like this: % @tex % \global\normaloffset = -6mm % \global\bindingoffset = 10mm % @end tex \internalpagesizes{673.2pt}{160mm}% that's 51 lines {\voffset}{\hoffset}% {\bindingoffset}{44pt}% {297mm}{210mm}% % \tolerance = 700 \hfuzz = 1pt \contentsrightmargin = 0pt \defbodyindent = 5mm }} % Use @afivepaper to print on European A5 paper. % From romildo@urano.iceb.ufop.br, 2 July 2000. % He also recommends making @example and @lisp be small. \def\afivepaper{{\globaldefs = 1 \parskip = 2pt plus 1pt minus 0.1pt \textleading = 12.5pt % \internalpagesizes{160mm}{120mm}% {\voffset}{\hoffset}% {\bindingoffset}{8pt}% {210mm}{148mm}% % \lispnarrowing = 0.2in \tolerance = 800 \hfuzz = 1.2pt \contentsrightmargin = 0pt \defbodyindent = 2mm \tableindent = 12mm }} % A specific text layout, 24x15cm overall, intended for A4 paper. \def\afourlatex{{\globaldefs = 1 \afourpaper \internalpagesizes{237mm}{150mm}% {\voffset}{4.6mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% % % Must explicitly reset to 0 because we call \afourpaper. \globaldefs = 0 }} % Use @afourwide to print on A4 paper in landscape format. \def\afourwide{{\globaldefs = 1 \afourpaper \internalpagesizes{241mm}{165mm}% {\voffset}{-2.95mm}% {\bindingoffset}{7mm}% {297mm}{210mm}% \globaldefs = 0 }} % @pagesizes TEXTHEIGHT[,TEXTWIDTH] % Perhaps we should allow setting the margins, \topskip, \parskip, % and/or leading, also. Or perhaps we should compute them somehow. % \parseargdef\pagesizes{\pagesizesyyy #1,,\finish} \def\pagesizesyyy#1,#2,#3\finish{{% \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi \globaldefs = 1 % \parskip = 3pt plus 2pt minus 1pt \setleading{\textleading}% % \dimen0 = #1\relax \advance\dimen0 by \voffset % \dimen2 = \hsize \advance\dimen2 by \normaloffset % \internalpagesizes{#1}{\hsize}% {\voffset}{\normaloffset}% {\bindingoffset}{44pt}% {\dimen0}{\dimen2}% }} % Set default to letter. % \letterpaper \message{and turning on texinfo input format.} \def^^L{\par} % remove \outer, so ^L can appear in an @comment % DEL is a comment character, in case @c does not suffice. \catcode`\^^? = 14 % Define macros to output various characters with catcode for normal text. \catcode`\"=\other \def\normaldoublequote{"} \catcode`\$=\other \def\normaldollar{$}%$ font-lock fix \catcode`\+=\other \def\normalplus{+} \catcode`\<=\other \def\normalless{<} \catcode`\>=\other \def\normalgreater{>} \catcode`\^=\other \def\normalcaret{^} \catcode`\_=\other \def\normalunderscore{_} \catcode`\|=\other \def\normalverticalbar{|} \catcode`\~=\other \def\normaltilde{~} % This macro is used to make a character print one way in \tt % (where it can probably be output as-is), and another way in other fonts, % where something hairier probably needs to be done. % % #1 is what to print if we are indeed using \tt; #2 is what to print % otherwise. Since all the Computer Modern typewriter fonts have zero % interword stretch (and shrink), and it is reasonable to expect all % typewriter fonts to have this, we can check that font parameter. % \def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} % Same as above, but check for italic font. Actually this also catches % non-italic slanted fonts since it is impossible to distinguish them from % italic fonts. But since this is only used by $ and it uses \sl anyway % this is not a problem. \def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} % Turn off all special characters except @ % (and those which the user can use as if they were ordinary). % Most of these we simply print from the \tt font, but for some, we can % use math or other variants that look better in normal text. \catcode`\"=\active \def\activedoublequote{{\tt\char34}} \let"=\activedoublequote \catcode`\~=\active \def~{{\tt\char126}} \chardef\hat=`\^ \catcode`\^=\active \def^{{\tt \hat}} \catcode`\_=\active \def_{\ifusingtt\normalunderscore\_} \let\realunder=_ % Subroutine for the previous macro. \def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } \catcode`\|=\active \def|{{\tt\char124}} \chardef \less=`\< \catcode`\<=\active \def<{{\tt \less}} \chardef \gtr=`\> \catcode`\>=\active \def>{{\tt \gtr}} \catcode`\+=\active \def+{{\tt \char 43}} \catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix % If a .fmt file is being used, characters that might appear in a file % name cannot be active until we have parsed the command line. % So turn them off again, and have \everyjob (or @setfilename) turn them on. % \otherifyactive is called near the end of this file. \def\otherifyactive{\catcode`+=\other \catcode`\_=\other} % Used sometimes to turn off (effectively) the active characters even after % parsing them. \def\turnoffactive{% \normalturnoffactive \otherbackslash } \catcode`\@=0 % \backslashcurfont outputs one backslash character in current font, % as in \char`\\. \global\chardef\backslashcurfont=`\\ \global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work % \realbackslash is an actual character `\' with catcode other, and % \doublebackslash is two of them (for the pdf outlines). {\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} % In texinfo, backslash is an active character; it prints the backslash % in fixed width font. \catcode`\\=\active % @ for escape char from now on. % The story here is that in math mode, the \char of \backslashcurfont % ends up printing the roman \ from the math symbol font (because \char % in math mode uses the \mathcode, and plain.tex sets % \mathcode`\\="026E). It seems better for @backslashchar{} to always % print a typewriter backslash, hence we use an explicit \mathchar, % which is the decimal equivalent of "715c (class 7, e.g., use \fam; % ignored family value; char position "5C). We can't use " for the % usual hex value because it has already been made active. @def@normalbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}} @let@backslashchar = @normalbackslash % @backslashchar{} is for user documents. % On startup, @fixbackslash assigns: % @let \ = @normalbackslash % \rawbackslash defines an active \ to do \backslashcurfont. % \otherbackslash defines an active \ to be a literal `\' character with % catcode other. We switch back and forth between these. @gdef@rawbackslash{@let\=@backslashcurfont} @gdef@otherbackslash{@let\=@realbackslash} % Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of % the literal character `\'. Also revert - to its normal character, in % case the active - from code has slipped in. % {@catcode`- = @active @gdef@normalturnoffactive{% @let-=@normaldash @let"=@normaldoublequote @let$=@normaldollar %$ font-lock fix @let+=@normalplus @let<=@normalless @let>=@normalgreater @let\=@normalbackslash @let^=@normalcaret @let_=@normalunderscore @let|=@normalverticalbar @let~=@normaltilde @markupsetuplqdefault @markupsetuprqdefault @unsepspaces } } % Make _ and + \other characters, temporarily. % This is canceled by @fixbackslash. @otherifyactive % If a .fmt file is being used, we don't want the `\input texinfo' to show up. % That is what \eatinput is for; after that, the `\' should revert to printing % a backslash. % @gdef@eatinput input texinfo{@fixbackslash} @global@let\ = @eatinput % On the other hand, perhaps the file did not have a `\input texinfo'. Then % the first `\' in the file would cause an error. This macro tries to fix % that, assuming it is called before the first `\' could plausibly occur. % Also turn back on active characters that might appear in the input % file name, in case not using a pre-dumped format. % @gdef@fixbackslash{% @ifx\@eatinput @let\ = @normalbackslash @fi @catcode`+=@active @catcode`@_=@active } % Say @foo, not \foo, in error messages. @escapechar = `@@ % These (along with & and #) are made active for url-breaking, so need % active definitions as the normal characters. @def@normaldot{.} @def@normalquest{?} @def@normalslash{/} % These look ok in all fonts, so just make them not special. % @hashchar{} gets its own user-level command, because of #line. @catcode`@& = @other @def@normalamp{&} @catcode`@# = @other @def@normalhash{#} @catcode`@% = @other @def@normalpercent{%} @let @hashchar = @normalhash @c Finally, make ` and ' active, so that txicodequoteundirected and @c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we @c don't make ` and ' active, @code will not get them as active chars. @c Do this last of all since we use ` in the previous @catcode assignments. @catcode`@'=@active @catcode`@`=@active @markupsetuplqdefault @markupsetuprqdefault @c Local variables: @c eval: (add-hook 'write-file-hooks 'time-stamp) @c page-delimiter: "^\\\\message" @c time-stamp-start: "def\\\\texinfoversion{" @c time-stamp-format: "%:y-%02m-%02d.%02H" @c time-stamp-end: "}" @c End: @c vim:sw=2: @ignore arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 @end ignore quagga-0.99.24.1/doc/stamp-vti0000644000175000017500000000014612476521356012654 00000000000000@set UPDATED 7 March 2015 @set UPDATED-MONTH March 2015 @set EDITION 0.99.24.1 @set VERSION 0.99.24.1 quagga-0.99.24.1/doc/version.texi0000644000175000017500000000014612476521356013365 00000000000000@set UPDATED 7 March 2015 @set UPDATED-MONTH March 2015 @set EDITION 0.99.24.1 @set VERSION 0.99.24.1 quagga-0.99.24.1/doc/mdate-sh0000755000175000017500000001363712476521250012437 00000000000000#!/bin/sh # Get modification time of a file or directory and pretty-print it. scriptversion=2010-08-21.06; # UTC # Copyright (C) 1995-2013 Free Software Foundation, Inc. # written by Ulrich Drepper , June 1995 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST fi case $1 in '') echo "$0: No file. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: mdate-sh [--help] [--version] FILE Pretty-print the modification day of FILE, in the format: 1 January 1970 Report bugs to . EOF exit $? ;; -v | --v*) echo "mdate-sh $scriptversion" exit $? ;; esac error () { echo "$0: $1" >&2 exit 1 } # Prevent date giving response in another language. LANG=C export LANG LC_ALL=C export LC_ALL LC_TIME=C export LC_TIME # GNU ls changes its time format in response to the TIME_STYLE # variable. Since we cannot assume 'unset' works, revert this # variable to its documented default. if test "${TIME_STYLE+set}" = set; then TIME_STYLE=posix-long-iso export TIME_STYLE fi save_arg1=$1 # Find out how to get the extended ls output of a file or directory. if ls -L /dev/null 1>/dev/null 2>&1; then ls_command='ls -L -l -d' else ls_command='ls -l -d' fi # Avoid user/group names that might have spaces, when possible. if ls -n /dev/null 1>/dev/null 2>&1; then ls_command="$ls_command -n" fi # A 'ls -l' line looks as follows on OS/2. # drwxrwx--- 0 Aug 11 2001 foo # This differs from Unix, which adds ownership information. # drwxrwx--- 2 root root 4096 Aug 11 2001 foo # # To find the date, we split the line on spaces and iterate on words # until we find a month. This cannot work with files whose owner is a # user named "Jan", or "Feb", etc. However, it's unlikely that '/' # will be owned by a user whose name is a month. So we first look at # the extended ls output of the root directory to decide how many # words should be skipped to get the date. # On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below. set x`$ls_command /` # Find which argument is the month. month= command= until test $month do test $# -gt 0 || error "failed parsing '$ls_command /' output" shift # Add another shift to the command. command="$command shift;" case $1 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac done test -n "$month" || error "failed parsing '$ls_command /' output" # Get the extended ls output of the file or directory. set dummy x`eval "$ls_command \"\\\$save_arg1\""` # Remove all preceding arguments eval $command # Because of the dummy argument above, month is in $2. # # On a POSIX system, we should have # # $# = 5 # $1 = file size # $2 = month # $3 = day # $4 = year or time # $5 = filename # # On Darwin 7.7.0 and 7.6.0, we have # # $# = 4 # $1 = day # $2 = month # $3 = year or time # $4 = filename # Get the month. case $2 in Jan) month=January; nummonth=1;; Feb) month=February; nummonth=2;; Mar) month=March; nummonth=3;; Apr) month=April; nummonth=4;; May) month=May; nummonth=5;; Jun) month=June; nummonth=6;; Jul) month=July; nummonth=7;; Aug) month=August; nummonth=8;; Sep) month=September; nummonth=9;; Oct) month=October; nummonth=10;; Nov) month=November; nummonth=11;; Dec) month=December; nummonth=12;; esac case $3 in ???*) day=$1;; *) day=$3; shift;; esac # Here we have to deal with the problem that the ls output gives either # the time of day or the year. case $3 in *:*) set `date`; eval year=\$$# case $2 in Jan) nummonthtod=1;; Feb) nummonthtod=2;; Mar) nummonthtod=3;; Apr) nummonthtod=4;; May) nummonthtod=5;; Jun) nummonthtod=6;; Jul) nummonthtod=7;; Aug) nummonthtod=8;; Sep) nummonthtod=9;; Oct) nummonthtod=10;; Nov) nummonthtod=11;; Dec) nummonthtod=12;; esac # For the first six month of the year the time notation can also # be used for files modified in the last year. if (expr $nummonth \> $nummonthtod) > /dev/null; then year=`expr $year - 1` fi;; *) year=$3;; esac # The result. echo $day $month $year # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: quagga-0.99.24.1/doc/fig_topologies_rs.txt0000644000175000017500000000006512476520570015260 00000000000000(RF1) (RF2) \ / [RS] / \ (RF3) (RF4) quagga-0.99.24.1/doc/fig_topologies_full.txt0000644000175000017500000000010612476520570015572 00000000000000(RF1)--(RF2) | \ / | | \/ | | /\ | | / \ | (RF3)--(RF4) quagga-0.99.24.1/doc/fig-rs-processing.txt0000644000175000017500000000430012476520570015100 00000000000000From Peer A | From RS-Client B | | From RS-Client C | | | From RS-Client D | | | | | | | | Main / Normal RIB | | | | ________________________________ | | | | / _________ _________ \ | | | +--->|(D)-|Best | | Main | | | | +--|--->|(C)-|Path |-->|Local-RIB|->[A]|--->To Peer A | +--|--|--->|(B)-|Selection| | | | +--|--|--|--->|(A)-|_________| |_________| | | | | | \________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \ | | | +--->*D*->|{B}-|Best | |RS-Client| | | | +--|--->*C*->|{B}-|Path |-->|Local-RIB|->[B]|--->To RS-Client B | | | | | |Selection| | for B | | +--|--|--|-------->|{B}-|_________| |_________| | | | | | \________________________________/ | | | | | | | | ________________________________ | | | | / _________ _________ \ | | | +--->*D*->|{C}-|Best | |RS-Client| | | | | | | |Path |-->|Local-RIB|->[C]|--->To RS-Client C | +--|--|--->*B*->|{C}-|Selection| | for C | | +--|--|--|-------->|{C}-|_________| |_________| | | | | \________________________________/ | | | | | | ________________________________ | | | / _________ _________ \ | | | | |Best | |RS-Client| | | | +------>*C*->|{D}-|Path |-->|Local-RIB|->[D]|--->To RS-Client D | +--------->*B*->|{D}-|Selection| | for D | | +----------------->|{D}-|_________| |_________| | \________________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements before considering announcement for the normal main Local-RIB [X] - 'Out' Filter applied to announcements to Peer X *X* - 'Export' Filter of RS-Client X, to apply X's policies before its routes may be considered for other RS-Clients RIBs. {X} - 'Import' Filter of RS-Client X, to apply X's policies on routes before allowing them into X's RIB. quagga-0.99.24.1/doc/fig-normal-processing.txt0000644000175000017500000000102512476520570015745 00000000000000 _______________________________ / _________ _________ \ From Peer A --->|(A)-|Best | | |-[A]|--->To Peer A From Peer B --->|(B)-|Path |-->|Local-RIB|-[B]|--->To Peer B From Peer C --->|(C)-|Selection| | |-[C]|--->To Peer C From Peer D --->|(D)-|_________| |_________|-[D]|--->To Peer D \_______________________________/ Key: (X) - 'In' Filter applied to Peer X's announcements [X] - 'Out' Filter applied to announcements to Peer X quagga-0.99.24.1/doc/snmptrap.texi0000644000175000017500000001414012476520570013540 00000000000000@c Documentation on configuring Quagga and snmpd for SNMP traps @c contributed by Jeroen Simonetti, jsimonetti@denit.net @node Handling SNMP Traps @section Handling SNMP Traps To handle snmp traps make sure your snmp setup of quagga works correctly as described in the quagga documentation in @xref{SNMP Support}. The BGP4 mib will send traps on peer up/down events. These should be visible in your snmp logs with a message similar to: @samp{snmpd[13733]: Got trap from peer on fd 14} To react on these traps they should be handled by a trapsink. Configure your trapsink by adding the following lines to @file{/etc/snmpd/snmpd.conf}: @example # send traps to the snmptrapd on localhost trapsink localhost @end example This will send all traps to an snmptrapd running on localhost. You can of course also use a dedicated management station to catch traps. Configure the snmptrapd daemon by adding the following line to @file{/etc/snmpd/snmptrapd.conf}: @c Documentation contributed by Jeroen Simonetti, jsimonetti@denit.net @example traphandle .1.3.6.1.4.1.3317.1.2.2 /etc/snmp/snmptrap_handle.sh @end example This will use the bash script @file{/etc/snmp/snmptrap_handle.sh} to handle the BGP4 traps. To add traps for other protocol daemons, lookup their appropriate OID from their mib. (For additional information about which traps are supported by your mib, lookup the mib on @uref{http://www.oidview.com/mibs/detail.html}). Make sure snmptrapd is started. The snmptrap_handle.sh script I personally use for handling BGP4 traps is below. You can of course do all sorts of things when handling traps, like sound a siren, have your display flash, etc., be creative ;). @verbatim #!/bin/bash # routers name ROUTER=`hostname -s` #email address use to sent out notification EMAILADDR="john@doe.com" #email address used (allongside above) where warnings should be sent EMAILADDR_WARN="sms-john@doe.com" # type of notification TYPE="Notice" # local snmp community for getting AS belonging to peer COMMUNITY="" # if a peer address is in $WARN_PEERS a warning should be sent WARN_PEERS="192.0.2.1" # get stdin INPUT=`cat -` # get some vars from stdin uptime=`echo $INPUT | cut -d' ' -f5` peer=`echo $INPUT | cut -d' ' -f8 | sed -e 's/SNMPv2-SMI::mib-2.15.3.1.14.//g'` peerstate=`echo $INPUT | cut -d' ' -f13` errorcode=`echo $INPUT | cut -d' ' -f9 | sed -e 's/\"//g'` suberrorcode=`echo $INPUT | cut -d' ' -f10 | sed -e 's/\"//g'` remoteas=`snmpget -v2c -c $COMMUNITY localhost SNMPv2-SMI::mib-2.15.3.1.9.$peer | cut -d' ' -f4` WHOISINFO=`whois -h whois.ripe.net " -r AS$remoteas" | egrep '(as-name|descr)'` asname=`echo "$WHOISINFO" | grep "^as-name:" | sed -e 's/^as-name://g' -e 's/ //g' -e 's/^ //g' | uniq` asdescr=`echo "$WHOISINFO" | grep "^descr:" | sed -e 's/^descr://g' -e 's/ //g' -e 's/^ //g' | uniq` # if peer address is in $WARN_PEER, the email should also # be sent to $EMAILADDR_WARN for ip in $WARN_PEERS; do if [ "x$ip" == "x$peer" ]; then EMAILADDR="$EMAILADDR,$EMAILADDR_WARN" TYPE="WARNING" break fi done # convert peer state case "$peerstate" in 1) peerstate="Idle" ;; 2) peerstate="Connect" ;; 3) peerstate="Active" ;; 4) peerstate="Opensent" ;; 5) peerstate="Openconfirm" ;; 6) peerstate="Established" ;; *) peerstate="Unknown" ;; esac # get textual messages for errors case "$errorcode" in 00) error="No error" suberror="" ;; 01) error="Message Header Error" case "$suberrorcode" in 01) suberror="Connection Not Synchronized" ;; 02) suberror="Bad Message Length" ;; 03) suberror="Bad Message Type" ;; *) suberror="Unknown" ;; esac ;; 02) error="OPEN Message Error" case "$suberrorcode" in 01) suberror="Unsupported Version Number" ;; 02) suberror="Bad Peer AS" ;; 03) suberror="Bad BGP Identifier" ;; 04) suberror="Unsupported Optional Parameter" ;; 05) suberror="Authentication Failure" ;; 06) suberror="Unacceptable Hold Time" ;; *) suberror="Unknown" ;; esac ;; 03) error="UPDATE Message Error" case "$suberrorcode" in 01) suberror="Malformed Attribute List" ;; 02) suberror="Unrecognized Well-known Attribute" ;; 03) suberror="Missing Well-known Attribute" ;; 04) suberror="Attribute Flags Error" ;; 05) suberror="Attribute Length Error" ;; 06) suberror="Invalid ORIGIN Attribute" ;; 07) suberror="AS Routing Loop" ;; 08) suberror="Invalid NEXT_HOP Attribute" ;; 09) suberror="Optional Attribute Error" ;; 10) suberror="Invalid Network Field" ;; 11) suberror="Malformed AS_PATH" ;; *) suberror="Unknown" ;; esac ;; 04) error="Hold Timer Expired" suberror="" ;; 05) error="Finite State Machine Error" suberror="" ;; 06) error="Cease" case "$suberrorcode" in 01) suberror="Maximum Number of Prefixes Reached" ;; 02) suberror="Administratively Shutdown" ;; 03) suberror="Peer Unconfigured" ;; 04) suberror="Administratively Reset" ;; 05) suberror="Connection Rejected" ;; 06) suberror="Other Configuration Change" ;; 07) suberror="Connection collision resolution" ;; 08) suberror="Out of Resource" ;; 09) suberror="MAX" ;; *) suberror="Unknown" ;; esac ;; *) error="Unknown" suberror="" ;; esac # create textual message from errorcodes if [ "x$suberror" == "x" ]; then NOTIFY="$errorcode ($error)" else NOTIFY="$errorcode/$suberrorcode ($error/$suberror)" fi # form a decent subject SUBJECT="$TYPE: $ROUTER [bgp] $peer is $peerstate: $NOTIFY" # create the email body MAIL=`cat << EOF BGP notification on router $ROUTER. Peer: $peer AS: $remoteas New state: $peerstate Notification: $NOTIFY Info: $asname $asdescr Snmpd uptime: $uptime EOF` # mail the notification echo "$MAIL" | mail -s "$SUBJECT" $EMAILADDR @end verbatim quagga-0.99.24.1/doc/fig_topologies_rs.png0000644000175000017500000002341212476520570015226 00000000000000‰PNG  IHDRÞÞÝ)àsBITÛáOà pHYsÐй‹çŸ IDATxœíiTTGÚÇÿ½ÙȦ²$€‚,¢ Ñ F='NŒÑ9ˆÄd—à”1ñ&2‰Y4=&šxrBDÜ2\"&Îà‚‘Œ¢Aƒ¢, .¸°JÓtßz?v7M¯ÐÛí¾¿ÓºëÖ­ûÜú?u»n­ûì”)SÂÃÃ{|usc]}{âš Ãì߿˖-ùùù4D DGGOœ81((((((,,ÌÉÉI,;99566Þ¿ÿîÝ»7nÜ()))...,,dÇ›0aBrrr||¼H$êñ=p˜[Ñ—Ã0YYY>>>ô\ggç™3gæçç3 cx"‰$777))Ianppð®]»är¹QÆp˜›Ò××,**5j½X@@@fffkk«QS£µµ5##cèС4ÍÈÈÈÊÊÊÞ$ÈÑlM_ƒ\S*•Ο?ŸÇãðððÈÊÊ2ªéF&“eggÐ?ŽeË–µµµ™*qC°M}õ»fEEÅÈ‘#ôéÓ'--­—%Immmiii@DDÄ­[·ÌqŽîج¾z\óüùóýúõ£Õ…óçÏ›ÈN­\¹r%44€——×É“'Í}9[ÖW—kæååõíÛÀ‹/¾ØÒÒbR#µÒØØ8eÊ|>ÿÀ–¹¨cbãújuÍÜÜ\>Ÿ`áÂ…~w–ËåsçÎ¥1yyy–¼´ã`ûújvÍÓ§O;99Q»Íf¡–-[@(rÿì&‡újpÍòòrwwwëÚM™7oOOϪª*ëZbO°E_u×looŠŠ'“É,a värùÔ©SDEE=zôÈºÆØ,ÒWÝ5—.] $$¤¹¹ÙRêâáÇô.55ÕÚ¶Ø,Ò·‹kž={–Çã …ÂsçÎYÐ<=\¾|Y ‚_~ùÅÚ¶°vé«tM¹\Nû©V¬Xaqóôðî»ïÒž.öR8¬ÓWéšÛ¶màïïo¦þ€Þ ‘HhO×öíÛ­m [a¾®)“É dËÚçää ³zå°QßN×Ü·o€ÐÐP›™ÖÑÑAëË»ví²¶-ìƒúvºæsÏ=`Ó¦MÖ³M?ß|ó €ñãÇ[ÛöÁF}A)++àîînãm‡MMM...<¯¢¢ÂÚ¶° –êË›› `Ú´i´³ßfqssKHH „ìܹÓÚ¶° ¶êK‰‰‰››«ð_³Äbq```BB¾}ûtT\ ´¦_¿~ÝÏíèè¸páÂÆ_}õUÕC‡k¢‚ê¨ékq›ššrrrf̘ܧO@øÆo\¼xQ5eU}ÑÐÐÀãñúöíÛÞÞ®ˆaàD¸É“'K$SYOùøãŸþyÕ8ªš››E"‘P(lll4TǦ»¾–·¶¶ÖÕÕUc>Ÿ¿yófEʪú i|TTTŸ>}ºŸyùòeÅw†aZZZªªªŽ?Ng!ýðÃkÖ¬ù裴7xðàC‡é°žŽËR°jÕ*¹\. cbbJKK›››Õ⻺ºÆÄÄœ9sæÔ©S´û•C7:ôµ˜¸R©´¥¥å©§žJLL¤Ó2[[[9²téÒ†††E‹=ýôÓ£GFW}‘žž`ñâŪÅBQ°´•Ž{÷Ò!!!: Vxx¸œÕ«Wÿ÷¿ÿ¥mÂÚlxçw¤§§•²ÃÒ]_Ë‹ûðáÃcÇŽuïÉ;xð MjÚ´iŠ@…¾Â’’tvˆá$$$x{{×××WUUu¢nÒÒÒôÆ¡3ôè['‡^z ¯ÉÅíß¿ÿ¤I“º‡ÿõ¯uwwojj:sæŒ"P¡/ÿöíÛh7‘áðx}ºŽ³äryCCƒ¶£b±¸ÀÔt©Tj쉎‰!úZE\¹\N_ÿE"ÑòåËáJ}¨ ”ÒÛôåçç·cÇ£'uŸNyï½÷t¼Öi{‘”H$ô {;ttºëk âBÞÿ}3##C5\¡¯6>Éd2C®§`÷îÝtÄ€å¡[a9ºÓ}- îúõëi«Ö§Ÿ~úüCõRßàà`ׯ_Wõ\EÁzØ:@xx¸î©Šhº‹Ž´=5+++õ8e‡¢»¾Ö—a˜?þŸÏW{^RúbìØ± Tks †a}0)))f²^· §OŸÝ㔊îúZQ\†ah‹º‹‹Ë‘#G4ÆQè˧ïê´±@/</33“VT7nÜxâÄ CÎ2-´ES±4‡n ××ÜâBÞzë­/¾øÂÕÕõÇ|饗4FSèË1b€ .xÿuëÖÑïsçÎmll4…ÙF@MçVÚ6£ô5«¸|ðAff&€Ý»wÇÆÆj‹¦Ð—ÿç?ÿÀÿþ÷?ï‘””4nÜ87oÞ\¼xqoM6’¢¢"<Îq½«¯™ÄÝ·oßêÕ«,X°€.Ç¥ ¥¾ºÅi«4”••)z±4®÷E™¼®É Š3ƒâ´brqkkk @ ܾ}[GÌ.ƒâúõë]TTtôèÑiÓ¦XÂÂÂ>þøcÚRº`Á‚1cƨö5õÚ¦E¡mÅj±±±tÕ½ô@_“‹»~ýú‡4hÐñãÇ5ÆILLpòäI¥¾„5kÖ˜3gŽÂyõ,BHGG]=@\\œZ - 7ö©IW­ÕÁË/¿ à“O>1*YGM_Ë‹ûÆoèu_sΜ9 }5O[3ÄzBÈÅ‹δuëÖÞXOÑëšÎÎÎÜ´5cQÓ×òâèšjÓָɾõå–Hpب/·°ŒCÀF}¹å¸ÖéË-bè(°N_néW‚]úr f;,Ò—ÛfÀ±`‘¾Üæ,[ôå¶´rDX¡¯mo(æmÛfÉK;¹ÙÙ|ÏÊúö`#@Šõ·×œ4‰ˆÅ$5•Ô×[æêA}=IM%bqÞäɬÜ>•båM‰7l ˆ»;YµŠX*ûì––²jqwïÌÕ غé4Åš[¹=Ú™‰ôããC22ˆTjì©”ddŸ.ùyô(±®¾:Ñïš„©T:þ|ÀÃÃ#++Ë„½22™,;;›öS ‚eË–µµµu«¨è’•ôJvï&\·0 Ù½›„†jÈÉÇc ­¦¯N rMJQQíé™™ÙËÖÚÚš‘‘¡˜YYYÙ%†LFÄb y ‘#É?öæêÁ?’‘#5g XLº¶kZA_áš„†a²²²|||{gΜ™ŸŸoT!“H$¹¹¹III"‘ˆ¦LWÂÕ{øpÍ9K?ù 1 ‰•œ?Oþò]Y7|x÷“¬ ¯vxÄॹ0 ³ÿþ-[¶äççÓ@M×B srr‹ÅNNN÷ïß¿{÷î7JJJŠ‹‹ é¼7a„äääøøxÅm¨“€tYÃãáÕW±jBBŒ½û¤¼+V`ÏèVvútì߯ñˆEõÕQެÆ;wV¯^=vìXZM1>Ÿ?zôèôôôk×®é¿FZ𮢝øˆDdáBRSÓ›Ûa=55dáB"”ciizÓ³„¾ÚéÉS³;íííEEEåååUUU•••mmmR©T"‘¸¹¹yyy 8ÐÏÏ/22rĈÑÑÑžžž†&½m ìêŠ%K°t)m¾eS>ÿ6 ¥ÅÐSrr`À”ŠõÕŽi\ÓŒüü3FևǃŸÂÆðpŒ‡gž±ˆq6Cq1NBY®_GYîÜÑóoàìYh_Bðy×|ðÚŠ`d$Þ{aaˆˆ€³³eͲm=ÂÕ«¸~k×â×_5ǹ–5Ë8øú£Xx{k>ôë¯ 1r$ç—ê8;cäH…ZýÒÛÛÆý,pMj+o©®$‘œŒ[·,l;¸u ÉÉÊŸjËo°a13¶¹¦·7„XÜùóÁ$&âñ40 ñàAçO±vùóá\Ó4„…)¿ðbc±zµ2äÄ lØ`y£lš  º:æêÕˆÅ(CT³ÔféMË“…8x°³).(ˆÐåÎär2qb—>·K—¬m¥ÍpéR—Þ݉ í†io'AAZÛJý°Á5¯^íÌÐ;•·n¥ú1lЀÓÖFþô'e¶xxÕ1>;wv†_½j= … ®ÙÞN„BIÔ:a÷îíÒ½¡sùqG!%¥KžìÝÛå¨\N"#‰PHTÖRµYØàš„ÐP:¸PÄD¥ <9vÌâ–ÙÇŽO™!‰‰â=JBC-nYO`‰k~þ¹æð¦&¬Ã×WëTÿÛ|ÖYm7R_O|}•YLšš4ÇÔ–™6K\SÇxª³g‰P¨”$>^CœæfâãClo­£im%>>DãêññÊL ÉÙ³Z±ÕÅâÔ`Cã¾v;ccñÏ*ææâÛoÕã¬_»wqã†Yl³$7nàî]¬_¯þí·ÈÍUþüç?uõëÈL›ÂÚeÃtt˜å3ÃÕ•¨nWWGÜÜ@ö챞‰&bÏ77RW§ ¼~¸º*o?&†ttXÏD“Á’¤¡;wÂÕµógK fφbWÆO?Es3”•YÇ<Bo¡¹Ÿ~Ú"“aölåX8WWìÜ }û4³»pM!!øòKåÏ¢"¬\ UUøúëÎ@»qM_ª*X¹EEÊ_~i?£ý­ýØ6)ª¯),$³f)CF²¶}½fÔ(åíÌšE ‰@ çµØüxM£¸w‘‘¸s§ó§¿?îÜQþpw‡Å·-41ýú¡©©ó;Ÿ??åÀ+??üú+¼¼¬ešÉ±—?tŠ—¶n…b"Ë­[]%55¡¦Æ*v™†š¥_`¥_òxغ՞üö暆G|¼Ö£¬®nê0>>Ç[ÐKÀæW¹ÖÖΩ0Š91eezæm••a ™grt¸æ8p®®WΑ¢_\\,h¢)a³k64 #99Êv"½ØëS“ÒÒ‚ @÷— ‘˜ˆ?f¯k²ù}à@de¡¤ññ0p¢ôõëf¶Éœh<‡øx”” + šÙ&3ÂfפDDàÀœ=‹ñãõG¶ï§&€ñãqö,@D„ù 2/öÕxtô(ÒÒPR¢5‚PˆÖVôécA›L„T ]U—#ðÙgxé% Úd^ØÿÔT套pñ"¶oÇàÁš#Èd(/·¨I¦¢¼\«_ŒíÛqñ¢=ù%ìÍ5ðù˜=×®aÃÍí|,­nj4ÛË 6àÚ5̞͚ñDco÷Ó‰XŒÔTTT`Å õWT–V7ÕÌvqÁЍ¨@jªrê³}a§®IqwÇÊ•(/ÇÂ…P,¢Çv׉°p!Ê˱r¥}¯:f×®IññÁæÍ(-Å«¯‚Çc±kÒ•DKK±y3¯ÎjÇØ×º^.\à=^šuóç1r¤µ­°暀Q«˜Úަ›;*{»dfoqê P×ä`'œkrØ(œkrØ(œkrØ(œkrØ(œkrØ(ÚxdC‡-ÓÒu$‹}||FõÚk¯ÅÇÇóµ­øã?rrr ÊÊÊîÝ»×ÑÑ!‹ àïïñÌ3Ï<ÿüóO=õ”Ùn‚ÍXs¦±50ü®Ã [ð|òäɉDc _~ùe}cCcbbLh³=Á=5õsùòeÅw†aZZZªªªŽ?N·ýá‡Ö¬YóÑG©uàÀÔÔTB¡011ñÅ_ ‰D---·oß¾zõêÙ³gOŸ>mÑ;aÖ.–Æð»V<5µEØ»w/ÒýhLL =š››«-…G;w΄6ÛÚ‡nÈ]+êšÚ"Bž|òÉúúz@ ë6ÝÉÉ©½½Ý××÷öíÛ½ìi4Üf{‚{Cï9<ÏÅÅ€““S÷£tãe¹\ni³ìÎ5{N]]]uu5€‘šÆªÑÀºººM›6YÚ2»€sÍ"“ÉRSSé£1%%¥{„´´4ú%%%eúôé………ŽöÜ[¬Yѵ†ßu÷× úz^ZZš••õôÓOÓ£K–,aFc _|ñ…j-3 àí·ßþñÇÛÜÅA•²¶–¦®© ??¿;vhóKÊÏ?ÿ<¡Û*Kýúõ›7oÞ… Ln³=áx7l:×ìʶmÛhxxxx«‘¾Ü¾}{Ó¦M±*ÛSשîÐ;›í Ç»aã]S-œa˜©S§ÒC)=Ý}ðçŸ:t(MdÁ‚¦²Ùžp¼îµkBnÞ¼éææFþôÓO=³¤²²’¾$ùúúêŽé˜®É5õÿuëÖÑïsçÎmìÑñAAAƒP[[k:ÓìÎ5{HRRÒ¸qãܼysñâÅ=HaêÓ^öµ»©à\³‡ðùü¬¬,ÚE¹mÛ¶\Õ}ø/¼ðÂÞ½{ÛÚÚ´¥°cÇŽ˜4i’YMe)Üð­èÞ`íڵ˗/àíí}åÊ•'žxBíBÎÎÎãÇ6l˜¯¯¯‹‹‹L&ûý÷ß:´}ûvBˆ››[qqqˆÎ}¨sx‡ÃU® ¿k½ƒâ!QQQ4Z\\œjó»···ÞÌ äÅiƒ{jjŧ&€K—.5ŠŽ0Úºukbb" gæÊ•+………ÅÅÅ¥¥¥üñǽ{÷ÚÛÛE"‘OTTT\\Ük¯½Ö·o_ÚlOp®ÉØhsïá^ƒ8lÎ59lÎ59lÎ59lÎ59lÎ59lÎ59l]½Ã1— föÔûLùóñö(DD€ÕŽx<õ†wÕüì3œ,Z¤ùôæf’“cVMK\sî\²j•†ð¼¼Î?kú™=[k ÇŽ™Ï:‹¢ãFfÏVfGòò4ÄYµŠÌk>ëLKzƒž}ee¨¨€‡‡2ðÎDFâ޽Ο!!(.ÆãÕÿ‘æf<ó ÊË;zyá×_»Œò|ðC† <œ3àØÐxD®^EC¯ì ƒÙ³•~)á»ïÚ/¸¹á»ï uþ¼w³g+gžƒY¯^+žGÖ~l@uu矔‹ ©©é üì³.U«5k¬j¢-±fM—œùì³ÎðšââÒX]mU ‚ ®yì˜2£ß~›BÎ#"‘2pâD{xû6r9™8Q™9"¡kr¿ý¶2 5o6ü¡—–*¿ó ~û 3g¢££3ÄÛ»Kí S¬$ßÑ™3ñÛoøæeÕ,µUØ èÕ«Êïí툋SŽåñÍÊihfÅ×ÙÙʱ,ˆ‹ë2ŒU5Km6¸¦ZW¹½hoÉÑ…©S±h‘ò§Úpwî©i´å£¿?ââÐÔdYkXBSââ´ŽOeƒkÚ|»¦Žù× ž|Æ!"B9÷àÉ'-bœÍP[«œ‚rõ*JKõ¯›`óóñM37¨½½½   ¨¨¨¼¼¼ªªª²²²­­M*•J$777//¯úùùEFFŽ1"::ÚÓÓÓФ )ßµµ¨­Åÿ cÆ =Ýá\óÚ5¬XÂB#N)-5Ü5ͨ¯zózçÎÕ«W;Ö¨å*ù|þèÑ£ÓÓÓ¯]»¦ÿ7vi¥Óñ‰Š²‡ao½áÈehvmܨ7=K諞ü¡3 ³ÿþ-[¶äççÓ@=qâÄ      °°0'''±XìääÔØØxÿþý»wïÞ¸q£¤¤¤¸¸¸°°a<o„ ÉÉÉñññ"E†ÿø¾þZAC‡båJ¼ü2»çW˜B°o>ü׮鉙œŒÌLG,ª¯Î{1†a²²²|||è¹ÎÎÎ3gÎÌÏÏgŒg%‘Hrss“’’æïÚµK®±Ù|Ü8]Eð`²u+‘ÉŒº ûG&#[·’ÁƒueݸqÝϳ‚¾Ú1Â5‹ŠŠFE/™™ÙÚÚjÔÅÔhmmÍÈÈ:t(M322²²²R=’··æœõõ%›6‘ööÞ`ç´·“M›ˆ¯¯æ ôöV‹n}µckJ¥ÒùóçÓ ‡‡‡GVV–QÅH72™,;;; €þq,[¶¬M1 ¶®NCžzz’µkIïrÍhm%k×OO 9YWG£XM_èwÍŠŠŠ‘#GèÓ§OZZZ/K’6ÚÚÚÒÒÒ€ˆˆˆ[·nBHAA—¬ts#~HÌa€ÓÐ@>ü¸¹uÉÏ‚b]}u¢Ç5ÏŸ?߯_?Z]8þ¼‰ìÔÊ•+WBCCxyyÿÀK/‘ˆ$' ‡¡ÜºE’“‰H”7uª•õ=p@GL­®™››Ëçó,\¸ÐØw«^"—ËçÎ  P˜·u«%/í8änÙÂçñ¬¬oŸ>yg‰B´¹æéÓ§œœ¨Ýf³PË–-  õ>ù9Œ…újpÍòòrwwwëÚM™7oOOÏ*;˜Bn3°E_u×looŠŠ'³vS¶\.Ÿ:u*€¨¨¨GY×û€Eúª»æÒ¥K„„„4k›÷mY>|HßéRSS­m‹=À"}»¸æÙ³gy<žP(**ª¦mä._¾¬øÎ0LKKKUUÕñãÇé,¤~øaÍš5}ô‘6ã|èÐ!ÖóU–Ñòõõ1cƤI“"##û÷ïÿþý£G¦¥¥544|ÿý÷ãÆ{ë­·\]]cbbΜ9sêÔ©©Ü’2 C_Kn ÃA¡IDATŠ«FKKËŒ3ÚÚÚÔÂUõEzz:€Å‹«z´¢`isù½{÷Ò!!!: –¢4‚ÆËýû÷Ó¤&L˜@CÞyçéé醧ìÈt××*âªÂ0Ì믿 00ÐÏÏO-)…¾ü’’tvˆá$$$x{{¨ªª2êDЉ#jLž<™~©{¼Ý9¡Gß:9ôÒ}Í!®*YYYß}÷H$úþûïݺ-$­Ð—ûömÚ¶ŒÕÇsqq@G¤šGÑ/ô 5ýšÞ%8=Ð׬â^ºt)%%ÀçŸÝ=‚B_þ;wøé]òª+uuuÕÕÕ0þqk,»ví¢_þþ÷¿Ó/P__oÖëÚ =Ð×|â655͘1£½½=!!áí·ßÖG©¯««+µ^ÝÕ‘ŽŽŽ×^{FØ·oŸ9ª#„¹\ž-‹,_¾\Ñ~DÒÓÓ³Ç);Ýõµ–¸ Ã̘1@pppÃãÛÔÕ¤ú éò4B¡ž%ã!=ª®®.,,ܼyó¥K—,Y²dúôé:Î’Ëå ÚŽŠÅbµFàßÿýßÿþwkkkEEÅO?ýT]]=f̘O>ùäùçŸWÄ¡µ©TªÛ`Š!úZFÜŒŒŒ½{÷öéÓgïÞ½t†±F”ú:;;P(¥·éËÏÏoÇŽ:FOê>òÞ{ï©¥Ö¸~ýú{÷î©Æ‘H$ôŒ*²Kw}­"îùóçiëUf×Ý]»?5úòiã“L&3äz vïÞ=kÖ,£Ö¶3„˜˜˜ãÇ:t(##cÆŒ·oßþ¿ÿû¿   ={ö(â477ÐØ ËÑèkrqf̘!•Jÿö·¿-X°@wd¥¾ÁÁÁ®_¿ÞÝ—<ì Ž <<\÷ˆTE4 ·FJKKé‹9ŸÏ?sæ ¬¬¬Ô›”‡îúZX\†ahÅ ,,¬©©Iíh÷§¦B_Œ;@AAA÷Э¦Ì0Œ¢&%%ÅTÖëà?ÿùMjòäÉ4äôéÓ¢íf;T3Ó]_ ‹ûÛo¿øp0oÞ<…¾|ú®N ôÂãñ233iEuãÆ'Nœ0üª=c„  ¯M[4KãqèÆp}Í$.£º¡(ôå1À…  <ÓßßÝã½"çÎÛØØhÔ……Çãõïß@KK ¡¦8FÃ(}Í!nDDÄCíÐ8!!!ôçÆ•ú?~ÀèÑ£Uº›¾ärù¸qãh„7Þx£÷Ï|´¶¶Ò7žÁƒÓúuèС^¦ì t××vÄÕ˜”B_=ƒâ´¥XVV¦èÅÒ¸ÞW¬ïèèè¨(Ä‹-"Ü 8ãÑ1(NÛ)æWjI©ê«g(±ŽD׬YCãx{{×ÖÖöÞzŸE‹>|¸¦¦¦¹¹ùòåËK—.¥M  ‹…rC‰{€¶¡Ä:N1¹¸ÚPKªËPb…sæÌQœ`ˆõtõqqqj-´=°Zðõõ-**¢qæÌ™à“O>1>>ôbÎÎÎ3gÎÌÏÏ7ªI$’ÜÜܤ¤$‘HDÓ ¦+áe ‡É±)}yÄॹ0 ³ÿþ-[¶äççÓ@=qâÄ      °°0'''±XìääÔØØxÿþý»wïÞ¸q£¤¤¤¸¸¸°°ÎMæñx&LHNNŽW܇ձ}{âš jjjrrrŽ=ZXXhx:|>ÿÙgŸ2eJBB7Ü–±®¾½rMíííEEEåååUUU•••mmmR©T"‘¸¹¹yyy 8ÐÏÏ/22rĈÑÑÑžžž½¿(‡Å°Š¾ÿTÛ@8T5IEND®B`‚quagga-0.99.24.1/doc/fig_topologies_full.png0000644000175000017500000002045112476520570015544 00000000000000‰PNG  IHDRÞÞÝ)àsBITÛáOà pHYsÐй‹çŸ IDATxœíPgþÇ?›AÐ 2,§ 7sP¦¨œµéÔ™ÖÚN¤ˆmVë9zŽõ¬Ž uŽŽ:w8Úûë0SF«-\ýŠ”V-ïz¤*Ò±TÐk¥"Ü8õ=F"‰ !ÙçûǃKØìn6ÉþLö5ù6Ïóìgó~?ϳûì³Ï!›‘‘«ÕÚÑÑÑÛÛÛßßß××çt:Ýn·ËåJHHHNNNKKKMMÍËËËÍÍ-((HJJ §’!‹¾D8Ö¼uëÖáÇ[ZZÚÛÛù—£Óéžxâ‰%K–”””ää䄼w ±‘WßP¬I’dSSÓÁƒ[[[ñ½^_PP°hÑ¢ÌÌÌÌÌÌììl“Éd4M&“Íf¼}ûöÕ«W»»»;;;ÛÛÛI’‚ Ìfóºu늋‹cbbB> aQо(H’¬««›1cÎWVVÖÚÚJ’$ÿB\.Wssóš5k¨p³²²¼^oPÁhŽ¢ô š?þ8ÞYzzzmm­Ãájg4GMMÍܹsq™yyy}}}á¨JÓ——5Ýn÷Úµk ‚€iÓ¦ÕÕÕU¸ñx<‡JOOÇGEE…Óéªp >(SßÀÖ¼víÚc=±±±Û·o³&±át:·oß®×ë`Þ¼y?ÿü³{ÑðG±ú°æ… ¦L™‚O.\¸ Pœ¬\¾|yΜ9œœüÕW_‰½; %ëËeÍ'NLš4 ž{î9»Ý.h¬Øl¶%K–€N§ûä“O¤Ùit¢p}Y­ÙÜܬÓé`ýúõ_;{½ÞU«Vá.æÄ‰Rî:zP¾¾ÌÖ|²³³e?yW#jÔw̚ǀ9sæ(vfÚèè(>_nhh;õ¡F}Ǭùä“OÀ{ï½'_lyÿý÷à©§ž’;õ¡F}!ÔÓÓ‰‰‰ ;¼wï^||Ä"¾øBЈ¤%ÔàUªï¸5‹‹‹©DsçÎ%X0™LË–-kjj€0–ÆÔ©Sýóz<žÎÎοÿýﯼò >y§X¾|9œ>}:èã¶Záé§áòå 3*‡Ë—áé§Áj 6M_YÄ>räÈòåËõ«_FƒÁ‘‘ñÆo\¼xÑ·ä ú 1iÒ¤‘‘ªiåù ÜâÅ‹].cãÌóW›2eŠo®;w>óÌ3ñññ¾i| ÇÄÄ ›ÍÆ·ŸhkCf3@))Hª©_¢`·£”€ÌfÔÖÆ3“¿¾Ò‹{çÎÉ“'3¦Ñét JöÕ×€‡àóóócccýs^ºt‰ú›$I»ÝÞßßæÌüÒ_|±gÏž;v°—‘‘qòäIŽèñ¼,Š?ÿùÏ^¯×`0þðÃÃÃôô“'O.,,<þüÙ³gñíW.¬Vصk¼™)/‡‰¦WññP^[·‚Õ V+˜Í°c˜ÍÜ™8ô•L\·Ûm·Ûó›ß¼ñÆø±L‡Ãñù矗—— mذáÑG-**‚‰úBUU¼õÖ[¾Õ‚ªXlu±±±'˜={6GÅÊÉÉáY¹1»wïnkkÃcÂl1lÙ²ªªª¸ ¢ZJê£ö&C5œÔ'P ꯯ôâÞ½{÷ôéÓþwò>ýôS\ÔÒ¥K©”¾ðòË/ƒßHlÀèI’œ>}:èõzA¢÷‡-†ºº:X±bs6SâOuuÈ‘(‹êj†£c7¨¿¾Jãõzñô¼äädj#¥¯îÆ€oñ‡ |Fˆg¤J ~xôÊ•+ô/ð…ã…BJ ¬_/Ep°~=¤¤Ð7²{úJ&®N§KII€ÁÁAj#¥¯îæÍ›ššT¡ׯ_ü0ž”¤¥¥À/¿ü2¾‰Ã”µŸeú‚Ï8aúBÐW2q=Ï­[· ŧ²ë‹/h¼Ümþèè諯¾Š?~\¤6Ÿ-lʤ¤$„Ø»oíó ‹÷×W âb¨AÀ²²2} xøÊ`0p!tÿþýëׯ···8pGmÞ¼ù¥—^âÈåõz‡††Ø¾5! '$$@¡ÓÚ _´ðà*þ·Ok }e×ëõâËÿ˜˜˜·ß~›ÚŽõu»Ý´‰R‡¾RSS?úè#ŽÙ“ÜÙ1Û¶mã¨Rl•ÛårÀóqqZ{ɧí|Öd¢é«qBúÓŸpÊšš}tèlœ={–{ÇáG¯uèaš2`‡.£¸ï¾û.Nö—¿ü…M_ÈÊÊ€Ÿ~ú‰Ñw'‚§£@NN÷ŒT*÷ArÀf;¾>ÈÌÌßР3r„a?ò3%Æ__yÅ%IrçΠÓéhí%†Ò,XV«Õ÷k6[$I݃ٸq£HÑsÇpîÜ9((( gà0hdŒ·cüGÝYL‰ñ×WFqI’Ä#êñññŸþ9cJ_¾Vǃ!¢¶¶Ÿ¨îß¿ÿË/¿ä“KXðˆ&µ4Þ8f3´µA[ý»¨©‘"8 ¨©úFöc篯Øâ"„Þ|óÍwß}wòäÉÿüç?ŸþyÆd”¾ºÜÜ\øî»ïxî`æÌ™{÷îůZµÊf³ vàÐYO˜ØDÚ·у‡öí›°…£B@PúŠ*neeemm-=ztþüùlÉÆõ=sæ ù6ªÜC_^¯wáÂ…8ÁÊ•+…móÆ€{¨“'O.‚ÖÅGÀ§ïY&¿ùGþúÊ".u_þøwJJß“âØò÷ôôPw±×ûÉšÚ¤8þ¦ÄpLŠcË"¸¸wîÜy衇@¯×߸qƒ#¥¯¾€*,,€ææf*EÀèB{öìÁi¦OŸ~çÎ0£Ç8}À1€ïF< kþüùA‹Ðƒªºá¬®Ê”4}¥wÛ¶m8KFFÆ,à”§N¢ô*ß¹<|¢Å«ç€Åb¡Ð†fM¼j-Ë–-€]»vUì8--!fT—/‡–¦¯ôâ®\¹’[V*˜+VPú2?¶Æ'z„Ð÷ßO™‰2~hÑcZ3..N{l-XhúJ/.OkÒ[Óö Ô¨¯¶DBT F}µ…e¢5ê«-Ç-¨N_mÃhAuújK¿FêÒW[0;ºP‘¾Úk¢ 髽œ%êP‹¾Ú+­¢Uè«ì '¶lQ÷t!eb·7oÞ¬#™õ áE€ù_¯¹i@&²XP}=â?Nƒ› Õ×#‹™LàÄ–-ª|}*Fæ—ÛløGûh ‰Žÿ1m6µ¾t#ó«Ü-†ç³4òÑ‘ÔÇbÁ©dÖ—ÀÖD¹Ýîµk×Ó¦M«««ð®ŒÇã9tè¾O¥×ë+**œNçø×õõ\¶jõ‡Û‘Ô§¾žÊ!§¾ìð²&¦££ßé€ôôôÚÚÚ0k˜Ãᨩ©¡žÌËËëëë£'¢õéšGÙàéHŸÞœV€<ú²„5B$IÖÕÕ͘1ƒšØ[VVÖÚÚT%s¹\ÍÍÍkÖ¬‰‰‰Áådeeá•p™30öél£qÌ£üª¦êq:Çi4ñ+=èÍiÈ£/ â½47I’MMMlmmÅ[ôz}AA^ 9333;;Ûd2F“Éd³Ùoß¾}õêÕîîîÎÎÎööv¼Af³yݺuÅÅÅÔa0ÐЯ½Æ7¸œ(-…ÒRÈÍ ö¸ÔJw746Bc#ôôðÍR_eel_J­/A™ÆÍ›7wïÞ½`Á|šÂNWTTTUUuåÊ^»áÓ§çä ÊJÔÕÎ᨞®.TY‰rrBèÍ‘H_Bi5ý±Z­½½½ýýý}}}N§ÓítºÜî„ÄÄäää´´´ÔÔÔ¼¼¼ÜÜÜ‚‚‚¤¤¤àv°t)|öÃv‚€¥KaçÎ(j#ùÐÝ ;w§Ÿ£¸ ½« =ª¹sþ¾öÕë¯mƒêëÇk‰0/f*Øç Ú"íBvþïÿÆÝ z=€×;öodûR|}µV3 hm'eJˆt_J‚fÍðÀæ++›àK½^óeøèä@ý0vg‘z#!š5ÃãèQxýõ M&x½ðúëpô¨L1Eš5ÃûÒ÷2_ ÁƒkvÍa Y3Th¾4 ¡Àðàô]sgxh—A!áïKßëÿñÎW^‘#J•#ÒP~$ß x¿Gö•j$@»Q©8xÞ‡ŒxwjÖTAÝlwjÖT!ÌÛˆ`wjÖT !Ï'ŠTwjÖTaÎs‹HwjÖ”Aæ_Fž;5kÊŒ€ó‚#Ìš5åDðùê‘äNÍš²!ÒsãNÍšò êó=‘áNÍš2 ÁsgàNÍšR#Ùójw§fMI‘ø9]U»S³¦tÈòü¸zÝ©YS"d\×@¥îÔ¬)²¯·¡FwjÖÙ}‰Q;5kŠ‹B|‰Q—;5kŠˆ¢|‰Q‘;5kŠ…}‰Q‹;5kŠ‚b}‰Q…;5k Â}‰Q¾;5k Œ*|‰Q¸;5k ‰Š|‰Q²;5k †ê|‰Q¬;U`ÍË—Qu5r8ü fÝá@ÕÕèòåpwÍ•ú#¯;üQ.}…°¼ÙŒRRPu5²Û} f ÝnGÕÕ(%™Íì—'ªö%F^wʤ¯Ölk Ñ÷h¡SAã-mmì—àKŒŒî”I_NÌæñ@ñø†î4€tMfÄø#£;åÐW kR‹ÏGš&3Â|‰‘Ërè+Üå•oÅâøHÓdF¤/1r¹Sr}…³&ÏŠ%A“Á¾ÄÈâNÉõtP*`Å ¿JùbЈx_bBpgÀŸ. èëƒ Ö X±Â¯Rõõ¨«‹õÛ(ñ%&(wvu¡úúp÷(¾>=”ÏQ±©R ª¬dþ*ª|‰áïÎÊJd±°G±õõAhkrT¬ð«”͆L&”“ÃðUúÃÓ99ÈdB6[¸»U߉ˆp”±b R¥êëÇJ£õéQëKL@wvu}~ŸŽÄÔw""X“±b R¥,–±Ò|ûô(÷%†Û••cÛéÓÅÓw"âL¡U,AªîÍqTŸ®ù’‚Ã99céÓ‘8úú!Ž5iK*EõæTŸ®ù’£;©Þ\À>] }ým2%U±„ªRToŽ?ÅÅš/ðwgqñ„ßM>‰ ¯¢Y“ªX‚T)ßÞBó%34wúþPöéÂêË„˜SÐÍfÁª­7÷ýh¾ô‡æNÚG> ª/¼>uddÄjµvttôööö÷÷÷õõ9N·Óér»z(999---555///77·   )))¸462o'xñE˜7/üCˆ(æÍƒ_„O?„¾ml„²² ÊcÔ·Ðét»Ý‚èËH8¾¾yóæîÝ»,X@ÿ=êtº¢¢¢ªªª+W®ðÚoîÿÉÉA••\÷0£®.TY9~=ÎöáݧK¤/ b¬Xœ$ÙÔÔtðàÁÖÖV¼E¯×,Z´(333333;;Ûd2F“Éd³Ùoß¾}õêÕîîîÎÎÎööv’$€ ³Ù¼nݺââ☘Öý54Àk¯ñ .'JK¡´rsƒ=.µÒÝ ÐØ==|³Ô×s4œRëËFPF&I²®®nÆŒ8o\\\YYYkk+I’ü q¹\ÍÍÍkÖ¬¡ÂÍÊÊjhhðz½Ìh׿Ü£Y,¨¾9AšZq:Q}=²XÑįÄr.¾,aÍŽŽŽÇï,==½¶¶ÖÞ<+‡ÃQSS3wî\\f^^^__=ŸÞwRØ‘‚\~ª›mÌ£<.¿J}ÙáeM·Û½víZ|Â1mÚ´ººº ª7çСCééé¸ã¨¨¨pú6x׿š#áéQŸët9õe'°5¯]»öØc@llìöíÛìIl8ÎíÛ·ëõz˜7oÞÏ?ÿ<öco®9’Ü}Чˬ/;¬yáÂ…)S¦àÓ… .'+—/_ž3g$''õÕWôÞ\sdh0zÔdB6›ÌúrÂeÍ'NLš4 ž{î9»ïãñbb³Ù–,Y:î“M›4G ÉDžØ²Ef}?ù„#%«5›››u:¬_¿>Øk«0ñz½«V­€XƒáÄ–-Hª_-Š°Û›7oÖ„ÌúÆÆž8q‚-³5Ï;g2™pÜ¢E€ŠŠ 0 [~`Q…¾ ÖìííMLL”7nÌêÕ« ))©¿¿_ÞH" µèK·æÈÈH~~>X,Ç#E€ìx½Þ^xòóóïß¿/o0‘Šô¥[³¼¼fÏž=<<,U„\ܽ{_ÓmÚ´IîX"é;Áš_ý5Aƒá›o¾‘0¼\ºtI¯×ëõúo¿ýVîXÔºô·¦×ëÅ÷©ÞyçÉà ÀÖ­[ñ.ïRDªÓwÜšGŽ€™3gŠt? \.¾Óõá‡Ê‹ZQ¾cÖôx<<òˆ’µ?|ø0dggË~ò®FÔ¨ï˜5?sæÌ‘xô•?£££ø|¹¡¡AîXÔ‡õ³æ“O> ï½÷ž|±æý÷߀§žzJî@Ô‡õ„POO$&&*|ìðÞ½{ñññA\»vMîXÔ„JõÕ@ss3,]ºßìW, %%%¡úúú‹øÏHZB ^¥úŽ[³¸¸˜J4wî\‚“É”‘‘±lÙ²¦¦&ü#lÙiL:•ÊrìØ±5kÖ<úè£S¦LÁ;ÊÊÊzùå—O:…<À´|ùr8}útÐÇmµÂÓOCKKЕCK <ý4X­Áæ£é+‹¸Œ|ðÁ8%5~‚¾CCCALš4idd„jZsrrøóâÅ‹].cãÌ';L™2…O–åË—ã ·ááᘘƒÁ`ã?A®­ml©‰”uOb²ÛÇ^4a6ó_˜À__YÄõ§»»›jÅs,b嫯ÁçççÇÆÆú—~éÒ%êo’$ív{ÿ™3gðSH_|ñÅž={vìØÁ\FFÆÉ“'9¢Çóî0?üpiié³Ï>›——7uêÔÁÁÁ–––íÛ· ;vláÂ…o¾ùæäÉ“ ÏŸ?öìY|û• «víofÊË!>>@%åå°u+X­`µ‚Ù ;v€Ù̉C_)Å¥a·ÛKKKN'm»¯¾PUUo½õ–¯£©ŠÅfùÆkÌž=›£bå0.ÓÊã€eSS.Êü`¡ˆ-[¶@UUWYTKI}ÔÞdb¨†“újAýõ•E\_H’üÝï~³fÍJMM¥Eé«ëîîütJJJ¦OŸýýýAeä?8BcñâÅøü>/éa{æŸSúŸ“©½ÉÄà†Ó¶ã}@úŠ!®/uuuÿøÇ?bbbŽ;–@û–ÒWwãÆ À·‰øCD||<à©âqÿþ}üǬY³ð8ô+W®Ð“rˆ”’ë׋¦„¬_))ôìÇ‚¾¢Š{ñâÅ7À¾}û üPúênÞ¼ ¸]åÏÀÀÀõë×!øæ6Xð¿ÿýïñiiiðË/¿Œ' ÔrDH“‰ño8)˜~‡ôOÜ{÷î•––ŽŒŒ”””üñdL3®ïäÉ“€vÁË}:2::úꫯâÇãt!äõz:d4àí·ß¦æ¤`S&%%!ÄtN©}&žƒúë+—¸$I–––@VVÖÐÐo0¾EQúðð•Á`É8„Ðýû÷¯_¿ÞÞÞ~àÀ‹/ÀæÍ›_zé%Ž\^¯whhˆí[£ÑHþïÿûÙgŸ9Žk×®ýë_ÿº~ýúoûÛ]»v=óÌ3T|vâv:Cä‹\Å“££H_iÄ­©©illŒmllÄO32¦¯Û qqq@›(pè+55õ£>â˜=ɳmÛ6Z.Ú`ĬY³þö·¿ýïÿóMãr¹ !.Nk/ù´qF#M_YĽpὪ­­õwšo«9¦oBB€³gϲÅŽ5Μ9sòäÉšššÒÒR\׎ú,îªuèQÝ¿ÿ—_~ɯ¡a6›§M›íííx Ѥ&ø&…¶6hkc¸w7055"G*55ðàîÃ8ìÇÎ__‘Äå˜&Â¥¯.77¾ûî;ž9gΜ¹wï^ü÷ªU«l6[P;j‹ÝnÇ[pè¬'Ll"íÛ‡˜‘J‚ÃûöMØÂQ! (}ÅwÞ¼ywÙÁifÏžÿÝ¿ÿ¸¾gΜ€¢¢"ßF˜{èËëõ.\¸'X¹reøm>‡_Ùeddà-¸‡:yòdàÌ´.>Î8}Ï2ùÍ?ò×W9â2Eé`R[‰===Ô],Æõ¾Bˆ~ttÔ#U‰7lØ€´Iq‚NŠcË"†¸lЊòÕB………ÐÜÜLe=BhÏž=8ÍôéÓïܹ~ô3fÌØ°aéS§nݺ5<<|éÒ¥òòr‚ ࡇ‹…ž:u æÏŸÏ¿Ø1°AUÝpVWeJ š¾²ˆË­(_}ŠcÅŠT>ÑŽŽâÕsÀb±ÐÆ«BˆXxøá‡;::pš+VÀ®]»ø;––3*Pƒ§é+‹¸lЊòÕ—ù±5>Ñ#„¾ÿþ{j&Û|fô{÷î]¾|ù¯ýk<í%11±¨¨è¯ý+u¿U{l-4húÊ".¾EÑôÕö Ô¨¯¶DBT F}µ…e¢5ê«-Ç-¨N_mÃhAuújK¿FêÒW[0;ºP‘¾Úk¢ 髽œ%êP‹¾Ú+­¢Uè«ìr¾(N#”¯¯²_ŸÊùzM0Q¸¾Ê~é´†È(YßÖD ~•»† (VßÀÖD¹Ýîµk×âY½Ó¦M«««ð®ŒÇã9tè¾O¥×ë+**œN§P…kðA™úò²&¦££ßé€ôôôÚÚÚ0k˜Ãᨩ©¡žÌËËëëë §@pPš¾AX!D’d]]ÝŒ3ðÎâââÊÊÊZ[[ƒªd.—«¹¹yÍš5111¸œ¬¬,¼nPÁhŽ¢ô%ï5[Î/ÀIDAT¥¹)H’ljj:xð`kk+Þ¢×ë -Z”™™™™™™m2™ŒF£Éd²Ùlƒƒƒ·oß¾zõjwwwggg{{;~6™ ³Ù¼nݺââbê04dG!ú†bMŠ[·n>|¸¥¥¥½½9:î‰'žX²dIII Ï%ï5dA^}ò&ÅÈȈÕjíèèèíííïïïëës:n·Ûår%$$$''§¥¥¥¦¦æåååææ$%%…¿S ÉEßÿ]Žy,Þo‡(IEND®B`‚quagga-0.99.24.1/doc/fig-rs-processing.png0000644000175000017500000023426012476520570015057 00000000000000‰PNG  IHDR]…tJsBITÛáOà pHYsÐй‹çŸ IDATxœìÝy\Tåþðï9³Á0þ Ë "(.l˜šW#S£Ô_æRJ†{YŠIiÛ ­0o–•׺®å–¦¦eš[.e*ŠÄ"« ÃḬ̂Ìz~œ`fàû~Ý×}Îò<ÏÊÇç< AQ d~äryBBµk×òòò²³³ ^¾¯¯¯··wDDD\\‡Ã1xù!„P¯C`.DfèìÙ³111"‘Èu …Â;vDFFš .„BÈœa.Dfçüùó‘‘‘Ey2™q¶¶L¦Ák)R©®56&ÔÔªTAœ={vÒ¤I¯!„êE0"ó"‘HE"Ñ>“ƒiäê4k++÷J¥B¡0--ÍÚÚÚÈ"„BæËØ¿vêœ-[¶ˆD¢`'Áø¡H€‡`G$mÙ²Åø"„Bæ s!2/ýõ¬´±a˜ªFÀJmÕ!„P¿…¹™…B#ØlSVJWWRRbÊJB!sƒã ‘y!ʽ¼L\¯SAà„Býö"„B!Ì…!„BˆÖÝ\H´2mÚ4ƒ´LŸI’´³³‹ŠŠzðà‘ªËÍÍ%bæÌ™F*!„BÈL`¹àS§Ny{{k¿´²²ê~™úÔHQT]]]VVV||üÒ¥KOžøàƒ7Ž?bccóóó“““Ï;wìØ±­[·jo‹‹‹[·n݆ Þzë­èèèÕ«W'$$9räâÅ‹ú4àܹsÇŠ¢¢¢¢ª««ÓÓÓ322D"ѲeËÚ9ߺ‘-ìÛ·oĈC† ™={ö… Z|:Ô>‚iÉó[òòD“¥ÃC2()ꧺ:c×…Bõ1Ý]¿^m®9mAìܹsáÂ… P(lmm¯^½ûöíÛ´iSjj*}Û¾}ûæÍ›§R©X,VóãÝ»w·~uKÄ•+W|}}5MEEʼn'6nÜxøðᨨ¨ëׯ‡‡‡'&&†††ÀîÝ»—,Y"“É’““užg³ÙÍÙ‚J¥òððxã7Þzë­”””ààà/¾øbåÊ•Ýùvõ7”ªAük¤F^¥=Ãq kÿÍrwÖ/ÌV*#Š‹™¡¢¨Pç´««þÏâú…!„Æfdd´5¾0""‚>‰D ô—™™™ÚÛè°Èd2[·eܸqôMhhè‰'žzê)HOO€Ù³gÓK¥R¥RYQQÑÖy77·æláâÅ‹b±xüøñ¥¥¥`À€Ä\Ø)t—¡$u³öŒ¼òš¢¨Öúk+‰²Ùlضm›³³³ö¤““S[çÛ¯…ž‰Ü<5Þ¿?//¯ùäkÔ!«A³eY»šw‚qÒ¡à°LÆ#Ékëkç×Õ½mkkÂB¡þÀDëZ{xxp¹\ºßRSSýüü ^KXX”——l†Åbµu¾¢êëë;¶sçNê¡üü|8xð Á›Ý·iG¶fØq‡WJÔêVV–1—Ç€#2Î=A!„ôg¢þB‹µ`Á‚ØØØíÛ·K$’øøø+V¼??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF[çÛYjñäÉ“J¥²ùrÖ^^^cÇŽ=pàÀºuëºÐÙùàÈÐ.~ª¾ÎP}‡ôKä9<<ÅåÚ‘¤H¥ºÞØaa¡!ÒŒox¾ó ¦e—›Bõ^¦ÛoóæÍB¡0((èÉ'Ÿ|þùç4PoÏž=‹-Z»ví€"""¾ÿþ{z&A[çÛ²ÿþ¨¨¨ Y¿øâ‹éééôtdXھî=.Ñh~©¯Ìb…p8À&ˆ™<<œž¬?iÚVñ©‰²Œo)eçD!„ú€îÎGFzÂþB}pœÂ'ì…ÎÏGÞ'•®ª¬|ßÎîÕ‡Qþ®Bñ¯¬H2C(´Ô£—ž\|xý%É¶á Ž¶ò™K°xj B!Ô{a.4Ì…íÓ¾GîÚ:5SKJnÊå:/mwrš©ÇÞŒ-r! Ó!B¡~s¡)9:’Ò(écî€(ÛQ÷l{ E–µ»ùR5-´YØ…\˜¯TŽ*.摤€Áh~¾V£)W«'XZvqé°:–ü®QÔ¶¸Ô”}çL£ïýBõ Í;Aý¥jeíÒyÉPëÔª«€wíìòùÍÏÿ­P<ñàÁ円RµºEdl‹Ë”³²ì}uÙ{5 ‰ö¤FQ+IûBvo/oðL‡!„ú0ÓÍ;AýS]î¡‹=Žð‰=Oìé~(Ô–ÉX1½ÕËâ¡lv ›­8ª÷ì‚ÅãYê<åèk$Ûú‘Š5’´/ħ"eßR*Üd!„P„¹QëÎB&BÚŸE*ÕS––v¤ŽæÙ<üPWשѤ>é0ó˜Bõ1˜ ‘5ï,4x"¤ÑËÎâéž2ÓÊŠI EšBÑÙ’›¥ÃWu¤Ã»Ÿc:D!ÔÇà¼3ÒÇæPªñ¯‘yU§Ævm>r÷ÑóNÚúã QÊ겿¯Ëþ®ù¸CɶåùE[ùÌÅq‡!„z;ì/DÆR—{ˆe=È}„¦G²xü!ËšúYÌniê;üõ)Yæì;D!Ô«a¡écý…*IÓÚ§³O™gas¥¬.û»º{ßi”Ò—HŽ]Óz‡L®1‰Bö"céB(ìH?d¹óÔsü¡+ZöÊ«%w·ˆ”eî Tõ=ÕB„B¨k0"Ô$‹¯G:܉é!„P/‚¹¡®û'Y®+~†é!„P/‚¹¡î"Y|þИBõv˜ ‘y™0a©T¦¬”®nøðáÝ)äÑtøÈzŠÿ¤Ã¬]˜B™-̅ȼ°Ùl¸Óùe¨»ƒ®ÎÕÕµûE=L‡çùC–éH‡©ÿy˜º_B!dX˜ ‘y €­µµjSÕ¨ØZ[«­Ú HŸ?ôUç)çÚN‡Ob:D!dnpýB3ÒÇÖ/ì‰D(‰ðù›Œý ÀÚÊʽR©P(LKK³¶¶îø™ÎV¡ÔeW—ý½F)kq‰äØñü^±4›`Z¼^„B¨³°¿™kkë]»v±W* +*:,“i¬a‘JuX& +*Ú+•±k×.c„B ÙÖû—êê;Ü,þ5R–µûBõ8ì/4#Ø_¨uöìÙ˜˜‘Hd‚º„BáŽ;"##MP—F!©ËÞ[—½OWß¡=Ïo!ö"„êA˜ ÍæÂæäryBBµk×òòò²³³ ^¾¯¯¯··wDDD\\‡Ã1xùí Ó¡,{…é!„9Á\hF0ö+Emݽ½²œý˜B™ _ˆPÏ Ù6üÀ•.SÎò–-ÇVý3îPÝØS-D!Ôß`.D¨'é•ïíÁtˆBÈ0"Ôó´é°¸e:l¬”ÜùÓ!B!À\ˆ¹ Ù6Ö¯c:D!ÔS0"d^I‡L«æ—š¥Ã½˜BæB„ÌQS:œÚV:Ü„é!„Áa.DÈ|‘lÛŽÒáSu÷¾ÃtˆBÈ 0"dîþI‡þ‹Z¥ÃŠÚ; ˜BæB„z’mk=ì =Ò¡¼§ZˆB¨·Ã\ˆPo¢G:Œ¬ËþÓ!B¡.À\ˆPïÓ”§üÆóÑ‘o‚é!„P`.D¨·"9vÖÃV=L‡Üæ—ètXöëS˜Bés!B½ÛÃtx¶u:T7–?L‡û0"„êæB„ú‚féð]éðcL‡!„:„¹¡¾ƒäØY[é!„P×`.D¨¯é8žžŒé!„Pk˜ ê›þI‡~ [¦Ã†2L‡!„ZÃ\ˆÌ”\.ÿðÃ'OžîÙöô ³gÏÆÄĈD"Ô% wìØi‚ºz–F^-ËÚU—{R5´¸Ä°tæùÇpþÁàôHÛB™Ì…fs!íüùó‘‘‘Ey2™q¶¶L¦Ák)R©®56&ÔÔªTAœ={vÒ¤I¯Å iäÕ²¬u¹‡0"„js¡Á\‰$00P$-àó798{ ƒ`meå^©T(¦¥¥Y[[¹Bs¡‘Wɲva:D!ÔŽ/DæeË–-"‘(˜ÃI0~( ÁÁ!˜Ã‰D[¶l1~…æ‚äØ[_ã2å,ÏïeãS>*;=¹.çŽ;D¡~Åð¯çꎿþú VÚØ0LU#`¥MtY]u¿B§CžßÂÖ}‡ê†²Ú”²ÌÿñüqÎ4Hß!AÝ/õ1øÎ !³‚ý…ȼ( Áf›²Rº:ºê~¨£¾ÃM}‡š~úýA¡þÇš_»”ʽ¼L\¯SA`×…vÜaÎAJÝØâÃ҅翈ë=“ õMírñ_—pí—ôÜ~õ¾µcÕªU€è23Ø_ˆúÇ?}‡ƒ£ †EóKêqmʆ²_'×åÔ³ïP^v½.{ŸqZŠBÈðú~.,))‰ŽŽîéV Ô›Ö#Þ4H:”¤nVVÿm´–"„2$Zo1mÚ4£ÖÚ¼.‹rùòåæ7äååýßÿýŸ££#I’ÖÖÖÁÁÁÛ·oo§Àêêê7ß|ÓÇLJÉdZXXøùùÍ›7ÞÇ¢¶¶vïÞ½™™iðaïÚOÁf³‡þÓO?¶|„z^é0÷PûéÒ(«þZ­QJÜX„BÐ4ùÔ©SÞÞÞÚ³VVVÆ®˜®Q£ÑˆÅ⯿þzÆŒ%%%l64ÍäÉ“CBBNœ8acc#‹oܸQYYÙVQUUUááávvv ¾¾¾µµµIII§OŸV©TÎ?“(œœ>ýôÓ®µö½÷Þ[±b…‹‹‹ÎâååUSS³k×®yóæ•——s¹ÜÖ·õC×óÿzl`xÇ÷!óF§CžßBYÖκÜš;T7ˆk“ãÎYžÑÖ¸Cu]QMâ;ö_˜ªÉ!„ºˆ (Š ˆŒŒ ÓÕúh‰ÄÆÆ&;;ÛÇÇòóó½½½e2™žñôµ×^KLL¼|ùr󨕙™ÐÍ¡Ím}‹šŸ¯¯¯·²²ºw¯o×jécóNÞÚÿWþŸ/‡ÇyëÿÎ;1gšÆÊÖéÆà Z§CÉÝ-²Ìô±MÐ:žï‹€óNÐC8ï!3ÔÁøB‚ <èîî¾gϨ««‹ŽŽ¶²²²··ûí·5ö¶sçÎr¹ÜÍ›7—””„„„°X¬Y³f©TªQUUE„ƒƒý¥ƒÁ¸pá‚>€¢¨ƒ®_¿^g(l®ù{ä²²²9sæX[[s¹Ü™3gVTTh?HrròâÅ‹y<ž““ÓáÇ€N«íS¬¨¨`2™:ûû§é#fTæ¯<¼|å‘å)EÉÆ«È©  ùÿ¼ '=x°µ¶V‰¿o ´p°±ÖeÊo¼Á Z¾Y®/­MŽ/;ýt]î:ß,Kîl1Ȳõy„Bæ£)–———6ÓüŽ>ø`ãÆãÇ€ØØØüüüäääsçÎ;vlëÖ­ÚÛâââÖ­[·aÆ·Þz+::zõêÕ G޹xñb[uSÕÐÐpóæÍùóçÏ™3ÇÎÎŽ>okk»nݺçž{îÙgŸýᇤÒöF&•””TVV†‡wâ}%EQQQQÕÕÕééé"‘hÙ²eÚ«ÑÑÑ2™ìèÑ£sæÌY³f ܼy®]»öå—_ê,P­VgffÆÄĬY³¦ÿl¤Ö! –åœÐ E”l‚t¸€ÏŸÏçÏæñ†±Ùi E|uõ{ÕÕÆ«®?#-éth5x¾®tø¡ÎtHiÛßpçsûþ\7„꽚Þ#·8«íØ'bçÎ .…Bakk{õêÕØ·oߦM›RSSéÛöíÛ7oÞ<•JÅb±šïÞ½»u7[‹Ÿ}öÙC‡YX<ò æäÉ“[¶l¹|ù²¥¥eLL̆ ø|~ë••åïï¯R© Ýdhß#k®_¿ž˜˜ »wï^²d‰L&c³ÙA¼ùæ› A¤¦¦Ž1‚þV´óY{úØ{dhT6ÌÚ9£ºþŸ|$ nÿÍrÞ#Ó¯€›?r±¡á±Ø–$³==;U¾Òê,Mc…4kg}î­wÌcpLþ ¹øÏæ'½!‘yÄš°È|á{d„ÌPÓ¿Ý322¨fšßAˆD¢†††ÀÀ@úËÀÀÀÌÌLímtXd2™-ŽÛråÊ•’’’’’’ˆˆˆ´´´ÖÙ4**ê÷ßðàA||ü?üðì³ÏÒ Û±c‡vpNNÇ€êÎô ¥§§ÀìÙ³ýýýýýýßyç¥R©}•¼páBº1lý¶ÜÈÈÈP«Õååå«W¯~úé§÷ï߯Kú£R©ZôYº¹¹ÁÃ`Êår1™L’$gÍšõþûï·†¨Ñh4mt………@yyùÈfX,VûíÔçeÇÀÄbq‡wö­» µŒ”3Š×**H€u¶¶,uˆN‡ÎS~k?’„:Üþ‹ÄÝ–BÈì´÷ª·‹µ`Á‚ØØØíÛ·K$’øøø+V¤}ôÑ?þ÷ý÷ß@NNÎÌ™3çÌ™.$ÉçŸ>fÌ:¶?zôè°°°ØØØÀÀÀÆÆÆÄÄÄ={ö\»vÍVW2ðóó›={ö믿N’äã?^__óæÍ3f´³,Ž££cRR’P(¤_[7———GQ”B¡())Ù½{·»»»§®1mc?{¬ÃïÃ~%óaìoé¿~õÇï>Ò¤ˆ’SDË;wØ¡ðâb @FS¥VäpŽ ŽXÕÇú“q!žaAÂ`/‡xô~‚aáÄX¢ªÍ–—]oëSf{åZÕ$S6 !„P‡:‘ `óæÍË–- b³ÙK—.]¹r¥Aáææ¶nݺõë×/]ºt̘1`òäÉ'OžüôÓO%‰½½ý´iÓŽ?ÞÖãNNN7n܈߸q£H$b±X¯¼òJë §µgÏž>ø`íÚµÅÅÅvvv!!!Ó§Oo§…ëׯ‰‰ihhX´hQ‹KS§N¥ØlöСC9ÒþÀJ¤“6v¹úÝ1­F­¾­P„p8œNu¸’sùJÎe°çÚ C‚=C‚…!¶Â.·ªRT$W__£nè ×ÜÃ2ßÇ*=§nˆiZ…BHÎ3 ýú ¥Úþ«u̯ªúÝboAÂà/gýº:Y Óh²”ÊýRé~™,€Í>æââØÆDu…<þŸÑ­/9ó]‚…ÁÁÂÐ aˆÀZ ÃúJ–¹K’öPj}îÖPŒ åQÕJGc7 ™'œŒž-d´ï‘¿„ÿv¹Àš$Ã8œ0Ç•ÉÜ\SóNUÕönÌ(¢•IÅgÒOŸI? î¶îAÂ`ah°0ØÁ Í?4òêê›oËK¯êÿ=Ðð\ùô¢’êÓ§Oµ³Ýe¯æèèèîîþôÓOãº÷!3‡ý…f¤—®_ؼ+ôêjCÊÞÚ¿íŠî%Á¡ÕІY¿ÊÕê!"Ÿ$óô[Â.äЭI…·R‹o×):žT>ÀÞ+XìälcÙ¯ç¸èùîX§äB^Ô›‰ýá/"‚ ¢¢¢žxâ £Ö"‹Í'd·ˆ±¿!3„ý…ȸ• oíÓy©ûsMÚaM’ÐØÉ_9/„Ìy!dŽZ£Î*ËL%%Þº[œÚ¨j¹0í~UÁýª‚ãwŽ’éí8(H" áÄã´9°µ¯"9vãv4;¡óÛN €¸¸8í)Qaá¡C‡˜,æÀ¯ÚÅqt6rK{†¼¢¬êöÍì]_žã º¾:¥(9¹ðVŠ(©°ºPçýʆ›7nÜ+o¤ûHz“oÇA˜Bõ Ì…ÈX>'t^O·ÂÔì¸vÿ<ñ_ƒ'@¹¬¶Â¦MV„!ö\ü+¡^¯±±qݺu_|ñ…F£ŽÁẪpŠÒTTˆ+*Ê333:ôÕW_ÍŸ?ßP…£> s!B=†ÂÛq·ã ÿ š¥¡4Ùe÷RDII¢[©Åwêõ:)ªÕˆNÞý‰ÂËa`08D:RlmamÚ¶#„ ã7Þøæ›o‚á9b­Û ¾—+ 4’òÄ¢´­ÒŠä 0ŒyóúÝÈo¤?̅ȼL˜0á÷ß/R©<˜¦ûá,R©`øðá&«±5’ ý\üý\üg‡ÎSiTYâ z“•´wå*yëû) ò+óò+óŽÝþ‘$ÈAN>ô&+#ÛͰ°Ìüú“â_ºNœúàì‰1;bòø@Q0hÁòŠÄ?1"(**–+‡©f°ø¦©ÑÊn(A0x<žiªC½QßÿÝ€zkkë]»vEFFî•Johˆ³µ°°0Æ;å"•êZccBMM¡JEÄ®]»¬­{ÓÔ +¶U„÷˜ï1 i”Ü%'‰n¥ˆ’ *óunÄ'WÉ“ o%ÞúߟÀes‡»† C|v“•3é§'yÚ€vÙø.h”ŠºÂüÜï¶eïþrð¢U5i)pï[ ¾è¾º¡žecgí;$åý×ãŸrý×&ÏD¿ž‘HÔ(Íç;…˜¬F–…#E©þùg“ÕˆzÌ…ÈìLš4éÌ™3111…"ÑŠŠ cW' wìØ1iÒ$cWd<ÖÖã|ŸçûTÕW¥ˆ’’ “’EIE5"÷×+ê¯çÿu=ÿ/à[ðG¸…x† C:zw“•‹Yç3Åé+ŸXe{ú‘,6ŸÏ˯¥¼óÚàE«&ÓÂÙÕëùôUÇ‚ É‘ÿþ¼êNbé…_KÎÿ¶ewÏ6õK¸³2#˜ ‘9ŠŒŒÌÎÎNHH¸víZ^^^vv¶Á«ðõõõööŽˆˆˆ‹‹ëK›Øsí'ú=9ÑïI(“Š“EÉÉ¢[)¢¤RI©Îû¥Ò?r¯ü‘{l-mƒ…!Áž¡AÂO;Ï®5`¨ëÐ×¾-•”~0åC –e—?ˆÁP”¬ ‡em!á÷íSÕÉøƒü@ÝØ ‘ËÕŠF‡àǬ}ü¯-š©ª“‘Lhr’Ýw~*tºüÂDKWQ[öÑ”KÒÖW&_×9禱¼ôÆ«óp:B}æBd¦8Î{ï½×Ó­èÝœù.“‡mXTaÕýdQRraRJQrmñ•ËÊÏfœ9›q\mÜè€$ qâ9µ_Q€`(IJ“)ÎXr0æÓéŸy9 4üçéH[=[Ž¡cCÇ4?úéÿ¹ƒ ã6¯aR[[{üøñ—^zÉÒÒ(=¯ÎJ?MçÂÒßÏ8…?Qrá}éÁÙ“¥—Î(ª+m‡Žô_ñ–¼²Œî/¤;‡½ýqîwÿ•WU¸?õÜÀ9¯£m½ Á´¬¼²ˆm?Üjð|’mÛÓÍéûDg,\ÇÌ.®ÕºiÓ&:ÿåååM:5##ƒ>ïèè¨!§Nòöö¦(ª®®.+++>>~éÒ¥'OžìZ“ÚG§ØS§NÕÖÖÚØØ£ -Ì…õ/ì½Ø{M1SCiò*rSDÉI…‰·‹o×Ée:)©}pªöÁ©´ŸÀÓÎ3ˆ~×ìlǵk}3ÃÚyÞ¯*€RIɲC‹7F}, 5ægê³ FFFÆ–-[^yåÃo-˜ðtê†7}¢W ñ•³þ¯¾­Í…ŽacÜž|F)“^‹™î=oq‹ÅWÏmøª¾¨à·±˜ €°ò_õÇ2Yö>+Ÿ9¼ÁÑ$GÇŸd( Gñ/ÿ²¼€ç;Ÿ`uzzµ››[óŽ=ÿ.´ÁÛÛ[û`hh¨@ ˆŠŠêB9¢(jÿþý“&M:þüñãÇ£££Q‹VÏ Gõ’ }œ|Ÿ~á“ç6ÿºüìÿæî^6öÕQ^£ÛXX]x"õøû¿¬vû”ßÍûâ÷Ï®æ\i±³3ý*™&“K×[u&ýW#~Œ¾‹$I(//ß²eËÝ»m¾äí2kߎ£sÙ_—ªS“¬x³íþÙq›aa)¾r®øÌqШZ®¦î¿l-“kŶuÐ(u,´Þ?Y¸Žc;Œ Tu²Ìâ_#%©›5òªžnTŸÅv eÚøIÿþZüëS²Ì”ªÁ€…×ÕÕEGG[YYÙÛÛ¿ýöÛô¾Õ²··W«›Ö”-++›3g޵µ5—Ë9sfÅà ”m'âàÁƒîîî{öìi]rRRÒ½{÷¾øâ OOÏà¶ s!B€$HAÀܰÿ3ã‹Ó+Îm›ýmLÄâ`a›ÉÖy?T^Eî)‡×\;í¿OÅìþúÊ—×ó¯Õ+ꇺ6¿S©V~t&~×_ÿÃi—EçBËå»wïþí·ß(JÇ"D]G‚'&—þ~ºäÂ/®§iOSMò;¯j” ·'ŸÑý½tþ}è«ô¥ª—eíŸzRrg“¦Ñè‹*ôOü€% QÔHî~&>ýT]ö÷”ZÇ–¡]›ŸŸŸœœ|îܹcÇŽmݺUŸ§Î;Go¦JQTTTTuuuzzzFF†H$Z¶lY;çi|ðÁÆÇߺä}ûö1bÈ!³gϾpáBi©îI„†‚ï‘B-1Iæ0·áÃ܆/xl¡B¥H+¹Ko²’Qš®Ò¨ZÜLh ©Égf‰3ÝÚÏ$™ì½ZÜCµû¯ƒgÊ>œg¢ÏÐ'hs!PuæÌ™âââyóæp½Ë¸'óîà8¹Ø ‘W–Ñ'•µÕõE÷GS××€F.'ûМ}ãá¸D°ƒ)ô—”ºQvoo]î!®÷ó<¿W–Ω¥,÷P~Ò¿ ’õ“mÜ¡fæŒ#òTV¥€¦±²öö'²¬Ý¼€%Ü3º3H¡P|÷ÝwW¯^õóó€wß}wÓ¦Mo¼ñFë;ËËËmmm5MEEʼn'6nÜxøða¸qãÆ7=<<`Ù²eK–,Q(ÉÉÉ:ÏÓ»¿ÆÅÅé|A¬R©:D7`öìÙ›6m:|øðÊ•+»ü;„¹!Ô6“MO:€eCjñz“•{â,z“+3â¼{C£Ø½¾Ì­¾«Ê­ÈÑY”s¨#Ç–­% pÚ¦^Œ–›AÞ½{—nèäÔÁ =±mí/Yöµ'šeP¶­½Sø‰«8„D8GL¸»iýˆw7¤º>?ôÕÊË ¸¤Ôòºì}õyG¸gðüb\A7«(/8”FU)úÕe‰6Ð3Oü€¥U¾ªýRÝ ®MþP–µ“?d9wÀ3@te/U‘HÔÐÐØôÒ#00033SçãÆ£lllBCCOœ8ñÔSO@zz:Ìž=›Éd€T*U*•m§G:FDDè¬åâÅ‹b±xüøñ¥¥¥`À€Ä\ˆ2 –,ËÑ^öz drÙ¢”$QRŠ()MZòÄϾۀÄVQæV/v¯»Õ7Xµì\´ñ±¾¤97†Ï….N$ìÔjµZ­Öh4ôÿÓZ«Õj…BÑúq±X¼eË–—^z)  ;ÍÐNÙ<ñ}`á$h:ICÞxWçýÿÜóè1¢qœc;…*Êoµ8O©åu9ëóŽrNçùÇ0¸]\ͤAš'«L%E©+ Nôó\háöËÖOY“Õü¤º®¸&q½,óü!+,…“¡“ ì7金¢ÚZ(*##C焺ÿoÛ¶mÎÎÿô;99µu¾ýöÐ3‘›§Æû÷ïçååy{{wøYºs!B¨+xÞ˜AcÇ  µÿWsÑõ€x{"X×°­kØ>é¶ µQˆÝêÅîõenuõ¼¦Œ(ÉE͹1ä8;°o§|SJ%ù‡v^dŠ=²×¬Y£ç,–îŽÕ†††;vL:u„ Æ[ÝЀV?ïh} š%RPëç9!IÝ E( €zøÿ (úàÑK”ö¸éNèJ M÷´UBÓ^¢ÞT‚¦Í¹8”FQ—ûC}þ1ËQü€–³¼õQ‘ÿ‡­*¼û™¬òN£´À‚ïÕÙB ”Aô1ÑêLûWµgë{[«3mUÔñm–žÏ´È…4•´ úÆ›²ÌoùC_³pÿ—þƒa=<<¸\nzzzPP¤¦¦Ò/”õååå‘‘‘úœoG}}ý±cÇvîܹpáBúLAAÁÀ<¸~ýúNµJ˜ BÝeci;}ÍòßËwfý£ùy~-›_Ëöɰ™µBì^/v«/s¯¯ã5^Ö\Eè~ob—_˜È±w’¤”J>7ÇcÊÌÖ·QjucY©¥«»º±¾äü/¦É…úkg"¤F£ùùçŸ‹ŠŠfÏžM÷C˜¹ÕÿçÒüŒÿ³Ž Ëêw{Re}þцû'd•#:÷ ¥®¸’Á´rñ')¿YSr¥âþIÀN¿Rd0J£hú§šA§2™emvÕµ•,»!ü¡¯Y¸ŽÓ狵`Á‚ØØØíÛ·K$’øøø+VtªR??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF[ç­¬Ú|yròäI¥R9sæ?wyyy;öÀëÖ­3Ò¿ q>2BÈ0ÆÅ/`ûµÙÈ“°eØF\p{î;Ÿg÷ùŒºè,μ;$ˆK^üð‹Ç¾>þíCV½—÷ývuC}ë{äUå7ߘo¼6tS‡ d¤¤¤üç?ÿ1McºÃ°³¨ûŠÒP”ºSHÄ× bÏ©$ÃÂià ¨(8ÑÔß©7’²t1’²:½êeçÉËnèsÿæÍ›…BaPPГO>ùüóÏwa0ßž={-Z´víÚDDD|ÿý÷ôJmoËþýû£¢¢Z,dýâ‹/¦§§§¦¦v¶UzÂþB„a$—$‰Hz²HÈ­ëà/ž„œؼg[$)J7~Ãx})FÝØÀ°ä¶ØÆ#wï6HZ»Øû¥¥Puû¦YmãAQI’í¤C¡PcÊ&uEAoxãmi)œÌ²œŸ"èÄrtå?mÝ&0Ù6òú’Š$k§0ý !û[*|ˆ`Z­f¢øûû·Nf\.wïÞ½{÷¶·fûyŽÃá|üñÇü±žçÛ*íçŸn}rñâÅ‹we‚ž0"„ ¯"÷ãýï:±+\„¹|¢£þ!Ê’©|Úëâ§{ŒÛ,ŠRJk ~üŽë&dÛÚC«m<-X^‘øgȦoËKÁ,·ñh'¾ôÒK½â%2üçHùäÉOCÓ[K‚â矡(jÓ¦O  ˆ‡ÿOÒÂúàÑK„ö¸éNÐQÂÃK­K ÞTK»%ЀG/µ*¡é]BMÒ‡ÅçtÒÒ#’?d9Ózˆôÿª•Òêâs–ÖƒxÀ$ÙŽž)ÍÞWQðS§r¡JM _HW©”@©Ò¥¦( }Lµ:ÓþÕfgšÚ¿íá±>÷ë|PG±”Z®’æµÛ#MX¸ç,aÛ×ÿ»ÔŸa.Du‘Z®,¿[Pš’#JLÏ¿‘Y§ïKÊÑR1Õ‹â7ÐÜxu0,,mü‡¾O÷VÑÛx4”•@ÛxL¦±·ñ`0 ƒ$I’$[h¿¤ÏˆD"•ªå´n?~|TTT‹¹“ælËåžc‚šŸÙvbl;ñrÏ4È8TÒ‚Æ:çhîùC_eÙøv­äJÑoµÜiàtí G¯¥ÙûªDg¼‚ß%ú¥¡€ ™ÚЫûkS6¨$¹º¯¤¥û$^À–mW¶¹ë·0"„:AVR%NÉ'甦äT¤j”M‘…­÷`eµ­r¢XF4£¿ÚoáôÈZqô6OÏp{ò™û?~×úÓlã±ys'Ö\·n]‹3$INŸ>ýñÇ7h£aÈ2¾i5à°p›Àº¢›é¤¢à8ÞÙ\x瑟µª¾ºø¼ƒç´6žëËÔõêóŽê¸@0,=§ðý=ì—E€¹!ÔRU‘^XšœCgÁºÒê.EõsUJääëj½ÓŠ…a¶Ï2†=‚gþüùC† Ñ¿„Ë/LìÎ*ƒå¥7^gáäBQ”F.gòxƒæ/w~Œ.yôWû@{¥R1,-=¦Ìt‹|¶Ë5ö^*Ya}á©æg,\Çñ‡¾Æ²ëÄ/e…ÒŠdÓŠõè¦)j¥DÙXY^p¢æBiúvJóÈŸɲð Ï“çÙS­êí0"„Zª/¯§ä–&çˆSrËÓ Ôr½^ª²¸§áA>õåµ™?^myÕÊbkî©Ô:‘¾+wAëmöö t?"êƒ1f̘3fjê±RR[_tß!h48?Vðã^¥¤FV3òƒ-ô”m‚ÁÌÿaWá±ý0t͇<¯AÐ<ö?6xñêÖÅŽÿá‚F©¨+ÌÏýn[öî/Ím磣4ü€% +£¼â§—-t ûռÀ©…w6Õ×Þ««Î´²ëÖ–Ù½ˆ,{Èr+ßI¿§ÛÒ×`.Dfçüùó“'O¦(ʓɌ³µ°°ð`þµH¥ºÖؘPSS(Mž<ùìÙ³“&M2x-=N^['NÉ-Mɧä–ÝÉSÖ5êóƒÍt:À%ÈGìã4ÈÊ¥ÿp3K[ȸ üfà´Ùn™0aBxx¸ *j¾²îÀ|¡é¥$½²#ýb½üú•¬íŸ6–•rÝu ê'Ylþ ?Ÿ—_Kyçµ~— ÒH¡údШOÚºÊâ8Œz>ÍHU›-Ûàw›žD††¹™‰D²páBŠ¢ðù›Œ÷çރɜÅãý·¶²r¯Tºpá´´4kë–oE{JCÕä>(¥—’IΩÉ/Õ³SÐÊÙÖ%ÈÇ%ØÇ%hS ƒÝÅ¿ÜÈ®“íSÿ}Õe$.Ñ]…,k®Ç€ªÛ7G­L¾n;d$ËÚ–7зè—#^Ï/ (J]_Çäéîƒqzlœ,?;íÓwƒ?ÚÆäê@Q²‚–µŽ×†B£Á\ˆÌË–-[D"Q0‡“`ÌP¨E$88ÜU(’E¢-[¶¼ÿþûƯÓðÒ†²;y¥)9â䜲;yr‰Ž€[#™ Ç!ž.Aƒ\‚|\‚|øîÝo ¥Ö”Þºç<Üû©ÿ¾Ú©^FdT7^«=ýÏ®€×Öemß\px/ÓŠçÿê[0äõw2·mzpöÂ;pnŒsÄ„¶ŠòzáeY~væ×Ÿ®ù°E”F£n¨gò­/‰5Þgé‹p÷hdF0"óò×_ÀJ›ö†°`¥MtY]uï@Q5ùbñízYÁ꜔F¯_-–ÖG r È´4ðŽ#•™¢ÿ9~c4ƒÃ2lɨËZÏ­æyù„|òÈÜpKW ø­:o1;› Éaë>iQ²ùLßî]„B¡ßKÙPn²•AN›6Õd5¢^s!2/%%%0´[¾ÒÕÑU›-e½¼ìN½¬`ÙíÜÆ™>O‘ ÒÞÏC;RÐÚÓ¸+œYØóÿµy‘Q«ÐŸ¢¶:ëëmˆAÈÜxxx€²´±Q®VJ&™?QWý7Eid2½þö@ýæBd^RSSÀMÚAWGWmV$…eחΩÊ*Ò¨5?`aËsÙÔ)è<›Å5Ý*<„ D«®…©S§þòË/Æ«µyL&søðáŸ}öÙøñÿ¬¡Ÿ——·víÚK—.UUUñx<ŸÅ‹/]º´­«««?úè£ãÇ0™Ì„††îÚµ‹ÃáÔÖÖîÝ»wÏž=™™™”~kv诪 [ê3Ô UyZv¯‘º²½#ÛA°K° hí 7‚ìË‚íð_—¶é®‡—cè§ðñ'ÜK<öÙn†…eæ×ŸÿzÔe|ÓZå­/ ø¿ù-vøà\‘øgȦoéåútì â³ð5_=´á«ú¢‚;Æb.DÝ÷ùçŸs¹Ü/¾ø¢ðΦÂ;›8VBí&ËÝGQEƒ˜žòÌçó¿úê«yóæªpÔ'5õž:uÊÛÛ[{ÖÊÊè;VÑ5j4±Xüõ×_Ϙ1£¤¤„Íf€F£™Z×Òz_ú¼ÿ²µ“ɶuÐ(•¦ø´¨¯³°°øì³Ï–/_þïÿûÒ¥Kµriù-–ïèèäèè0vìØO>ùÄÞÞ#€Q¯Öô·¡···¿¿¿)+ÖÖ8dÈ›ÂÂB¸ÿ~vvvJJ O'NœØNQï¿ÿ¾ÝåË—µQlìØ±o¼ñF‹ÛÖ¬YÓµÖÆÇÇÏ;·u.Ô³êþ©ê^Ñío ]ù¬Ûh“þh™ J]‘^(NÉ¡G Ê´ù›G„§“K ÄÇ%ÈÇÞ×Àät!هЇЗñO¥}²Î}òt‚É´pvõz~}ƒc¡Q5å¶Ö—胮½= èIQý´¯‹Ï÷߉¤ººÚ€% ì§@úë`|!AX³fÍÆ£££ëêêV¬Xqäȇ³dÉ’7Ò[vqöìÙU«Vååå}øá‡óæÍ›6mZjjêôéÓ8ÀìhniUUAMËêÚÙÙ1Œ .DEEuø(Š:xðàîÝ»;ü¹oþ¹¬¬ìõ×_?uê”J¥zúé§¿ùæGGGúƒ$%%mß¾ýÀ–––_ýõ¬Y³è´Jï[ß|œ¢þU÷O/þëÎŽ~Ÿi« IDAT3'ç%¸ö7v:¼£P|/•^ol,T©(ÊŠ$] ?k$‡³ÜÚšmªI m,O+P5*ôyŠiÉv6P»×ˆ¥=n÷Ùò¿.Ù£÷ÛPTU°íÀ!$üþ±}ª:=EÝØ ‘ÖÒ÷·¾Ä°°l±ÃÉd€F!×ÖÒz_ÓRÔY[[÷—PïÕ”ØÊËËmmmµg›Jýàƒ6nÜHþ‹ÍÏÏONN–Édtÿ™¶o,..nݺu¥¥¥k×®=wîÜêÕ«ÅbqlllLLLdd¤Îº)Šjll¼{÷îš5kæÌ™cg×4xÜÖÖvݺuÏ=÷Ü3Ï<3wîÜ)S¦ðùmþ¦,))©¬¬ìÔVQEEEEÙÚÚ¦§§«ÕêçŸ~Ù²eGŽ4Í@ŒŽŽ ßx¹P£ÖTe‰SrJ“rÄ)9‘¾ëÓò=]è¥d‚}ü…$ÓdËx÷e×~ÏÛÿ?J£&H’ãà<äw€ëîéÿê[YÿÝD©Õ$‹í6FðÄSôý­/y=¿ åáO8?vkíâao}ÔT A´Þ!„ú¶¦\8nܸæg›¿^‰‹‹‹ŽŽ…BñÝwß]½zÕÏÏÞ}÷ÝM›6isallìܹsU*UllìüùóçÍ›G?xð@gÅÚãgŸ}vçÎͯ~øá‡¡¡¡[¶l™3gŽ¥¥eLL̆ t¦C©T ÚL©7nܸq#11ÑÃÖ-[¶dÉ…BAnœã6¶xªõ¾ ÚK-vA¡¾¡)fdd´5¾0""‚>‰D Ú>³ÀÀÀÌÌLím!!!@¿2n~Ü–+W®øúúÀÌ™3ÓÒÒZÏ‰ŽŠŠŠŠŠ*--=pàÀ¦M›îÞ½{á‚ vìØ±hQÓ† ÙÙÙ<ª««éÁúHOO€Ù³gÓ-”J¥J¥²¢¢ÂÍÍ .\H7†ÝÑ–]¨º¿ÑvjÏ6ÞU(vJ¥<’üI ¶úyÀdÆâu ¥¡ª³‹Å)¹¥ÉÙ¥)¹µbÐo\š•ÀNäC/+è8Ä“dõýe¡BõjøEE%Ô¢(ªu˜ÓŸ““ý¶úóÏ?5jÔ–-[ÞzKÇk@°zõê)S¦{xxÌ;wÚ´iôUGGG’$é™3gÎÔ³j:ðmÛ¶ÍÙùŸ=Áœœœ:û\]];[u?Ô¼ËPËPépŸT 1|~ëPØM I½øvÓâÒewò²}ž"YLÇ!ž‚‡#M³ùB4ŸœœyEÇѸ»v–¼¢ èx#„Ì\'~›zxxp¹Üôôô   HMM¥_(wSXXØ‚ 6lØ0þ|ú/•JÅ`0š‡Nú<L¹\.—Ëm^¬Y³ÞÿýÈÈÈæïy5 ´Ê²Ú ¼¼¼­:µžºH’dg«î‡Zwju?^kl€)þf̘¶þ¹?zôè°°°ØØØÀÀÀÆÆÆÄÄÄ={ö\»v­ùd-??¿Ù³g¿þúë$I>þøãõõõ7oÞœ1cF;«6:::&%% …BúÝqªÞîór‡ß‡iTäÃéY?]K™Ûñ#faù?‡ú|̺“ï«TàÃ2X»ôÖ®ï!¤C€§KÐ z¯¾Ž"è:³íâ2cw›Mœ81++ëþÑïÙ6¶ö#G™Ã·T^QVuûæý£ßÑþrc!3ѹ·o›7o^¶lYPP›Í^ºtéÊ•+ Ò77·uëÖ­_¿~éÒ¥cÆŒ“'O>yòä§Ÿ~*‘Hìíí§M›vüøñ¶wrrºqãF||üÆE"‹Å |å•WZd¸æöìÙóÁ¬]»¶¸¸ØÎÎ.$$dúôéí´pýúõ111 Ú¡]®é¤M‡zª¢ÀÊø]³–ö|ç‘MSFœ‡dZâÊD†a¶]\Æ`ìn3Ÿ¨¨¨“'OÒ+x›‚ ¢¢¢è¿BfŽ0ø¾pH'ýú IFÓQŠcÊaïöï7û—ghçm hçιööÀ[Pîå¥ÏýÂû÷)*ÏÓ“ßíhèTPÿMI0H{_w— : Ú pS-‚ØýzS\ ®g1ƒ`2ƒd0ƒ`2H&ƒ`2&I0™äËÑó5jUôü  Ð@þá`MùýA –™I—1ÐÝfÙ»¾zùòåFMHb±øôéÓEEEíìe2ŽŽŽîîîO?ýtëM`ÕªUÐÕÕÅBF‚$‘Yøç=òN¬çÉdÞS*3”ÊQZZÜsü0—`— —Þ,+ ƒ”Ù<=ÊåÔÒã>hÿWü¸9ñP ivÊmÄäy^>}Ùܺ¸ŒÁ4Ýf...ôÊb!ÔØ_hFJŽŽ¤4M;wqDÙŽúØxu5ï¿\š³»;Eýì1íñÕÕ×[ßpû§uÎ;¡µYHÏ7Ò³¿pueå÷RiŒµõÇÝÞô“î/Ä?Ý‘V ùæTA]£^[?Ó, Ù òv¹¸Ä|º¸Œ¡ýn³~ û 2CØ_ˆŒKÕ ¿³ãŒÎKÝ_§f.÷½TúTú‚•ÕHܰ§zY¿÷¢ßW'òDåz-ëÃÕ2 vq!„™ÀµTq¥í»ØbñBpíµ?.j\7—¶åpfóx Šú?±øÇº:U³Ž Y.½¢¢R­îN¨Sœl8ëçú= W÷­'™Á†Fc7 !„þ°¿QëÎBƒïƒ÷ Àa™lYyùzc›Í'I©F“¦P”«ÕÀ»¸Q¡i±™äÜ õªÔü–ÿhN@ð‰j“µ !„>0"#jÞYhðDHcÄ׎Ž/òxd²rùŸ Šâ‘¤‹5‡Ç›Íã92—‚ ¤JªøíVÙ•»r¥¦Û¬‰Jg¢Ðd­B!¤'Ì…ÈX´…FJ„Í…[X„[àôážTRÕøëMñõŒ*uGûÄp AHf¶B¡¹KÚ¾‹v>nOn]fÔDˆz\^IÝ©›âÛ¹5­ç•2H¢ELTÊëý¸é ÀAŸ!dŽ0"c±ì1rÑÓ=Ý d,Àß’_oŠ3EÒÖWíx¬È—¤ìêœuÍž¡®z?dá3¦k%B¡ÎÀ\ˆŒÅsü°žn2 EݺWóëMqaY}ë«{‹§Ã\Âì™ "ñÞ#3Kîþ¾÷þÝ‹˜ BÈLa.DéK©Òü™^u&Q\V#o}u €;e” ØÇV»e JýÏK䡸{Î|mšv"„êÌ…¡Ž5(Ô—îTœM*«­S¶¾:dê(A€'¿Åy•ºiV²£5ûÿÙ»ó¸¨Êýàß3 þ¯£‚  ¸"(h.I„ËK½®¹Dd.mJEYi7mÁ,l3oq©[¹µx3•4SoàŠ¦è .#²ƒ Ë0ÃÌœßc#²/sfü¼_½z gy¾ÏãŸsÎsž™äû’¶¥‡”Àä  %òõ¯§Š~;W¬P6|X„a($Àab˜G/wq“çêæ -¼eSül¬ðÝÀÜá;5˜—feeÝR«}ÆûÃyK­Ö•6ZÅ.¡¸By ³è•Ö©Îó øLD?ç ¡îîŽ-½~P£a‰h^¤¤§[ÓÁÌ r!˜OOϬ¬¬s*•1sá9•JWÚhÍœ¬XñKFAæ•;ÚF‹ZZðÇt‰ qs°¶ÚNFûð`בý¹é&r!˜—ðððƒ~RQ-çE%¢O**t¥RЬ]¹Uµ/£àÂ5yãÅ©íĂȡnr[¶õwÆ×ÃzÖXŸ—/_Þén' Á¼,_¾|óæÍ§e²„ÒÒuÎÎ<ŽËi‰JKO+•‰äAÎ+,ѹ«û2 ®Ö_nðo.vsh€³… }¿!OE÷ð™Öó€\æÅÎÎ.%%%**j[eå…"ÁÁ!ÂÒ’‹kÊ·Ôê´ÚÚÄ;wnªÕ 䤤ØÙÙ¼ŠùÓhÙôìòýy¥µ÷ú¸XMsÞבÇëH¼kð¬ Ûø(`N ÁìDFF8p ..î¦L¶¬¤„ër‰$99922’ëBæF¥Ö;_zðda©\Õx¯¿·Í¤0÷~ö˜îxp ‚9ŠŠŠ’J¥‰‰‰iii¹¹¹R©Ôà%üüü"""D¢–ªí~ªkÕ‡Ï:S\¥P7ØÅ ð³Ÿæàmc’¾€ !‚™‰D«V­2u/º›òʺƒ§ f•(ë.=Ãã1a}'†¹û¸X™¤o`rÈ…„ü²Úý™…^*«ÿn: oT°sô0w{ “ô Ìr!@7w­ ú—ŒÂÓ9w?õ!¶ä?<È5r¨›ß ¹ ûúëFå/—nV6Þå`#Œ q;ÐÅÒÂ8ËD@€\ÐÝhYö´ôξŒÂ…5÷º;Š&„ºGôsÆÊ‚Ðr!@÷¡Ö°iK÷g–+ïíé.žæ>4ÀÇ @ º…Jsô\Iêé¢;Uu÷õ°æÑ¿§­ñ;]r!@×&¯QÿzºèÈÙ⥦Á.†¡¡þÃ<|=Ä&ét-È…]UI…êÀÉÂÿ](U©.F(à3#‚œ&†º{8Yš¤oÐ!t=·Š¿df\.×j®=#òÆ ty4ÄÝÑVh’¾@×…\ЕHóªöežÏ­h´!ÙX êöð`kKü½€ŽÀÏ€.€%ÊÊ­Ø—Q˜“WÕx¯³Eô0÷‡8[xÆïtÈ…fM«eÓ/—ÿ’Q˜W¢h¼×ÛÙrB˜Çð@G>KÏ@g!˜)•Z{ü|éÁ“…%rUã½þ^ÖÃ<õ¶GCA.0;5µšÃg‹.ªT¨ìbˆ‚}í&…yôñ±1Iß C.0#åUu©§ f•Öª.FÈã1¡}&†yH\­LÒ7èö ÌBa¹rfaÚÅRµ¦á£ÆÞÈþÎÑ¡n®ö"“ô È…&v½°æ—Œ‚SÒ;l£µgÄ"þ¸A®„¸Ù‰ñW8‡6`¦”JebbbZZZnn®T*5xû~~~ "‘iæá.ݬܗQpñFeã]öÖ¨·±ƒ\¬,øÆï<˜ Á¥¦¦ÆÅÅÉd2îJH¥R©TzðàÁäääää䨨(îj5À²t:çξô‚ë…5÷º9ˆ&„ºGôsb1B0.äB0;‡ŠŽŽfY¶‡@ààaié#0üÔ[juZmmâ;7e²èèèÔÔÔÈÈHƒWi@­aO\*ÛŸYXPVÛxo7ñÄ0÷a}x Ÿ@.ó"—ËcccY–]`k»ÎÙ™»3`†Ít›WJK·UVÆÆÆ^¸pÁÎÎŽ£rµ*ÍѬÒÔS…åUu÷Jl'†¹÷ïe‡<&„\æ%))I&“ ‰¹ …z<¢Dgçó*Õi™,))iõêÕ/Q©P:]tølqMmÃ¥g†÷v˜æîçimðºí…\æåĉDô¼½½Ñž¶à=oo¿°¨HWÚ€Jåª' Ÿ/U©µ v øÌð@§‰aîžN–†- ÐaÈ…`^òóó‰h……1‹êÊéJD^‰â—ÌÂôìr­¶áÚ3"!oô—G‡¹9ÙuŒ­B.ó’••ED\Ktþšü—ô‚+yU÷:ÙZ<:Ìmô‘KÏ€ùêþ¹0??ÿµ×^Ûºu«©;Ý“VËf\)ÿ%£ðV±¢ñ^/gË ¡î#‚œø<}º‹‹ dz³³:tè¦M›Zh°¼¼üå—_ö÷÷–––}ûö;w®R©$¢ŠŠŠmÛ¶Qvv6cèeáô£àóù={ö|æ™g8]ŠÌŠJ­=r¶øÕ”¿¾Üw½q(ìíiýÜ¿5 úìïŒP]ÂÝùÂ}ûöùùùé·Z[s¾j†®¢V«-,,üüóϧNšŸŸoaaADZ­6:::$$ä§Ÿ~²··/,,LOO/--m®©²²²ððpGGÇÄÄÄ€€€ŠŠŠS§Níß¿_­V׿™««ë|бޮZµjÙ²eîîîM¤W¯^UUU/^ܰaCHHHzzº¯¯oÇ u'y¥µÞÎÝóaÛ¥æÈÙâ_OÉkÔ v1Dý{ÙM óè+±1Iß:ŒaY–a˜K—.¯êýår¹½½½T*õ÷÷'¢k×®ùùùUUUµ1ž>÷Üs™™™Gmò-·ÙÙÙAAA,Ûø1€Žw¸¹í555£FêÓ§Ïwß}×*ù{³Ú»‹‹{Æ8„½×™>·l“ÿ“úÏ‹s¶t¦©‡>¡ÿ||ÅŸúÏ2 ³®É§„{¶+!éæt‹{õêL—:Àõúu"jõÏIEuÝÁSEGÏ•(T #ä1̰>ÃÜ{¸‰9ê$§Z¹ ža˜o¿ýÖÛÛ[w^uuõÂ… ­­­œœ^{í5­V«?ì×_ ‹ÅëׯÏÏÏ  …3fÌP«N¨4VVVÆ0Œ³³³îKGGG>Ÿøðá¶ €eÙo¿ýöõ×_o2ÖWÿ:rQQÑìÙ³íììÄbñ´iÓJJJô9}úô¢E‹lll\]]wîÜIDº´´pá–KˆÅâÕ«WïÝ»·-£îöÆ v½]ªHÜyeÝNéeYOc„ëõëõÿó¹q#,/oqqñ!…¢Sÿh¤°\¹5õæËÿ¾p ³°A( xcº¼Ûoñd_„Bèºî^G...vppÐoõððÐ~ë­·Þyç1cÆQ||üµk×NŸ>]UU5gÎww÷_|QwXBBÂÊ•+ ^yå•_ýuÅŠ………ñññqqqQQQMÖfY¶¶¶öüùó/½ôÒìÙ³uÛV®\ùØcýßÿýßœ9s&NœhkkÛÜòóóKKKÃÃÃÛ>f–ecbb.^¼¨Ñhþñ,Y²d×®]º½ . Þ³gϾ}û^zé¥3fddd8;;§¥¥·Úø¨Q£ ÅíÛ·{ôèÑö.uK"!/z˜ûÎcyÙ²ÊlYe Ä¶½s‡m·ÀÖ–%ªcÙr­ö’Jµ§ºzOuõX+«dWW{^g¾QTóKFá©+w´f­Dü±]¢BÜì­…¬`rwsáèÑ£ëo­5-!!A7O¦R©¶oß~üøñ¾}ûÑ›o¾¹nÝ:}.ŒŸ3gŽZ­ŽŸ?þܹsuŸoß¾Ýdá   ýç)S¦lÞ¼¹þÞ·ß~{ذaIII³g϶²²Š‹‹[»vm“é°²²’ˆô™²-ÒÓÓÓÓÓ333}||ˆhÉ’%Ï<óŒJ¥ÒÝݘ˜È0Œ§§ç§Ÿ~JDNNNº-ÄS={{{"ª­­m{º±qƒ]œ,ÔÝ„Çi:\ÿ÷d3±DéµµKKJ~W(b‹Švyxt8^ºYùKFá_7äwÙ[ ê6n‹•ÈhofàÖÝ\ØÂý…º2™L¡PèçÌ‚ƒƒ³³³õ‡…„„‘@ hð¹9ÇŽ  ¢iÓ¦]¸p¡ñ“Â111111ß|óͺuëΟ?øða†a’““Ÿ~úiÝ1R©ÔÆÆ†ˆÊËË]\\Ú8æ‹/ѬY³t=¬¬¬¬««+))ñòò"¢ØØX]g,:ôʲ²2"ruuíÀ¹Ý~ÊP¿Ås‡ ÑKË=<ÆÜ¾}¬¶ö@MÍDqû®í²,¹zg_zᵂêÆ{ÝDÑÃÜGöw °!t+íX¿wÿõ8Ý+.ìêꪻZ½aư°°¤¤¤W_}µña+V¬˜8qbPPP^^žÏœ9sôËèè²qtt<444>>>88¸¶¶633sëÖ­iiiõ¦ÑëÛ·ï¬Y³^xá7jÔ¨šššŒŒŒ©S§¶°,Ž‹‹Ë©S§$‰î²u}¹¹¹D¤P(Ο?ÿÑGYXX¼ôÒK[ˆýðt«¿ÿ”°ü¿sGÚŲÝÇ[?¥ÃÂê}nKßZR/+u )îÒa€PHD…š† Ê´ A(dˆ÷¶ŸæÑÛ‹ó=L®}ïÁ[¿~ý’%K† baa±xñâçŸÞ ðòòZ¹rå믿¾xñâ‘#GzxxDGGïÝ»÷ƒ>ËåNNN“'Oþᇚ;ÝÕÕ5==}Íš5ï¼óŽL& …ÁÁÁO=õTã §·uëÖ·Þzë•W^ÉËËstt yüñÇ[èá믿§P(ô·6êMš4‰ˆx<žŸŸßìÙ³¬¬¬Úù ÷Ò¡Û´âñˆHÝ¡¥+ùÿ²DÒÆvž\J$ä=ìüh¨»³mG<èºÚ7_Àýuä„™kSZWG_Mn£˜pϨ71–ž€r¡‘¤Ämõ˜ü= {÷ 2ÑÏibXë§èÄy¡¼R¥ûühˆÛ̱>­ž²é‹öõ­}ÔJS2 ›|îD‡»çNRkjˆh¬e;.?áiðntÈ…À-eöÀÉÂ&wqºNMžZ½¹²Ò‚aæ4›)Ô‡\Ü:r¶¸Áâ…Äq"$¢L¥riq±\«]ãääÕâúê ‡™À¡Æ“…%—JK‰ˆ%ªÒj/¨TWêêøD¯;:>cggØBÝr!p¨þd!§s„Û*+uD ÓK ˆ³³{ÒÖ¶O{ž8äBàŠ~²ÓDØöm eÈ…À•#g‹½œ­–Læð>B0 äBàŠ·‹Ut¨»©{mÅ3u Ûà‹g>ºäB B.äB B.s3nÜ8"º¥nøŠNéÊ 8ИEÌ r!˜ ":§R³¨®œ§§§1‹˜äB0/áááDôIE…ÆX5DŸTTèK<° Á¼,_¾\"‘œV*JKµÜ—Ó%”–žV*%Éòå˹/`¾ Á¼ØÙÙ¥¤¤0 ³­²2ôÖ­UUÝkxK­ÞYUzëÖ¶ÊJ†aRRRìì°à"<Ðð¾0;‘‘‘ˆ‹‹»)“-+)ẜD"INNŽŒŒäº€™C.s%•JÓÒÒrss¥R©ÁKøùùEDD$$$ˆD"ƒ·Ðå ‚™‰D«V­2u/ ¸¿ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆ @¹ˆˆ¦î)•ÊÄÄÄ´´´ÜÜ\©Tjðöüüü"""D"‘ÁÛ€n¹ÀôRSSãââd2w%¤R©T*=xð`rrrrrrTTwµ ‹B.0±C‡EGG³,ë&¡éñÔ/œ\¼ _¥$.ž Ý’L&‹ŽŽNMMŒŒ4|èÊp!€)ÉåòØØX–e#çÑÇÐè霄B"rñ¦ÑÓéã?(r±,+—Ë9©]r!€T@¬³ IDAT)%%%Éd2ÿ!»–îÿ:2<Š]KþCH&“%%%q^ºäBS:qâÅ,%ßHy|ŠYz¯4€r!€)åçç‘ß@£Õ•Ó•ÐC.0¥¬¬,"®î)lŽ®œ®4€r!!€r!!ŠZžcê.t r!€aÔæ/ý}¡ª8ÓÔè ¼À0¬{ϪºœRòûB‘k¨mÿe®¡\T™åsß—V¶äéK#&Ó¤EÄÇßfèü$0 F`eÓ7Vžµ^Yœ©ä8F>A,KjË(;“r³¨,Ÿ®á¢<@  F7e¨U–§é0îý{ŸÏýNï=AÇ¿G.€ÎÂý…£›2¬¿EYœYòûBNï;ì?’ˆHQÅQóðA.0$ëÞ³x"§9M‡·sˆˆ$} Þ0À]ù{³Ú:S÷ŒAß!Ã0DôÝ­¶ž¨{Ù«7iµT]A•eä7žXEýF´¯³|hÆX‡/“^±î=K`ëÛ¾“ ›Âs'& *%¼¿õ‰¿ªÛ{úí«÷>WWPî9 BBQûyj‚Sµôëjé×BÇþbßiV=&ò„¶ííI{ér0@}˜ž0È…]Ïw·ˆÕ’¢šn]¦#;èë5tl½ñÙ¹´µ…`_Ë`_KÝçºò¿*Êÿ’ŸK´ô‰÷š*r %Bzx!˜€þ:ò‰¿¶u¬†Gb[ê3Œú #'Ú“DÛÞ¢ç>këéÓ²o°…Õ(7þ«¸ñ_DÜkªU¯)|+÷Žõ­UIIIµ ]ËòåËMݸr¡a„6¬²\÷Ù.ø9› Åm<1þË å•*ÝçGCÜfŽõiùx"Úäÿ¤þóâœ-íìé}úèÞ­mÇWüÙ™¦º‡ªË[äYë›ÛËÅŠ†QóiO>ÜŽSÞû¶è´T±%q¦²ð±Úú»ÔU2ù…å}*r)öjé5Žá ;Ð+V£$†ax8L¹ÀXµ¢êrJ“»¸{ŠØŽˆH¥hÇ)ª:ö¿'äÎ}©©É¯¹þSÍõï5Õy÷Áj•Ç•Çy"G«žÿgÝkªÀ> ]½bx‚Ò£O9=ô/†ßÎ;ÀD  ©úêwº÷ÔÇé;ñˆèè."¢^ý;r._ìiÛo±mÐ"eqF͵ïkó±eý´Êòê+Û«¯l: °öf%™ÀmÚÔ4ï«Ì-ÿó%§ˆ Äð;Ò90.äBƒiÝÅÅ…ÇãÙÙÙ :tÓ¦M-4X^^þòË/ûûû KK˾}ûÎ;W©TQEEŶmÛˆ(;;›a˜Žº•XXX 8ðÇìX;¸Ž ÝËV]ÏÚÙ‘sHøï¿VWWÙöîKDšZ…V©Ô¨j‡Ž°óL{zšººŠ'‘V¥äYàÅb4-«åa• ºVšëëì××­[÷ÆoQnnî¤I“.]º¤ÛîââÒöFöíÛççç§Õj ?ÿüó©S§æçç[XX‘V«ŽŽ ùé§Ÿìíí ÓÓÓKKK›kª¬¬,<<ÜÑÑ1111  ¢¢âÔ©Sû÷ïW«Õõ_TèêêúÁt`¼D´jÕªeË–¹»»79^½zݹs'%%eîܹÅÅÅb±¸½í#@·•þìV«Õ(j¶v}ž‰'"±wÀg_½üÅ:V£á -œCGzGM9·öebY­Zå;3Vhç@,ëµZ=a„ýë_ºÉN†aN:µiÓ¦o¾ùÆÊÊêóÏ?Ÿ1c†.­-X°`ë֭͵_RR"šÌŽ­Â?€ÌŸÏ¿téRRRRaa¡¡Ú¬ºžsúµ¥'_Š;÷ϵŅD¤ÈÏ;÷ÏéÏÎÉxq~ñŸÇš=“aì‚ÔU•MîdµZeiqý%º°^Ãû ‘•ß|?õY)ÓwŸÙY«®5u§º!K¡ÕìaOÑÙéçw.}~×Ò3·Nw¾Ùøøøk×®>}ú×_ýþûï?ù䓿ŽdYV¡PdddÌŸ?öìÙŽŽŽºí+W®|ì±Ç¦L™²cÇŽÊʦÿðëäçç—––†‡‡·½‡,ËÆÄÄ”——_¼xñÒ¥K2™lÉ’%ú½ .¬ªªÚ³gÏìÙ³uó‹D”––öé§Ÿ6Ù F£ÉÎÎŽ‹‹{饗ìììÚÞ=Ì‚™R*•‰‰‰iii¹¹¹R©ÔàíøùùEDD$$$´úo;#xÐÆ m¤›Þ(..NJJš;wî€:Û"Ë^úôÝ^3º-Û»#'å“à„w.nxÛ-bœ$f&±ZMs'Ö–^ß¹Õ5|Lã—ê6Z²ô»EDTTYøñ‘¶ý™2#döユوl X%}gPý/ùBK›žN’hÏ> Þñ“Z7eX^SNDgd§ÏÈ:;w¨R©¶oß~üøñ¾}ûÑ›o¾¹nݺƗt‰((èÞ/þ”)S6oÞ\ïÛo¿=lذ¤¤¤Ù³g[YYÅÅÅ­]»ÖÖÖ¶q;ºÔ¨Ï”m‘žžžžžž™™éããCDK–,yæ™gT*•îîÆèèèÄÄD†a<==uAÐÉÉIW¢Éè2räÈ矾íݨó…`ŽRSSV¯^}ðàA.BI¥Òƒ®^½: 55•‹m÷ ÚNÙK©TnÙ²åàÁƒºkOV'¯¨¹uÃyÈp"r:¢ü¯3uò;U×s¼¢bˆaˆa¾àÚŽ”£3Ç9¾$óÝYGgŽ?:+2ýÙ¹¬ZÝgÑŠÆÍ6^¨Ûà50Ü÷Þww¾üßÓ“û×ÿ¾Ð…rë=ÓÍo†K¯Ç¬‚jîd˲>¼y.Ѱ%Ì–~ÊP¯“s‡2™L¡Pß}ëLpppvvv“G;v,??????""âÂ… o牉9räÈí۷׬Y³cÇŽ)S¦èþ&''ëŸÎÉɱ±±!¢òòvü©¸xñ"Íš5+00000ð7Þ¨««+))ÑíÕuF[uéÒ%FS\\¼bÅŠ &üç?ÿi{Oôˆ…@×rèСèèh–eÉÓƒžœOƒ‘››áËÑÙs´e»L&‹ŽŽNMMŒŒ4|•6Ð×MBÓã©_8¹pðbÞ’<ºx‚vH&/´KýÛ¡X–=pà@^^Þܹs >é[?núÎŒõ«û\[\@߬Yüç±Ë›>¨-*{÷h¢«/ tæçú<½Ü°Ý3­§G-N¿~BËjõ[ª•U_glÛuú»Ébf{Âݶ#7r5æò–þó‚ã—-*¹±·ç× Ò¸ù«?e¨×á¹Ã·²,ÛÜó[®®®D´aư°°¤¤¤W_}µña+V¬˜8qbPPP^^žÏœ9s&Ož¬Û«[ÈF÷ÐÉ´iÓÚØI]àÛ¸q£[½s®®®m<½1çââ2uêÔ>}ú„……=öØcº'fÚÑB‡kpA.—ÇÆÆ²,K1“é›íõ'¡ˆÜÜ(êúf;ÅLfY666V.—sR¨EúñFΣÿ ÑÓ9 …DäâM£§ÓÇPä<2áx¡½ø|~ƒ-çÏŸOJJ*..îXƒB;{±Oϲ³DTzúO‡~ƒ…v6¾·~ÞE,ËjµÍÝ>HD®#F{?úØ…ÞT×T7}D½%º“×€±}n¼]©Vî9³kÖæiï\{³ü¦a‹Ú» "M]3¿ÔÝQã)C½ÌúøøˆÅbÝ„eeeé.(· 44tÁ‚k×®½}û¶n‹Z­n0C¯{üY:Åb±ÇßÇ›1cÆêÕ«܆¨ÕjµZ-5%44”ˆŠ‹‹×#¶òxS[.øúú*ŠÜ—ŒùB0/III2™Œ‚éÅçÈÐË~6aèÅçHš#»”””´zõjÎ+ÞO7^ÿ!»–Œ°ãصtý圑p¼²cçÏo?ä(qéßÓ¥_Oû®Æø½ëÊ4F£Ñjµºÿë4þ¬ÑhT*UãÓ “’’æÍ›Wÿ¾¨¤?;Gÿy؇)AÏ­¼¼iýõÛÖ6ϾJDý^x#{ãºÛ©?ñ-žsâÜ"Æ5×T¯™OV]“fþ~ðKo7(Ñ`I ®±Äª5jV­ÑjÔZµZ«Vk5º-j­Fsw‹Z­U7:L·E£®¿Q£Vkëîÿ²~SšªÚJ†–šøy¬Öªùëç0v^ØÂ·> BžKDVöí^gä¡F¤f¨]s‡B¡pÁ‚ñññ›6m’ËåkÖ¬Y¶lY«%Þ}÷ÝÝ»w'$$|õÕWD”““3mÚ´Ù³g‡‡‡{xxÈåò 6Œ9²þâ8õ­Y³føðá¡¡¡ñññÁÁÁµµµ™™™[·nMKKspph||ß¾}gÍšõ /ðx¼Q£FÕÔÔdddL:µ…I>—S§NI$ÝeëúrssY–U©Tùùù[¶lñööîÑ£‰©ý–!‚y9qâÑœ™ÔÚjÃãÑœ™ôæ?ï–6.]ј¥Äk8+ÄŸb–ÒGO“Ç+= äâÍôõ»u_ZØX9JœûõpíßÓ9¨‡S€OؾÕÔUʯ}·Ù8@Û¾tYs3 …"99yÒ¤IãÆkauCKWÆëõØôòyÿ¾6Xyú YÓô£š Z`x¼+ß×}ÖooËúˆ éå}=§%–%­–´,±}fù1|fõϯ«æ6MSIN]ÿ0MsÏǘˆ–Õ¹òÛïWŽ ÷5@,STHs3WÓ¿ÐùÖº™¶§Ãõë×/Y²dÈ!‹/nË£^^^+W®|ýõ×/^;88|øá‡íꉫ«ë'Ÿ|Òäš8úNÖï­H$zï½÷Þ{ï½:Vÿø_|±É§ª;ùDšr!˜—¬¬,"âêžÂ渹Ý+m\º¢ÝSØ]9ƒ7|å,EY¥toÃiHmºäâÍ’‹7/ïù_¼÷–Xú*[ëjźZi]¬ìøVr°=ÑüöÇ–®DTq)ëÜÛñžã&ð­¾JYVœñâüμ„S-äB3gÎäåå½öÚkÆéO‡±Z–X¢n}ŸKï§G>3²÷C_ÎMéX µ•×ôŸ5*yuÙ§<>–ºa×¾† À03nÝSµwªdÇηt1T¡äW()ç…Ùö>tç×}³ñ `µZM­‚o%¾º·à÷ªòR‡þƒ—½zuÛF":õÊ"¿y‹‰¨ìlÆÕí_(ËJ¼}ÌwöS\w¬U,Ëòx¼Ò¡D"‰‹‹3f—:ˆ%VË2|ƒC†_Àgø|¾@ÀÓýÇ×mð|Þßoi¸‘¯Û"àÝw–€'àóøú-×JsÿýǦæ:ãíàýTø¢ñtòuyÃg\"V«QW×Tä_Ûsóܺ’ë?ŽMŠœÛÞÈñv¦¦õíÉÿl<Öì:GH„F€\Ãðý|ÙÞ'ÖËmÃÑLÝÃ’CÿÚÊmŸX¶®²âúîíb/‰…ƒ¹„Žôzäÿêª*Óâ÷›»¨÷‚¥%™„¬ûR· KáñCCÖ~Vsëú¹·ãÍ!Q ¹088xÞ¼y]à"2ÝÍðøB[[—!¶.C,¬Üó.n¼qæ}ÿ¦qóV[§øöä×MîB"4äB0¹¬Xvì¼ÈNÌðVÛâÍ.ž*º§¶WG^ÓÔvéÏÎ%"¾¥•}`pÿ—×èž’æ[ZûUQ”ODZu]ƒS—¼ÂÎÚº†» ˆÏçóù|ÇãñЩÛ"“ÉÔjuãFÆŒÓêû^͇ìðí¾“ï{€º0³˜ˆî3ÞD=j«¿òÏŸ–j°ÑÞÊá‰Ðyž.pu×ÝNÞÅwòç¨}sóùï/ŽDhdÈ…À•rižc€qï›3©m¼zêZÕíô˲cY7]¨¸VЖSXK~Ýd_­GûV[í€áŸýGwá½ÒZíé7žõ™0Õë‘ÿ»±{{ãSÝã{ß·~ýú¶¬¿^Çã=þøã£F2h§ Y_¥ß÷à‚µ…õŒY3CæX[pûg˜/´!"­æx#sãÉB$B“@.®Üø=ëø[_{~Š×ð@S÷Å´ñÞÉ-?ó÷¬üÌ+êÚ&ÖØköDuÕÔ!¬“%w}kA]EyÍ­.ÃGkjª‰H«T ¬mˆH«Rš¤?mÑ`FP$ÍŸ?¿_¿~¦êσæjINZîÝ÷Š¢ÇM{"l¾½UkÑ\Éõ‰HìЦU*»ºú“…H„&„\\ ~âásÉöÎMôÈyZº"¥Ÿ¡¬óTP@µJ²²"êÕƒûÒŒQÏ3ÎxgùÜ÷¥•-yúÒˆÉ4iñ¹e]2ïÄ%ÙѬ›ÇÎWÞ*iåh†¯\PWñéí_ßt 稇­²ppr ›¹|sH„[ĸóë^þñWÎCGœ|eÑ€Wß5U¯ZV?ÚÛÛ?ýôÓÞÞš™Ö­àÃüý&±zNŸ×–k‹ ÒŸkéêβ,«Vó­¬|&NóŠšÒ™Î˜¿¯3¶³Ä x‚‰Á“ŽxÊÕ¦ãï(kÕµSo«Ukê*9ŠÊ\"ò l¸L]÷£Ÿ,D"49äBàŠÀJ4(.úÏÄ·Ó³÷ÎÍæ*-i4ôéFúq/‘o/zh …TVNWséøtüšò$lvAQ2Òx‰ˆ(ò bYR«¨XFÙ™”›Eeù´p ¥ˆX¶ìJÞÍcçeÇÎ矔j뚸ÑM'x Œ`ßÃíà²Ïìuè÷òÞw«ŒuQ¬é¥g¦ß‹o6ØœðNƒSš\ÚTô¯Âóòòzúé§›|kB{éWðé€áŸ}£ûPv6ã¯õ«ºw.Ì»së÷+¿=õTÄ"oŸÖO蜢«÷žná ¬­xöYèäó×uMî‡sß÷röýçäwM¹8¤›BS”ʉˆ«´ôÙFúq/yzЯQÿû¯¬ÝΧô ¸Ñ IDAT´ò¢I2Æx‰ˆ(îý{ŸÏýNï=AÇ¿7p.TÉkn¥]¼y4KvüBuAÃ;Á°õqé1z€dÌ@ïð ¡XDDW~LkpŒÏ¨þn|®Êz•!{ù`ÐÍ-X°@$âꇪë9Wþõ‘¶N%´µë»4ˆMvnÏió*._ôfû!Y­VU^Zv.ÓiPGý1— ³·/øFâØî—‰µ×ð—Z?¨ûá>{Ø\S÷ˆ Sú)4ý§%iý°—ÄbJZOî ÷zyÒãFÉà|¼Mé?’ˆHQeˆ¶X¶äâÍ›GÏß<–UtæªVÓÒŠÊK ÏÐ>=Æ”<4ÀÁ¯áÌSÉ_7êé?yøÃÄu‰·á™!>Ÿ?räÈ©S§ðÑcÝ“Ú:cv&–½ô黽f,t>Z¶wGNÊ'þ±ÏßÒjÐ WH9:óîãÃÎ!áýW¼e¨.™§‡ûFšº _g?Swî·iàVý)4=ƒ¥¥}û‰ˆ¦Ni"š·ãmÊí""Iߎ·P[^uë¿tSƒŠ’V^áeïëÑct°dô@¯á}–Í.›Wré¦þ󀑯ÏaxÝúM\7n\x¸ïÈlð¤v¼¢æÖ ç!ÉÈyèˆë»ï>~+ù¿ÔèåËcvÖÖ©ªo^»º}£t˧æöæ@è äBàVã)4=¤¥³YDD£Fv®†Äíx‘]¦/V㙯´ïD1=-]N~üãÍcç‹Ï_ky­A¡Xä5"¨Ç˜’Ñì$m¸éžeK/Ɉˆ&lùÔ¡K'·¯sp?ƒ‡Âvh uxB ÛÞ}ýŸ|îÌÏ!t'È…@›üŸìÔùK;ÕT§ÒRA>‘DÒÞ¢Mú¢÷ÂÎþR´AÒáŠ1¤ÕRuU–‘ß@zs'õѾFÙõ™í~òÓŸZ8Æ©·dô€£x ë÷hÇ÷ŠÊۥʊj†Ïýöü ™cÚ×30¡½Ø§gÙÙ —°‡JOÿéÐopëç°lÕõ¡=÷½ãA.³ OK}¬<®(Ú´62Q­’ˆÈÊŠ»Žq¤ƒãÕŸ~õÞçê Ê=GCHØž.)ò›ÜnakåÑ_2f€ä¡`O§övL§ä¯›|‘02i±o-ì"&蹕—7­¿¾s›ÀÚ&ðÙW[86ýÙ9¬V«QÔlíú<o´>v!ãÆ;r䈪&ßBìi´¢ªš|"8p Ñ*B·„\]™HDJ%)d-6uWŒê»[ÄjIQM·.Ó‘ôõ:¶‹ÞøŽì\ÚÚBq¼¸®ÒUhKDÄ0.AÉè=Æ pâÏtöµ³•·Š'm‰÷ ëÄ=¢ª(¿üy―ï·~胤É%xlzù‡¼¿©åÃÌjùs¦{cuUÙ'#æÂª² Däéi¼ŠÐ-!‚YÐ_W´4Qч;ݸI×®QpκƉŽ·†Gb[ê3Œú #'Ú“DÛÞ¢ç®Ø’“Uמ›÷´.Z9ò=Åýç>Ìq»ZGÆ{d’Ûñ6ãè."¢^]ìZz§.M¸°î ±O/—a#]ÃLjœ]‰H~å¢lïw¡má[Zeþ~Þ/{ÜÇDéŽo¼«çôù7¼í1N3“ˆX­Æ¶wŸ’Ì?BÖ}Y[ü÷“@ͬö\xüеŸÕܺ~îíxäBhRddäâââd2ÙÕŒÞ.Òv‰$9992«pCg!‡Ož>!Å¿HZ-¥¢wާϾ >þdmMÕÕ”“KååÄ0ô´ñ~lc¼DD”ü*‘FC5$»rwië)϶ˆYs5Þ%lTyÖ©’ÌÿÝØ³½×Ì'½£¿sá ]ùwÕܺ¡QÔèsaã]uò;U×s¿•¤[¢á7ñͰ¹Õž—¼ÂÎÚº:cŒº¦¨¨(©Tš˜˜˜–––››+•J ^" ÀÏÏ/"""!!»w$¹8TòŒ«93¡V&Ф‰´ÿ¿@gÏQšÄb’øÐ„(Š~” \±yÆ/úúÞg+ê=ˆ&-¢° \”2_< ‘ó°çaîc½ðþJïèÇÀÒͳ×?èà‹,µê»¹­ñ.݇ŽÝQÊDDx ´F$­Z…w‚CW‚\\ÑOžq}•ˆhÐ4€ÃöÛÀ8ãýî­v=Å'~w*[‘ª¬ÄÂÑ™ˆœCÂo|ÿµººJ÷<ЦV¡­¬ÐßxßÒÊÆ7àÖÏ»zýc˲ššjž@HDZ•R_¥#«=teÈ…À• _ÿæèïõÈ'K¸M„fãA¯i¥ÉýÏ¿Y­†áñDÎný^|“ˆÄÞ=Ÿ}õòëX†'´pé1öQÝñwõúÇ‚~/¼‘½qÝíÔŸø–bß9qnác‡Ž8ùÊ¢¯¾{·L{V{è +N}|?ý]Ú|ÐÆkZýãÿÙäv—a#]†Ý÷¾lý2„wYyú YóIý-Á ï48«…Õž±È3t?/ª°cL|a×È´ñ@÷ƒ\ÐMøûû‘²¤ÈÔiH×%///SwZ\ÐM"*8šjêŽ4¤ë–\0È…`Jf;ÅÅÝ0uCæÂøñㆹ±ç«üC?›É/©²¤(ÿÐÏ7ö|Å0ÌøñãMÝhž;ó2nܸ#GŽPQ¹¹¯jQ 8Ðxÿ¦oI¹x¯hI‘‰ÆÛ˜~Š«ç´'LÝÎé¦ÍtCæ‚¿¿LLÌÞ½{u+x›†abbb¸ Ä`(È…`^,,,ˆˆ._1j.¼|…ˆ<= ÿöÒV鯛›eÔ\˜›Ed¢ñ66~üøËW®È~üÎÂÞÁip˜Èň¿ïF¤,)*;›a„i³±cÇíß¿ÿÖ­[¥¥¥Üj#ooï &¸»»›º/Ð:äB0/ááá¤ovÐÈâå>­–¾Ù¡+mŒr÷ÓwïFE<~ëÇwžVC{7Þ-mŒzÍS“E%ë(ôë7ïŸýç­ æ6ÅÅãL›¹»»/\¸ÓÐ]áþB0/Ë—/—H$t)›6|JzGYû°,mø”.eK$’åË—s^®ÝxsÎPÊÄj9/Çj)å Ê9C¦/1Œ“WŸ"¶GŽvÈEÍ™¶oëâ.®yùå— äììl‚.…³³ó AƒÆŽkê¾4 ó…`^ìììRRR¢¢¢Ø½?SæIzr> ÄÉ5å¢":{޶l§ü†aRRRLò°¤~¼‡¾b³~§éñÔ/œ“kÊ%ytñíþŠddüñªÔÚK7+Ï]­˜ñÆ/Öön÷'`'¦ÐS\f¹ÌNddäâââd2½»Žër‰$99922’ëBÍ©?Þ/r^Θã-¯¬;w­âÜÕŠK7+Uj-YÛ7ŒøVL•%Sm„Î@« ÁEEEI¥ÒÄÄÄ´´´ÜÜ\©Tjð~~~ "‘Èàí·Kw/ËÒµ‚ês¹çr+dEŠVopd ¹ë ´ r!˜)‘H´jÕ*S÷ÂxºúxY¢ÓÒ;g¯VœË­¨R¨ÛxC¬SÌiÇ íðÜ Cäçiíåli'nÇ¿6m™r©¸ë´ æ À0m„BÝ'„º_+¨I»Xšž]ÞêÄ!."˜äB00_±¯‡x柬kGÎÿu£²ÉÃø¤¶cL¿ð2èá:2pBÀgÜD·Jj›;À)fˆû5 Í0_œ¸š_½áû«ÕµÍ^JÆEdsƒùB0¼‹7*×ï’Ö…îŽ÷-Ž#"…˜‘½_ÐäB0°39w6ü£¬»wø‘¡nÓGß÷G& Ì®#€!¥],K9xC«½· õcž1ážÊ:­€Ï¨5w·ã"2€Â|!Ìá3Å›÷_ׇB†hö8Ÿ˜pO" y}}luÛm˜;BRš¬—Р̀aü÷Ï‚þ¸­ÿ’ÇcžŒê1²¿³~ËàÞöÝÑþo>Ê9µÏ]€a¾:‹%úî÷[õC¡€Ï,™ì[?Ñ ?{"ªSÖܸpÄØ]€6À|!tŠ–e·¦Þüß…{+T‹„¼g§ôîßÓ¶Á‘.öÞΖ½<œ¿ª­6n M  ãÔöË_®¼rG¿ElÉ_þ¸o/ë&ègÜËÎX½€öA.€R©µŸý”{áú½eí­…ñÓü}\­š;edgOgK£ôÚ ¹:¢F©ÙðÃÕœ¼*ýg;‹—¦4X¿º/„B3†\í&¯Q´Gz³H¡ßâédùÒôG[¡ {„\íSZ©úpwNAY­~KO7ñŠéþ¶Vø~еáû8˜)¥R™˜˜˜–––››+•J Þ~@@€ŸŸ_DDDBB‚HÔÒ¥Oãè*ã-,W®ß%-­Té·ôñ¶yáñÞV"¾!º ¦„\æ(555..N&“qWB*•J¥Òƒ&'''''GEEqW«U]e¼7‹í‘ÊkÔú-|í–ÅøY°*@w€\fçСCÑÑÑ,Ë’§=9Ÿ"77×)*¢³çhËv™Lššiø*m ¯›„¦ÇS¿prñ6|•’<ºx‚vHoN^Õ†®Ö(5ú-a}ã&ôðCwLÿÊó"—ËcccY–¥˜ÉôÍvŠz„“PHDnnõ}³b&³,+—Ë[?ËÐôãœGÿA£§s ‰ÈÅ›FO§ÿ ÈyÔñ^¸._¿;§~(=ÀeÑ$„B€n¹ÌKRR’L&£ @zñ9b¸Ï C/>GA2™,))‰órèÆë?„b×Ãý_G†G±kɵk¼'¯ÜùäÇ«*µV¿%z˜û‚¨<#ü€!‚y9qâÑœ™Ä3ÖNæÌ¼WÚ¸tEc–ÏXmðø³ô^éVýïB馟¯©5¬~Ë´Q^3Æx#t?¸¿ÌK~~>Qß>F­Ú·Ï½ÒÆ¥+ê7ШEuåÚ2ÞÔSE;~¿¥„ Cs–<<Ø•ÃÎ€é ‚yÉÊÊ""®î)lŽ›Û½ÒÆ¥+ÊÑ=…ÍÑ•ku¼?üqû¿è¿äñ˜§¢{†9qÚ70!äBhˆ%úæ7Ùá3Åú-BoÉdßÁ½íMØ+àr!ÜG«eSÞH»X¦ßbiÁnŠ_P[ö Œ¹îQkØ/~¾v&çŽ~‹•`ùÔÞ¾Ö&ìžG®ä•Ö¶~P7Ò Æ«¬Ónø!§~(t°&Ì@(x@ WÎçV¬Û)½,«2uGŒ¤«·¦V³~—ôâJýW{Ñk³úx»X™°W`L¸Ž \7ØõÀÉÂÄW%¶SÂ=ûJl8)3ö‘û¾´° W ¤Èñ4<Ô+cÿÍ8ãåsß—V¶äéK#&Ó¤EÄïÄßæŠêºwçÜ*Qè·x;[ÆOp°v¼Qèj +"!/z˜ûÎcyÙ²ÊlY%·é0f2±,©Õ$—Óµëtè7:ô ¡·Þ n*6bÌñF>A,KjË(;“r³¨,Ÿ®é`k%rÕú]Ò¢;Jý_ñò©þ6Vøþð`Á÷}àn M^£&"nÓÒŠî}fY:ÞM¤“§hÕÛ´>‘xFš54ÚxãÞ¿÷ùÜïôÞtüûæÂü²Úõ»¥å•uú-Ûçó³´0Ö XÀlàþBàn ­þ–lYeâÎ+ÜÞ‡Ç04p%­'±˜NŸ¡´4® 5b’ñöID¤èPó7 kÞûîJýP8¸·ýò©½ LÈ…À­qƒ]íÄ §¥‘==hÚcDD¿þÆU‰¦¼·sˆˆ$};rîºÒ*…Zÿåˆ@§e1~B¾-< ð¸Õx Mót82‚ˆ(û2'7ÃÈã•]¦/V㙯tät…J£ÿ‡Ô‹P(ðX¸ÏÄ…d¶ñƾz=Jò¡;{uië{昶µ;Ì…$£ê“gòΙmþùꆭ-ºxcÂ=¸7]ýd©U?³7á‹kÛöNè~3î~Cµ#Ì…$ã䙼‰p篲4Ûtæï×—äh•ˆˆ`.$ùüv$«‹›ýSãä|ŽÐš´·ñQÛÃ\Hrñq·hO_Ñhoã%"¢¶GaéP›u“üÐHÚÛx‰ˆ¨ía.$""""€¹ˆˆˆˆ$Ì…DDDD0’µ=z4dfšµjf&€~ýú™µ(€Æ›]ïç”e!•³Èx‰ˆÈš1’u±µµ€3gÍZõÌYÞÞÞf- àŸñ¦$™µ¨TÎ"ã%""kÆ\HÖ%44Öo€Á`¦’Öo¸VÚ¼¤¢›W 7SEƒ›W^+MDDdÄ\HÖeþüù§Nã£EÙë‰">ZS§5Íüùóe/W‹4ÞäÈ{¢üIX4 îU$†¥ÆKDDÖŒ¹¬‹³³s\\œ Øü3¦NGü¯r=k˜™‰ø_1u:6ÿ,B\\œ³³ 4Ž7aæŽÀ®Mr=k˜†]›0wÖÁ‚ã%""kÆïÕ Ûºuktt´N§Ãâ¥r—Óh4±±±aaarªOõñ®œ'{9‹—ˆˆ¬s!Y£ððp­V»dÉ’ÄÄÄ””­VkòAAAÇ_°`Z­6yûMÒÞÆKDDÖ‰¹¬”Z­^¸p¡¥{a>ím¼DDd…ø|!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD*Kw€ˆ ¼¼|É’%‰‰‰)))Z­Öäí >|Á‚jµÚäíQÀ\HdyñññÑÑÑ:N¾Z­V«ÕnÛ¶-666666<<\¾ZDDÔJ1YXBBBDD„(Šž<ðz‡ÂÝÇôU²Ópr6}Nfú2DDÔšñùB"K*((ˆŠŠE1l–ïÆmÈ ¸ûà¶°|7¦AŨ¨¨‚‚Y*Q«Å\HdI111:.p¢Þ† ÿoGA¨·8:.&&FözDDÔª0YÒž={D΂Bi¦Š %"g]+MDDdÄ\HdIéééú™µ¨TN*MDDdÄ\HdIIII€\ÏÖG*'•&""2b.$""""€¹ˆˆˆˆ$Ì…DDDD0™JUA²¥»@DDÔ"Ì…D¦Q–þGÎÎYû-Ý""¢fâwðˆLñûä¢3qÙ;g¨=wè3ÛÖc°|µR’°c=NïC–奰s„«|‚н?Æ=•|•‰ˆ¨-ã|!‘i*{§žQʳögïœ!ÓÜ¡¾ q¯àå»ðƒ#0z2z CY öoÅ×Ôä5‰ˆ¨½à|!‘ÉHS††ò\åYûËe˜;\óâ×ÀÓsV GÈu‡2/âðvNQóq¾ÈdŒS†F¦;¼pñŸÃÞ ¯m¨ xúaìL¨í[^‡ˆˆÚ)æB"Srì>Y¡v­±ÓTépÇW0v&<4-i†ˆˆ¨nÌ…D¦T{ÊШåéðäÑìÞ5DEÑÒ} «.o¾ÅPžgé^9Ÿ;À×—uÕ#A(/ÅêS°ïÐÒLö…R"Ýv».··´-""j+8_HdƹÃÐ>ŽM¸ªìšpECG{çî~ºàèû ¦i‘ˆˆZ9æB¢VÃÖÊŠMÐÔÃa.‡¹(:ûyÎ*òMÐ(µrÌ…D öì>ês·QŸï9Ñ„”'½nrñtK«+ Â[3½Œ?–gìÉÞ>©*_ÛÒv‰ˆ¨•ãú…VÄÆ¥oùå?¤m·[W©½nmä…+:àìÕg÷ÔÃ冗¬ œiÜ~2yu{z[?fÜþãÙ¿ZÒTÛPtfuAÒ²ú޶dEÃàÁHÓbÏfôlÙzˆ…xï ±Ïûvq»ºÚaU‘.kÇC.CÞµóÓ¢¦‰ˆ¨5ã|!‘)‰U¥Egâê±ðäÊÜĹb•)ža$"¢Ö†÷‘‰L¦öd¡É¿ƒý züñ->yk^‡ÿMp耒B¤žD~S^lBk‚¦SÈë¶.½ò/ •Òβ¿wdmŸâ:â•“Ÿ©ºMDD­s!‘ÉTŸ,4y"”ØØbörÜ>;¿Æ™ý8™ˆªJØ;Á;#Ĩ‰pvor›Uι{æÊ®N6VœËÞ>Éeè2µ×ÓöŸˆˆ¬s!‘i' eJ„ÕõŠ^CMÙ ­û@1sŸ©Ì;!í1Täüù¤óMÏ:õœÙðµDDÔfðùB"Ó(>÷µsw“³«?nX’²)ç÷™†²l vŒˆˆdÂ\HdI£GfÖ¢R¹~ýú5â\¡CïY®¡ *G㮊ìÃY +sËÕ?""²æB"K²µµLð½ã&‘Êy{{7ò|;Ÿ1cÖWÿü‰¾4#{çôÒÔŸäèY s!‘%…††ؼ½™*ôؼòZéFR9ºÙPýó'¢¾cüоøRöŽ©.ƒÛùÞÑÀ…Åç6:Nnv]j«D‘a ²œ/$²¼ððp­V»hÑ¢±cÇÝø‚¦ ;vì¢E‹´Zmxxx [³qéí¶ÑÖ=ĸG¬*ÉÝ3¿ðÄŠzo‡‹†Âãù{Û¶°4ɇó…DVA­V/\¸ÐÒ½h…ÚÕmd\Á‘ÅÕ>‚"ž\UyåŒË÷§çW¦* ¿Ûí¥Øô˜˜3÷–¬SSr%"¹q¾ˆšIP¨:\Ø)ä AacÜYö÷oY;¦T¥Ö8¹"ç(€‰£:¹9+ÍÚK""j4æB"j‡€ÝF®Vع÷T¤d'L*¿ügõÓ*rް³ w5w‰ˆ¨q˜ ‰¨¥lÝx„m´qíkÜc¨,Ìùó©¢3qÆw+r®.Þ=#ÂU)TY —DDt#Ì…DdJûÎî£ÖÚwm—h(Hú oï ¢¾ÌPYTU˜"ívsVvshÌ¢6DDdnÌ…Dd‚Rí2低7/€pí ÂÒ‹ÿËÞñpyúÎêï)÷t:&p-C""ëÃ\HD¦äØcºÛ­ÿVØv4rêÊÁ7ªŸã¤Êïb_óÅ""²8æB"21uçP°6¯-Ä(V•Ö8'Ø)ɼ""¢c.$"ÓS:úºß¾ÞΧޯª¸Ùf¸Ùf˜³KDDtCÌ…D$ CyžÒÞ³úÒ†5pʈÈÚð{'Ddb•¹Ç‹Î®.½_ï7ñ]ìSTùEU8‡ˆˆÌ‰¹ˆLE,KßUt&®"ë@cÎ öt:vðÊ-rw‹ˆˆ‰¹ˆL@¬*ÉÝ=§¤‡Ã­ýÝÕŠ2é,µ¢¬›ƒ61ÅuË–-iiiÙÙÙí´\ÜÝÝ}||î¼óÎÎ;[º/DDõb.$"slœÔžÃ>þ.@LÌ|'U¾›m¦ô?aßûKê mùËxÙÙÙÙÙÙIII‘‘‘£F’µVFFÆ–-[.]º”““#k¡Æ` &j]˜ ‰ÈŠª:UuL- JNN^õÙJ¥ªûô9®ý‡¨Ý=-Ý5Y”ggæÙ§[±yóf__ßÀÀ@™ íܹsóæÍ¢h-!Ûœ˜ˆZ޹¬Tyyù’%KSRR´Z­ÉÛ >|ø‚ ÔjµÉÛoªö6^£íÛ·ë ¢æž‡½ÃÆYº/2R»{z‡«È¿raãêíÛ·Ë” “““7oÞ …²GÔÓV²Íˆ‰È$˜ ÉÅÇÇGGGët:ùJhµZ­V»mÛ¶ØØØØØØððpùjÝP{ou¼FZKdå52üÂÆÕÒå°}ûvQ»Ý?ÍzB¶y1™ s!Y„„„ˆˆQáí…™ÓÑÿfxÊ0í‘™‰#G±z­N§‹ˆˆˆ «÷c¾²2Ž×SƒžCïP¸û˜¾JvNîÁ¦`ññÖð÷ß°†™-3†) YUUU°Ê-w &"Sá÷‘ɺDEE‰¢ˆÈqX¿áwÈ xz"ü¬_‹Èq¢(FEEYä?ZÆñ†MÃòݸíYB!wÜö–ïFØ4Xp¼$«äädXeÈ–;‘©0’u‰‰‰ÑétèŒyOCd¯'˜÷4zëtº˜˜ÙËÕ"7p¢Þ† ÿoGA¨·8–/Y3æB².{ö쀩“ 0׿œ ¦NºVÚ¼¤¢‘³ Pš©¢B‰ÈY×J1’uIOO€ž=ÌZµgk¥ÍK*ÐϬE¥r/Y3¾wBÖ%)) €\ÏÖÇÓóZió’ŠÊôLa}¤r/QûÑnŸ¢V¹ˆˆÈÄÚóâSÔª1™’qñ)µ£¯oŸ9ΞCl¼M^¥¢$½ sߥŸXÛâSÔª1QÛôû¤1vEQ«ª”öö¾wÝß%üžÆ\(êõe™—í½Í{wŸÚ ãâSžÝ'ù\(ßB¶ÞîÝîqï:þü¡73ÏmˆŠŠ:~ü¸³³³Lå¨à{'$—ó9)–î‚Yµ·ñ¶ C?Y?ìÓ¯BÿýMàŒ9çÖ~ÖÈ«Ês³öÍ›.kǨ “Ÿrrí×màkæY}ªÛÀל\ûqñ)2 æB’Ë_ç÷<óͬ×Yº#fÒÞÆÛZˆCyNVîÑý®7‘ö¤mýáà‚'.xâøû¯U•Cµÿ÷ñ¾yÓü+úܺϜ[³ÀÁ·d¿©Õ’V€òŽ3­>%Jïàhpñ)2ÞG&¹L¸ù¾¯|ñÌÆY4g†Fð(K™Qw\÷££||0j$&Þ•Yÿõ6Óx)Iر§÷!K‡òRØ9ÂÕ >AèÞ㞀ÊF¾Ê­Ìï“ÆHn!¡}ž}@ÁÙ“ºÍ_þpµÒÎþô§ï¥ýï[ï1wÿÿãˆÿûAåÔ¢ û#³²÷ïYú öœZ/i('×¾æ,*•ãâSÔrÌ…$;û)ƒ^¹kÅaÝ¡Ã:™ÓRä8ˆ"*+‘~ÇŽã¬ÙÙxf¶,µêažñê«°æuįMO Ž€W²zû·bÿVÜ1¹ðš‘¶*+Š/ž?·v¥võŠÍ¿rü0€³ÿPr)U_ZbÓÑÅ9¨÷á×çzë}û]*§–î5µnÒ Pr¼hÒ©Ÿ¢–c.$IShy%yäM‡Ïν¶½o?^x¿&˜9Â,ã]óâ×ÀÓsV GÈu‡2/âðv ‡Â’Š[Kö …m‡î=g>}øÕ§{<6_P©ì<½»=øˆtT©¶Šþ‹>Ê=ºÿòöÿ¥'ü<8fµe;LDdA|¾d$M¡UßsXw虳ä}oÀ(.‘«ýúÉ=Þ Çÿ9ìðÚ†š¡€§ÆÎ„Ú¾åuš¯¼ªüí-‹ŠÊ‹,Ù‰ÚD±èB²sGn!¡E’«Š‹ì½|ì½|”ö†òòª’"·Ãz<ñliÆßUÅE • CE¹¥ûMDmGzzúŒ3,Ý‹c.$yM¸ù>—;åM‡/€7ӷܲŽwÇW0v&<4-iFF..™E3×=|äÒaK÷öΙú׬ɻ£îIýî‹O<ÀÁÇ/x΋g>[ºþŒƒ/<®ûi£¾¬ôè›Ïx>úðÂgü'EÙ8w²íäê6pØëx濫¢BÅf_^–uÙøeKZØ;gê_³§$Fß·oÞôœCI‡~Ÿ4¦,ërõö<ñà¾yÓÿŽÿ±%‰éá‡êòöÛo7²…êWÙØØ„„„üþûïÕOHIIyàÜÝÝ …³³óÀW­ZÕ@ƒyyyÿú׿U*•]Ïž=zè¡òòrùùùkÖ¬púôiAš;èæ”nÞG&yŸº«}H–;­ç/`É2(DÏ4MƒM$ëxOî€Á-주FŽþè·æ~3{Ê ‡þ˜Òb7¶GnØ^ç~÷A#ܨ¾gÐûÿ½î Aè»àù:Ö$ùùùßÿý´iÓìí-9<ô“õ Šé¿m9ûŸCWm¬û ÷ȾË6r©H+w>þ`·1%'P¬ÔÒ¥K_}õU)))wß}÷©S§¤ýîîîoä—_~ 0 Ÿ~úé}÷Ý—žžnkk À`0DDD„„„üøã;vÌÈÈØ»woNNN}Måææ†††º¸¸,Y²$(((??ÿàÁƒ[¶l©ªªªþ¡B÷ß¿yC^¸páìÙ³;wîܼÒÁ\H¦të‡Ãšz‰iÒá´(ˆ!?={ fnî×Ô6nù`h3úßT-o–º˜¦'} ~ìË™W¿®.]5®]ý\ü|]4v*»6{[ÐÈå¿}h _î_{àâ¾…w.òsíj’·OJ¥òÔ©S111>úhíÿ4OÑ…ä³ÿþÐPYaÓÁ¹ç¬vKÓÓÎþ烲¬Ë‚Jå?9ÚcØmu_)ÎA½ªŠ ë<( y9Õ—jíôUëÇ,™ÙcÂÓ¡ÌÎýo¿ßÈ›l›ðGP—.]ºtébü188¸u¤ {÷îÒ±cÇ‹/HMMÕjµ‡vttзoß1cš}ýõ×]\\~ÿýwc»õÖ[çÍ›Wã477·çŸ¾]ðÖ[oM:µö,Ýü¬‚ñNkÇîÍZ¬_§Ã¥4äç@aNŸEE…i{hZÍoy)Ø9š¦üOgœúõÔ¶ØÄÿ¼þó+3×M ÿxôÿ½çÙoŸ‰Ù±ì»#›ö§î½\pÙ šÔ¬‡“goï>Òö™ŒÓ~ñÈG¿Ñü;¡íœB¡••sìØ1´(ЧV,ÖÜ;yвX×C“ã>pò£7]ûºâË!1kܯﲬË6~î:²öÁß'Ù5县fM.ËHï=¡ úiºß9Xik³óŸ á/ý!QÔ7í÷5‰ƒ‡óºÏXþCEa©I,..ž1c†£££««ëK/½d0Üø_nn® nnnÒ...J¥rûöºï<Ô ŠâW_}õÊ+¯Üp~®ú}äÌÌÌ)S¦8;;;88ÜÿýÙÙÙÒ~A:ôøã;99yxxlܸ€”V{õêUã9ÅÆ—n ÎR›°óWD”–àülÙ†Ïþmñø`)\:Yºg¦dk‡Š2”þÅK©¨T*‡š¿ýEˆ……ûS÷wÚ©ì|]4~.~¾.~]]»ú¹tÕ¸hÕN 4>*hô‰ôãÒvYUÙÛ—î9¿{Aø+®®-íwû#åBååå«W¯;vlxxxKNª,È/¹”ê6`(·Ã.lZSYp¥èBrÿ7b ¥êü†¸‹ß}  Ïóo:uëŽê+AÖãñgk7[{I f÷ÐzJEÈìñÛŸûO~jæŽçÿ{håOƒž¹·û]C…é#ïÁ=Ý‚5VüxlmBÿÇï¼iz˜Ê¾E)ç¹çž;þü¡C‡ŠŠŠ¤9¶úæÏDQ,++;vìØóÏ??eÊ—«ÏˆwêÔéå—_¾÷Þ{Ç?uêԻC‡zÿðMOOÏÉÉ m|EQŒŒŒìÔ©ÓÉ“'õzýƒ>øÔSO}óÍ7ÒÑ3fôíÛ÷Ûo¿ýå—_žþù‰'îÛ·ÏÍÍ-11±oßëVÇlFé0’U0ÞW]1±±+«I!ÀÑ}û o¸»aÍøô3¼ú’I»i2ͯ‡iZ\<žƒ[ÚÏÆÞ¬)«*KÎÒ&gi«ïtst׸hü\ºú¹võsõóséêåì­T\ýºÃmA£>½þ ËÄ”Ý3Ö>ôbø«-íwûcÌ…DQܺukZZÚC=d’‰êª¿Ýâ?)ÊR”´]–uÿ<¬™õ×®3«Þ/˼ìàãWGW¯_ȴݳ”ÀqC¬ø1ÿB€+)—æ­:øéOƒž¹'`ì ¦Ãâ¼™)ßf(/N3èË”*ûÎöÎÝ\oòî9SP´—%ICæDþSG+ÕÍ~EEÅÚµkÿøãž={xíµ×–.]Zg.ìÕ«—qûž{îù¿ÿû¿êGß|óÍAƒÅÄÄL™2ÅÞÞ>::úí·ß®30fÊÆØ»wïÞ½{÷ïßïëë à©§žzâ‰'***¤§#""–,Y"‚··÷Š+¸ººJ%jt ¥À\H¦ôdzÕÞùÕ/ë|C"ËŠ†÷FbÍØSGgðçs{[òâ§‘|ã Œ4-öl6A.,¸P´oÑ¡¿Nü¥Ë½˜š{A—§»˜—šžÿw#ïçgçgWéØFiÓ¥£ŸkW???×®¾.šKyºê—ä•ä½øÃóÝïïvþ§‹-í}{¢TÖü–Ú±cÇ¤Ç =<<šÑ sGß®¹Gö¹¹5çÐ_z÷·qîäätéçoº=øˆ(Šú’âú÷öv[Ñyíñ÷_¸x¥Ê¡®ª- Ô6JÅÀYã~{áZVÈÓ¦ýúôJ·`Í gîõ¿cZöb©(êS¿“‘üûŽA®¾w Ûʲì’+gòÒòÒ:NQ¶›\è{KÏ~™I)Js ßùêhìÖ³Ç÷zðV…MÓâŠN§+--5ΫõíÛ÷ôéÓuž¹k×®   ÷ßÿñãÇkOÆGFFFFF^¾|yýúõK—.=vìØöíÛAˆ}ì±Ç¤s´Z­““€¼¼¼Æ¿õròäI“'OV©T +++³³³¥‡&£¢¢¤ÎH1±Í(ÝæB’WYeéW¾¨óŒ_@qt€r úè£!C†ÄÄļøâ‹µOóòòzöÙgïºë®^½z¥¥¥ùúúN:uܸqÒQi!éÍûï¿¿‘”ßÊ•+===«÷§‘—y{{7µt˜ I^ßýNúþGu²Axk<v—«ýúÉ:Þ 9¿oÄ;“1ó„އòŸßÁ¢ˆsG±ý Ly ÎnÍlßFiÓÍÍ¿››õù¥W.æ]Ôå]¼˜›z1ïâÅÜÔ¿óÓ*õ•Í…½§ýNCBoá¦B°+zN«²°àü×ÿgž ÑƦîXPZZ{÷Ýw=ºÇ í<¼j¯×ãÔ-0ä½ëÖ`³÷öðÖÇiAP(nzù=iÛ¸¿¾%j¸ËåfÕþ ¸š¢ÜÑ©¯1)n›  (‚B…  …  @þÙP\=|ý~APÆýW÷‚ PRÃW7„U?­V 5~ìóðí{ÞÝP{DÙ'/ny|¹g?ÿAs'ø¼©1¿ÕçÊH^¯T9öõ¹ÚѧÆQµ£¦sàCMm³µëvûÍnÁšœÓ×Ým(¼”ýÛ‚ÿ;´ê—Ásû|§¯¯¯ƒƒÃÉ“'  ))Iº¡Ü€Áƒ?òÈ#o¿ýöôéÓ¥»ªª*¥RYý÷—´_ ×}Þiâĉ¯¿þzxxxõû¼Òû.5rª±"€¬¬¬ðððŽÈ¨ö}-…BÑÔÒ `.$Õž<“+~¸ôzáÂ\ÔÀÔÉ&®r#foô{0èñÇ·øäi¬yþ7Á¡J ‘zùYL©ã/º-ÒѾÓMönêrm~RoÐ_.H—f/æ¦^ÌKÕåérгߦ†ãâÑËâ߃2. ôû¤1jWw(be%ͽS|ïªã/Ó¢^_–yÙÞÛG_V’žð³µ=×ÀK”ƒá§Ÿ~ºtéÒäÉ“ox§ÉŒsí/ì½\}Ï}nƒ$.þÚB=2̤óÿ{ôÃκž7ÁwDŸÆ_˜uþƒ® ›í?ÁÑ‚R!( ¥BP*… ( …BP)…ðÏNÅÕW·…R)üs¾âŸ®5¢TTß)(¯ž£P)¥kn+‚R©P^ýñúþ(ªëÛWÂõ‡zܺç=]í¡åŸ¿œ0oÕ¡•? žwß ïàÛØØ<òÈ#Ï=÷ܪU« Þzë­Ù³oüeÔÅ‹oÚ´iÁ‚ëÖ­œœ|ÿý÷O™2%44ÔËË«  à£>1bDõÅqª{ë­·†:xðàçž{®oß¾eeeû÷ïÿüóÏ;uªã%Èž={Nž|Cý¯­]\^$=¤˜š›z2ýØÁ‹o¸6M6² Û<ºeªwØêÿær;/ù§’޾ùœ÷è;•ö5?ß\ž›µoÞôFÎx™ß ×8|øpZZÚK/Yé+VÕYÕô°Ée>÷ó#˼õhü%Yû¸ú´èƒ45ªô¨Ò›°Ak“{6mÛ¬}» ž7ÁoTCÏÓ,[¶ì©§ž0`€­­í“O>ùÌ3Ïܰñ.]º¼üò˯¼òÊ“O>9bÄ//¯ˆˆˆÍ›7¿ÿþû®®®ãÆûþûïë»ÜÃÃcïÞ½o½õÖ;ï¼£Óélllúöíûè£ÖÈpÕ}þùço¼ñÆ /¼––æââ2a„zøÊ+¯DGG—––mlvéú0’\Œ“gò&¿ÊÒlÓ™i¼€^CÑk¨|Í7‡£Ú)Ø«W°W¯ÒÊÒ™ë¦5fÁÂNpñ|÷¦0C÷œüƒDƒA_Vª´wø;~óå[+òr:õé<ûÅskV8øÂãÓž{dß¹µŸ•çfûŒ½×Ê£fè[ÃDQT( ¤CFmÎ.5OÛ…F Û&üWµ¼è»þ7<“jÈ:~áÑ1^Ï¿Ï'´Wpppí»«kÖ¬‘>=WŸÚW½üòË/¿ü²´Ý©S§>ø Ióððøøã?þ¸Ž§2Œ¬Þ[µZýî»ï¾ûî» t¬úùóæÍ«oµJ7 s!Éåû£ßusó_4îY’õhoã­Ïòß>L»r©ÞÃ" / ïv‹àë'%¦YöþŠbeaþ…Mkºhl;¹p<¢Ëã+‹ £'<ôx÷Gfeïß²ô?Ò‚,$ xû“’K޾ùœ5äB ä¾}ûN›6­UÜDÄ_òŽŒ  þ#'â·;Ï>û, ¢(D¢Áƒ(ŠEDˆƒh6¤=¢Q¼ú£(íEƒhÜu(Š¢ÃÕ†¯nˆÕN6üsR-÷ô†²œ‚†×+ÐÜÚ7dN¤WHÖ½ÐÈ_ƒ¾ €RUs›Iå V¨øyc.$¹ø»LÔŽšnoã­Ó.íÎ_ŽÿT{¿BPÜìÛTÐíSF=T‘_1#ÆLó[{ç<@igß1¸oŸ½%=¤´³ÏØõkif:CUÍh‚ŸzAP©l;¹*›ÿnÍ )•J¥R©P( Eí ãÒNWUUU»‘‘#GFFF6õ¡rKŸsŒúHõß}sÀ¦—Íý(pSí]¶éðª_ê>&~#û z:Òóæ&¡R¡´3èËôU%J›&ßì«Ïã§cE½A4 zƒ¨7ˆQÔ ƒX¥—®tôÚ9ƒ¡êŸ=zÃÕsŒ'üs¨úNQ/µ£ÿg§( †*}mƒþê×õçú¦ ÿôPÔ z½t¾¾¼2/ùï†R¸ t}sÈœñžýLôUPª†¹ä2Ìß4k¯·ím¼µee/ùõº»!6J›šQA·ßx['ûN*ò4g—†~ò¥ô|¡‘h0zuŽï÷u¹c|ꦵµ/T*rßó\¶lYãO6ÞÕ2R(&L¸ås?AÛ>•æ_›PÇAè6¦ÈœH¾Ýš×²Úѧ´à\IþÙî&»É P)¡ª¹æeëòÇëërµiuBÀØAgw Ö˜¹Wís!™€qñ¶·¤ÅÕ*õnÃFp«Sƒ_Ì3¿Êü¼’K©îCoÓ—0”—«*Ê-ݵzÕ˜T«ÕÓ§OïÝ»·¥úÓÞýï–Ê’ëþõ‚ÿ!!OG¶0tpXZp.W·Å„¹°µ+LË>µqWíý ¥"pü°Oséîmþ^µ+Ì…Dd›m<‘~lLÏ;FæjocoéÕͶ“«Gè¨ýóq î9|ô±¥¯ ]¾Îmà°/<~Ó‹‹-Ý»ºUÏ…;v|ì±Ç||Z´¬‰´‚ðÏ—T¼FÝÙõi½X/ÿ¾-mË÷•…ù¢^¯°µírG¤&rRKúcÍJ³ Ž±Ãø£ î2;Òµ‡ V–ñð¿?3囌sÜ»ÞãèÚ÷Æ´Wl6T^÷Ô„ÂFÕsÂðOÞíìçYßUdBÌ…DÔRÑ qñû߬_ŸH¶u/=#½ç½Vc_ßïÔ¸¤Îå -Åø)¼.]º<öØcM]¬NÆ|š*mË÷i[¿ïýÜN]»¨ÈË)ÏkÂÒ•­ÎáÿRUZ@P*ï:pöxΚ?A IDATW9¹ÝìÑmBÖ…ïOýÕmàkn~w ‚ñwX”{,óÜFM¿gmÔíåã@ù2Î~¿Ûø£ÊÎ6øÁ[û?~—“w{ù°Ì…d]FýÛo¿!3žfü«af&€~ýZüi¹¦“Æ›w“­k{cÙi€IÇ«|¼R>Ò|a¯^½yäµZ-S•¢ Égÿý¡¡²Â¦ƒsÏY qºÞ?-ÿÌñ›_ûçiHQLýþË^O¿$…B¶.n¶.ÍýÀŽÕ+ɺrò« ¥"èžÐ³ÆwìÖÙä%º zCõÙ©›Ïí}!õÈ»Ž.½•6ô•…%WNW–傦Ÿu-´.«Ë0è lÔ½§Ž¾ùѶó­íÖ‚¹¬ËÕ7Μ5k.t‰gÀƒ™ç¿-Ê>T¹O4T*UŽvÎþÝ&¸ûO°Q·ÙØ]Cž6-ù—½¶ìûNë7#ÜÎźMn?˜ ɺ„††nÛ¶ ë7`Äp˜gƒë7H¥ÍQîzÒx7¯Ä p˜ç¬AÍ+¯–6G=j±Ñ£G›üV7µ+ òK.¥º  Àmà° ›®.¬?±á¯µmCŸ»_©®ûûÔ¦ÕÁcPAf(dÍ’Öü:xÓÃl;XéÓÉíDëXøŠÚùóçk4œ:V ÁUdMCñÑ œ:­ÑhæÏ·Àýi¼É‡÷*Ä|ðÌDâ^EòaXj¼Ô –LðׇBÛN®6:^9~ØRÝ13ó„B’ܶhúÀÙã -޹¬‹³³s\\œ Øü3¦NGü¯Òæ—™‰ø_1u:6ÿ,B\\œ³³³,…doÂ:Ì]›®>ügrÙiص sG a,8^²N6Î|»æÙ çÐ_z÷¯ûÕÇ»²îï^š’ÅÇKÖHz=ýò™UË.l\£rt žób}'jÆOTÚ;$Ç­(ÏÍT*µ‹»ækÿZ 5s!Y£ððp­V»dÉ’ÄÄÄ””­VkòAAAÇ_°`|ïx6R{¯ÙTäçùtÉM/¿géŽX—:—àqêòÞªžAèrÇø.wŒ—©oDdYÌ…d¥ÔjõÂ… -Ý óioãm¡ÌÝ;R¿ûB_V*êõJ;»®÷Më|ÛµO3T”7þ.§¨×—e^¶÷ö)˺¼wÎCÖ³~!µ.ÒâS%é¶æ{å¿¢$]*m¶ŠÔV1QësúÓ÷¼µ¢C÷ž*ò󪊋ZÞfynÖ¾yÓGnØ®vó ý÷7-oÚ'iñ©¢Üã®fÌ…E¹Ç¥‰Z‚¹ˆZ%QõcY¶]l;ºHÛi[¸üÛjwÏàÙ×=$WãÊÁ±4=íì>(˺,¨Tþ“£3ÿLpð…Ǧ=™ôö¿¤ùÂ:W{¾é¥wÏ­ý¬<7Ûgì½þS5ç¨ÉúI‹O¥ŸŽuñ¹½Ú÷Kd$ŠúôÓ±àâSd |ý‡ˆZŸàY Ž/}õÈó/ý¼©<'KÚYpö¤nó×ý}²äß*Ç´ÿ}k<¿ÎC'?zÓµÿ¡+¾³Æ}ððî̲ô?ö^]®^&ЧV,ÖÜ;yвX×C“ã>–vgü‘0àíOú½üÞ¥_8­H5I‹Oå&]8ô–yVŸºpè­¢Ü$.>E&ÁùB"j}ä–¼¤ƒÙûÿLývm·I3}"&Hëêýo €’K©úÒ’Î#Ã¥ókª,¸Rt!¹ÿ1Ò}‚²Ž? ë[í9ø©•ʶ“›¡²Ò£¥VEZ|*<<<ó܆üË»}ûÌqö"dz†%é™û.ø¤¼øŸ"Sa.$¢VIa«v4ÜmÐðÎ#ÇïeŸˆ ‚JeçéÝíÁG¤”j;CÕÕÜVû´!6kítA¥€öûºê‹OÛWï¢?¦ÂŧȄx™ˆZŸ¬=;«JŠ¥íŠÜl[7n!¡E’«Š‹ì½|ì½|”öÆók²qîäätéço Š¢ÁPUT¨PÙ0T”¯jìjÏDµH‹O-Z´hìØ±AAAr” ;vì¢E‹´Zmxx¸%¨â|!µ>™‰¿¥|ù_Ñ  µ›gïy¯pðñ žóâ™Ï–Šz½ÂÆÖmð¯Qc¥ókêöà#½ç¾zzåÒ¿ãTÚ9øOö å6pØ¿éÅÅWË4zµg¢Ú¸øµFÌ…DÔúôynQûÝp4¢úã2„µÙ{ûxëãê{ú.x§ÆU ¬ölçáÅ5‰¨á}d""""˜ ‰ˆÚŒÀÀ@åÙ™–îHMR—ºtérÃ3‰È²˜ ‰ˆÚ•Jàòïñ–îHMR—¸Š ‘õc.$"K²Ú).9HÔ†,‡1cÆ‚úíºô„Ÿ­ä—´<;3=áçÔo× ‚0fÌKw‡ˆn€ï‘%§¸ºÞÿ°¥û";iÚL²###7oÞ,­àm=AˆŒŒ”/‘©0‘‰‰"DQ4ˆ0ˆ¢(ý¿Q4ˆ°wvE%Ô""„Ñ÷e\ùZ÷ÃW¶;¹ö¢v÷´t÷eQž™{dŸ¦ÍFÕ«W¯-[¶\ºt)''G¾BäîîîããsçwvîÜÙÒ}!¢c.$"Ø}"gýŽKå•Cƒ_™¼p€Súj»|ß5£Ïú%[Û—Ì3mÖ¹sç3fÈZ‚ˆÚ*æB"2}ܺz:|öóùôܲ&]h‹²>s5 XÏ—ÜÜÜ|}}9mFDV޹ˆLÃ×Ã~áÃÁ_îÐýy¼±ÙN€è§8­D§¸ˆˆ¬ßG&+U^^þæ›oFDDôèÑCA="""Þ|óÍòòò÷F~mc¼jEÔØ®OÜíoo«lÌù„ùúCDDMÂùB²FñññÑÑÑ:N¾Z­V«ÕnÛ¶-66666Ö²_ocãìâïåðÙÏçS3J8ÍI¸â)È8d""j*æB²: ¢(ÂÛ 3§£ÿÍð”áÕÌL9ŠÕku:]DDD|||XX˜é«4‚q¼ž<ðz‡ÂÝÇôU²Ópr6}3Œ×`Ï\***­jà*ü§eê5ï#“u)((ˆŠŠE‘ã°~-Âï%ðôDøX¿‘ãDQŒŠŠ*(°À MãxæaùnÜö€,¡€»n{Ëw#lä¯A÷œÌ}yõÉÕÛRs *8S£8£BC'‘ù1’u‰‰‰ÑétèŒyOCd¯'˜÷4zëtº˜ ¬“"7p¢Þ† ÿoGA¨·8&¯(bÿ™¼×>?õß-2¯ÜàFA×AÈ3au""2 æB².{ö쀩“ 0׿œ ¦NºVÚ¼¤¢‘³ hÔ{& P"rÖµÒ-'‡“¯¼¾îTíEjlTŠ §çg¥óR\0Ii""2->_HÖ%==zö0kÕž=®•6/©h@?³•Ê™d¼Iç ¾ßýwí÷KTJá–¾nã‡zï?›§M+2î¯(-üý˗Ǽö¯–—&""“c.$ë’””@®g ëãéy­´yIEez¦°>R¹Ž÷ÔÅÂïvÿ}îïâû axo×ÈaÞîm¥«ÝýÍÛ…¹·¤.ɇ¹ˆšælZÑ÷þ}æRQý AìrO¨wguµ×NÕÏ}uR‚y:IDDÍÀ\HD•’^üýîô©5_d€.÷÷îâfWóÐ?¹ÐÇÝ~òhßGÌÐK""j.æB"º±ÔÌ’v§Mɯ±_nîÞqˆ.û:/T[•âÉqþ¶*¾èFDdÕ˜ I.i9e>µfÚ°¶:Þ´ìÒÓi¯ˆµõíæN÷ðÖthdSÕ3ÂýZÚ!""2 æB’‹ÚF1¨óÆ]i§u…§u…ò¦¥ÈqETU¡ ç/ av`PÞxNfš½3ÏxõUXó:â×€¦'GÀF+YH=‰ý[±+î˜Þ¢\˜SXñӞ˻Oäè 5¡¿—ã„Þ}»97©Á¿bí¹G""²Ì…$#i ­ ¤ €¼éðÙ¹×¶EÇŽcñ8ˆ…obÙ(Ì4kh†ñ®yñkàé‡9+Ð#äºC™qx{óCá•¢Ê_ö]þ=)»J_3ºùyÚß;¼ËÍÝ;šoö•ˆˆ,¹ddœB3î1ÇÜ¡  ßMˆY†GŸÀ¡ÃHLÄ-#d)T‹Üã½pñŸÃÞ ¯m€‡¦æQO?ŒÙœf Jªþ·ïòΣÙU†‡|ÜìîÞ%¤G'&B"¢ö€¹äU} ÍÈéÐÛ ÷ß‹uëñë³åBÈ<Þ_ÀØ™u„Âæ).«Ú²?cûá¬òÊš‰°³‹úžáÞC{ºšñM""²0æB’Wí)4#ÙÓáˆáX·§Ï˜¾åúÉ:Þ“{`pD û¶vN}F>ôÂO”Vèkrïh9Ì{xoW…¹î¿‘•`.lkVþt8ãóžzÚ¸¹ïƒC-©„•Æí¨¦7%c:ôÓ@nN#OŸ¹ì`3úßT-o–º˜ #^ì<¢F(tí`;n˜×­}Ý”L„DDís!YcZòêrùÜAÓ4jgúšóaÖ yã-/;GtàøÎµ¾Á×n¯wt´7Ôkd?w•’‰ˆ¨ýb.¤¶«¤:4m]kfk‡Š2”þ±«Ö+=ù@zòïÀAìUwé|{~¤Žˆˆ˜ É*ï«.˜d¢ÉBuÀ?w“­LóÆë¡AšO£ç`ôáЖOã6l»#Ä“‰ˆˆ$Ì…mÁ¬ñþ€“.YxmE“'“W·¤ú­3nÿñì_µOغ?£Î÷0$2¾w²ç/r£ó®Zý|ˆIV]–o¼Áƒ‘¦ÅžÍ¦É…™©Iwõ2ACDDÔV0’¼Ê+ [dÔyHÞuj2³ðݰ±Á]cei¿²ŽwÔdl_„/pÛƒè×ìfˆˆˆêÆ\HòúíHVÅü w"pü/Eq1f? ¹ªÔEÖñ Äȉø}#Þ™Œ™ï t<”ÿüEœ;Ší_`ÊKpvka""j§˜ IFµ'ÏäJ„.QDI ’Ï!õ" <…î3q¡™a¼ÑïÁ Çßâ“§±æuøß‡()DêIägA0åES•""¢v‡¹dT}òLÞ9ÂÍ?_ݰµEoL¸÷F¢«Ÿ,µêg†ñÚØbörÜ>;¿Æ™ý8™ˆªJØ;Á;#Ĩ‰pv7mA""jG˜ I.ÆÉ3yáÎ_ei¶éÌ4^@¯¡è5T¾æ‰ˆ¨b.$¹üv$«‹›ýSãäMHÖ£½—ˆˆÚæB’‹»}ÄàΖî…ù´·ñQÛÃõlI.7ù·4F{/µ=Ì…DDDD0‘„¹ˆˆˆˆæB²6£G€ÌL³VÍÌЯŸ>-'7»ÞÏ)ËB*g‘ñ‘5c.$ëbkk gΚµê™³¼½½ÍZÀ?ãMI2kQ©œEÆKDDÖŒ¹¬Khh(¬ßƒÁL% ¬ßp­´yIE7¯„Ao¦Š=6¯¼VšˆˆÈˆ¹¬Ëüùó5 NÆG+ в×E|´§Nk4šùóçË^®i¼É‡÷*Dù“°h@Ü«H> K—ˆˆ¬s!Ygg縸8A°ùgLŽø_åzÖ03ñ¿bêtlþY„¸¸8gg ,@hoÂ:Ì]›äzÖ0; »6aî$¬ƒÇKDDÖŒß;!«¶uëÖèèhN‡ÅKå.§ÑhbccÃÂÂä.TŸêã]9Oör/Y-æB²FáááZ­vÉ’%‰‰‰)))Z­Öä%‚‚‚†¾`ÁµZmòö›¤½—ˆˆ¬s!Y)µZ½páBK÷Â|ÚÛx‰ˆÈ ñùB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆ`.$"""" s!Ì…DDDD$a.$""""€¹ˆˆˆˆ$Ì…DDDD0‘„¹ˆˆˆˆæB""""’0À\HDDDDæB""""˜ ‰ˆˆˆHÂ\HDDDDs!I˜ ‰ˆˆˆT–î@yyù’%KSRR´Z­ÉÛ >|ø‚ ÔjµÉÛ'"¢6€¹Èòâã㣣£u:|%´Z­V«Ý¶m[llllllxx¸|µˆˆ¨•b.$²°„„„ˆˆQ=5xà9ô…»é«d§áälú:.""">>>,,Ìôeˆˆ¨5ãó…D–TPP%ŠbØ4,ßÛ%p÷Ám`ùn„Mƒ(ŠQQQ²T""¢V‹¹È’bbbt:]àD½ Aþߎ‚Qo#pt:]LLŒìõˆˆ¨Ua.$²¤={öˆœ…ÒLJDκVšˆˆÈˆ¹È’***ô3kQ©œTšˆˆÈˆ¹È’~ûí7@®g ë#•“J1À\HDDDDæB""""˜ ‰L¥üò–îQ‹0™Fe~rÎÎYû-Ý""¢fâwðˆLñûä¢3qÙ;g¨=wè3ÛÖc°U&û^÷£nÞè޷܇þ£!rÔ$"¢ö‚¹È4•½SϨ‚¤eåYûËeN‡aC¡¯Bat§±ûìþ7݆y«àè,GA""j˜ ‰LFš24”ç5F¿wm[qf>‡c»ó8^YoŽïéQ›Äÿ€™Œ4eX}OyÖþì3d}îP<¯m€½Žÿ‰ñ2Õ!"¢¶¹È”»OV¨]kì4C:ôôCDüù½Lˆˆ¨íc.$2¥ÚS†Fr§ÃAcàÜQ9Ú&"¢vAEÑÒ} «rþx’kàµÆçAðõ¥Æ^(½\çù¥E˜ • ¾8ߨv” é¶Ûu¹½±µ‰ˆ¨­ã|!‘çCû8šªMµ=èõ=q´wîî§ Ž¾Ñ`ª>Q«Æ\HÔF”€S§Füp˜ËÃa.ŠÎ~žóÇㆊ|9»FDD­s!‘¨=»úÜmÔç{N›ªÍ¿“À'ðÆg* Â[3½Œ?–gìÉÞ>©*_kªžQ+Åõ ­ˆÛ­«ÌVkUàLãö“É«[ÒÔ­3nÿñì_-iªm(:³º iY}Gå[ïúPÜtëÏ4(Ä{^ˆ}Þ·‹›´§ªH—µã!—!ïÚùŒ1yLjˆ¨µà|!‘)‰U¥EgâêÅuÄ'*'?Óv›ˆˆ¬s!‘ÉTŸ,”ï9B _\ݰQ£sWŒ‰ðéð jfkUι{æÊr¤=Uç²·OrºLí5Âý%"¢Ö¹È4Œ“…²&ÂÆ¯€Ý$¶î=ÆlÌM|¦2ï„´ÇPQóç“Î7=ëÔsfÃ×Q›Áç ‰L£øÜ×6ÎÝe}ŽPVJ/÷Ñë컎¿¶K4$-ËÛû‚¨/·\¿ˆˆÈ|˜ ‰LÃÎûÖVš¥ÚeÈ{Î7ÿ µ?J/þ’ýÛÃú’t vŒˆˆÌƒ¹È4TÎXQº5pê1ÃíÖ+l;÷TæÌJ˜X‘uÀ‚½"""3`.$¢šÔ‡»Ù êxíMCynήG‹Ïm°`¯ˆˆHnÌ…DT•“Æãö/«þD4TåzóÊÁ×+ÚQÃ\HDuTŽ®Ã—wè3»úã†%)›r~Ÿi(˶`LjˆH&Ì…D–4zôhÙif-*•ëׯ_#Î:ôžåú‘ r4îªÈ>œ•0±2÷¸\ý#"" a.$²$[[[)If-*•óönì'óì|ÆxŒY_ýó'úÒŒìÓKS’£{DDd)Ì…D– `óJôfªhÐcóÊk¥Iåè>fCõÏŸˆúò¼}/æ]Ñ\]'""™1YÒüùó5MòaĽ Ñ {9Ñ€¸W‘|fþüùMºVaëìv˪Ÿ?)>»6ç' ù&í&Ys!‘%9;;ÇÅÅ ‚°sG`×&¹ž5ÌNîM˜; ë B\\œ³³s“[ÎýžwºTPªûÊ3öd%L¬Ì×6âz±É‰ˆÈŒø}d" Ûºuktt´N§[9Oör&666,,¬Ù-ØûÝ­êàŸ›øŒñ#(úâKÙ;¦º ^lç{GŸÛè8¹Ùu©­Eþ…ÈZp¾ÈòÂÃõZí¢E‹ÆŽtã š.((hìØ±‹-Òjµááá-lÍÆ¥·GØF[÷㱪$wÏüÂ+ê½. äïmÛÂÒDD$ÎYµZ½páBK÷¢ jW·‘qGWûŠXxrUå•3.CÞlœjœ_U˜b¨(xün·ÿgï¾ãk:ÿ8€ν7{ïMDB[ì±bÖ^µ)J©=ZTQ›ªÒR”jUªFð³•ØY"Cö’y³î=¿?Ž^‘å&¹çÞ›äû~ý^¿×Éϸžæ~óœg,Ýçëë«äÒõTÑA®„¾Q!!¤’ȨÅ*ã–_1 ÙÉÜØ+IÿU˜Yìæü”'†w563*µ”„BäFq!!¤Jt>1ërP m.;S˜ž|iD^üÍ¢·å§< ­ÉLð2Uv !„ȇâBBHUiš7·èyBÃÔ]vFZ™rsfVðÙäü”w‹wOô62…*(%!„¡¸¢B+ó®‡têxŠ•f<ý>íî"V’+-È*Ì çN› uåYÔ†Bˆ²Q\HQ F¨eÒfƒQ³Å`Þ GMþߨ¼¸«Eç)7ÐÆÐZ†„¢~(.$„(’žëx³N?4dg Þ¾|ûà«¢÷è‹ÒmuŠOL!„¢rBLËÊÓ¢ç £÷ 1²…âb÷4ÔªÜBBù8Š !Š'Ô³7ï~TÛ®Ì]UÌ4Ì4”Y$B!Eq!!„Ò¼4¡ŽeÑ¥ ‹¡.CBQ7´ß !DÁ R³BŠßø—¹'ÀV'R_”žUhTÎ=„B”‰âBBˆ¢°¹q׳‚ä'Ý—çnlýgÞvä»X„BäDq!!DØÂœÔ[³óP‘huC3ZåIµù+!„ùQ\HQF¤kÖå€4?£ õi~Ê“üÔ')O¥™å?%d õŸ?Ïh©œBB)Å…„…hjYwԲ03"?åq~ê“‚”'¯Jnè¬÷"(³™„¥ßE„¢zô»˜ÂF 2t:éÖ€-ÈÊO \4s@KWÝNæZ‚\î.-A®£nèípÓsçÎÅÄÄ$''«´Ð|177·³³ëÓ§•••ªËB!e¢¸¢ Œ†¾–e»í&ðõ¯/J7ÓLäþgÇ|·é‰DZ“wÆKNNNNN~úô©O×®]yÍ+!!áܹsoÞ¼IIIá5#yP@LHõBq!!D² ² "s\ÂÂÂöîÙ-ÔÕ?ÛÔ£–¹¥ª‹Æ‹¼äÄÔÇ¡vøùùÙÛÛ;;;ó”ÑÕ«WýüüXV]‚leÄ„ª£¸¨©¼¼¼7Þ¾};<<<44Tá黸¸899µoß~ñâÅZZZ O¿¢j[}e._¾,‘²ÇÚôì¯ê²ðHËÜÒ¦gÿüô·'^¾|™§¸0,,ÌÏÏ¡ë¤9jd+- &„(Å…DùûûO™2%::š¿,BCCCCC/\¸°ÿþýû÷{yyñ—×GÕ¶ú•‘‘Àº‹º”‡WÖ]¼"NäªÌ‡Ë—/³,ë8tœúÙÊ ˆ !ŠBq!Q;—.]òööfY6Öøt<<šÁ’‡nÄD<~‚ƒ‡¢££½½½ýýý{ö,s3_^Éêké€a ÐÈævŠÏ%9/þÅÉï¡òú @‹¨A! IDATz¶”€«&We>B-ƒl¾bBˆ¢ÐþÈD½dddLš4‰eYøôÇÑCðêÅKPÀÒ^½pô|ú³,;iÒ$•|iÉêÛs¶ÝBça¼…ÌíÐy¶ÝBÏqPa} ¯Â –A6ß1!DQ(.$êÅ××7::n 1o†÷üóæÀ­att´¯¯/ïÙ•ÀÕ×¹9&­ÃÿŽŒ“ÖÁ¹9TU_B!êŒâB¢^þý÷_=e5N£G¼ÏZ¹¸L}fA TRŽ!|f½ÏšB‘¡¸¨—üü|hàªÔ\¸¾ÏZ¹¸Lš*5S.;•Ô—Bˆ:£y'D½\¹r_c Ëbiù>kåâ2åiLaY¸ìTR_Bj¡ôôô·oß*0AkkkµZmŠÔ$B!Šöõ×__½z5=Ï:3é¾S67·077ëÔ©Ó† LMM˜2!B!Š”››»lÙ²mÛ¶I¥RZzŒ–®­¢gYirrBrrRPPÐo¿ý¶sçÎñãÇ+*qB(.$„ÔL×Fôж°bY–-,êèØ÷jë5PžY‰$71^ÇF¹o÷I 2oÞ¼~øa„uš-2±í¦mà¨à XiFÒ½7Û3“N˜0A(Ž3FÁYÚŠæ¾Üy]»¦»Ö¶úV mwm·ë˜ç¿;OœýêÐ9ŸÊKM ˜G0¤’.^¼¸oß>F jÜã˜MƒO`†–mu?bï>Àܹsãã㟠©•(.$|y>÷÷YÞõœÒܾ/ÙtíõÁzº°³C×.>"¥6oåÔw¤ý?jhÁÌõ=Ðq<º)c!ðêåÚˆÜYKÏÆ_| #äE´ßo­·jëíÚsö›ýbýOwøé/‘¾X@ý ³’ïÝj¹iŸ KNª©‚‚‚ÇŒUý‘ÊÉÑÚelzüÍ{÷î)';RãQ\Hø¢­¡3ªÕØÝ×w<Š~ø(šçèЧ?Xˆ‹Ç³@„„"9s?ã%¯2(³¾=Ç‚e!)Df¢ƒpë/Üú M:cÞ^èò‘auÕåøeiA~vÔëW‡v‡Üá:uþÛÀGB~ôó&R"ÎÑ021tiôhõçÖ]zÛtï+Ò7Pu©I5 -‘D¨¡¤†¤gÒ˜a„úúúÊÉŽÔxq]hi9iø–¾øüýqÀ=,Z†‹—”B‰õ²áý1Ë"8»æáÙuøNÃò£ÊØO¯,’ ¡†Ê²/@CÓ ~çOç~óH•åøÏÝÙ£ïÌykÒÀÈ?u¾€®]†³—ïÙtoþÄ‹¦Eÿ}B’+~²fáý…S­š[oÄ$ CcMcS³íî«Ç¼“üü|–e+ýxnR¼leUR¸;{ôÏFÝž2$`Þø”‡w¸K×FôÈMŠ/zÿÓ? ˜7>ÖÿtUr$¤BÆŽË”fݺur¦Pô) –-[^»v­è áááÆ 377†††-Z´Ø»wo9 ¦¥¥}ùå—ÎÎÎ"‘H[[»AƒcÆŒÉËËžžþË/¿ b=$\V ¡PX·nÝéÓ§GGGW4zLø%uWò/oZ_G`ãfLùT1 V²ë[D«Þ8µ¯ž(<áŠéâÜmë•ï?ÿý³Q­ÆNn?U…¯•»¿\êyóVÌ[u(z¦Õw?~pø/þ†¿‚UHzzú©S§Æ§£££Âb´ÝyX6îʹ}[<÷ž(ý õqÀóÍ«ä\*R±,‚¢3ÝêÐxSeJÙ´¬3CÍJ<»iÓ¦+VïׯßË—/¹óæææò'òÏ?ÿ899I¥Ò„„„]»v 2$..NSS€T*õöönÙ²åéÓ§ŒŒîÞ½›’’RVR©©©žžž&&&7ntqqIOOðàÁ¹sç ‹î^haañÝwßU¢¾V­ZõÙgŸYYY•ZGGǬ¬¬/^lݺµeË–wïÞ­W¯žü‰S\H©Ó–v}D1ÑÒ¸I`¥ÈÌBz:¸Âw3š5­h¿o[‰òWÑ¡m}x› ïý§6œzäSÓ:uMê:˜Ö­cRÇÞÄA[¤]Åbtvé²íÊ)+=rïÐý¨€U}¾®cZ·ŠiÖfB¡ðåË—¾¾¾“'O.õk ²"ÂB~Ø"-È×00l0k±¶…•8.&dß÷¹IñŒHToä‹vK’a ]Ü ³2K½ÈJ¥ùi)E—ªÖ÷CÞžº7¸½ E‡|˜×cÄy’ž6õmõ*ô¬­­­­íûíd6lX‰899q6jÔ¨eË–FFFQQQÎÎÎ"##CCC=z¤§§ÀÝݽGòúàW¯^mbbríÚ5YØ©S§yóæ»ÍÌÌláÂ…•(*€µk׎=ºÔ_²Š´iÓføðá;v\ºtéo¿ý&âô™¨Ù›V£ú•šO71HO€Ì,… ?_±%T¬ªÖ·4Z: ‘È{¿A½ „—_^Ø{ßê3Ë?=<Îk{·a?üâ¹¾ÿÛüçã“÷"ïÆgÄKYi…Ša¡oÙȦ1wœ4ù× =ù“Eåß„Ör@RR’¯¯ï³gÏ"˾ܱÞaÐÈV›÷›6ov`;€[טz´i»ãHß_Ì[·/ëÁܤøˆ?[xv)yñÚˆ×Gõº3kdnB\£ù«PN5з­UD|öw¿‡n<òFÍFÍÖ8>í¬ŸGf|s,xËaa±ÙŠJ6;;{âĉzzz¦¦¦K—.åv&,_jj*Ã0fffÜ&&&B¡ðòåÒß?òì±cÇ–/_^´k°TEß#'&&Ž5ÊÐÐPWWwèСÉÉÉÜy†a>|8mÚ4}}} ‹'Nà¢U77·ŽSÔÕÕ]½zµŸŸ_aa¡<…çP!©®^„”…8¯#pîöü€ þø~LŒU]2åg€¾|5éŠDºÅÿógÁ&d&$d&Ü‹ ÔiÛ›8Ô1©coR§®iÝ:&uLô´Ê[£«K·çqÜqnaî÷—7ýûúÖb¯å¦º¦©þ‹ äåå|x@@€™™ÙíÛ·ÝÝÝ?šxÇŽÅbqlll:uä,Å…D-ÈÞ«î.ïfeÅ èéÁ½1ÜÃÜ ¿üŠ]{°b©B‹©0 ¨o ±a`ç,×ͺ–ò¾/Î-Ì K K -zÒLÏÜÁÄ¡ŽIÝ:¦uë˜Ö©cR×ÚÐF(rW;»tÝõáËÛá·&³Äk…œ™Y\€eÙóçÏÇÄÄŒ3棽UtvK½“ê˜Äç&Åã¿ÁšIw®ïý.71^×®”ï˜bK)¶xªÒ¿­õ­ç)) àeTæË¨`wGÃÁlêY+&:¼{­è¡–¦Ž•žiSóºŒm:Õ¶yÍ>ž6÷CÒ¸–ø<2ãydFãº=mœí*¹:c~~þ¡C‡nܸѠA+W®Ü´iS©q¡›ÛûˆþôÓOE¯®Y³¦U«V¾¾¾£FÒÑÑ™2eʺuëJ333ÈbJyܽ{÷îÝ»÷îݳ··0sæÌéÓ§çççs£½½½7nÜÈ0ŒÍŽ;˜ššrY”žÊÈÍÍ•¿<’ªºñÅòo8vÿH©ó08¼ÌÃäƒ_~Å¿)X17Ü­ÊÄOÔðð4é$×ÍY_?¼óüNtjTdjDtZtTZd\z¬œoS²“S²“‹N:ÖjØÙÕ1­[ǤNÓºö&oÒ>˜—–“¶ä¯…õ‡:¾þ;JþJ¡PXì̳gϸᆕHPÃÐH×¾nêãó6RÞ1nä¡ah¬_ÏåÍ™ß?™À²¬$'»¬Å½-ÚuÎzøÝÊëw‹tK ŒŠ, T3˜iz62½ø~’×›ÕÌÉhP{›ºVº ÉŲþ°,Ëæ½ÍIM‰:“uÆÈª½Kû­J[[Ø™i·v5 N“y™ù<2³Q]ƒž6.£££Åb±¬_ÍÝÝ=((¨Ô;¯_¿îââ`èС%»ä}|||||âãã=ºiÓ¦gÏž]¾|™a˜ýû÷O:•»'44”[`<--MþY//^¼0räH‘H 33³   99™49iÒ$®0\˜XQ©©©*ô»‚âB¯Üñ±û¿–z‰ÇAôô OC US_ %BCÝäÞ|+?£ ¹}‹¢å)ļ}•••••‘›.Oj’‚ÈÔˆÈÔˆrîaÁÚ´·2v6LCª jõ;e‰D"‘H¤R)÷ÿœ’lj$¿´‘² ¾¾¾ãÆ+ÚÉQŽ»³GËŽ[}Àmβཛ#Nü"ÒÓo8{ €FŸ¯Ú½)Öÿ´P[·Þè)–í»••”ãˆO³^‡íÚà¾pM±,X©T"ÎrKÕýÛZß~‘*•~ðGã“ðô§áéÎÆƒÚÛ8XTuªx½–_ù‰ÍLzø*`qzÂíÛsÝ:ÿ¤Ê¥ê•ÎÇÓæÞ]†2/"3_DfºÕ1ØÞƵ"ÑaÑîv,Ë–5ÃÂÂÂÚÚÀÖ­[Û´iãëë»dÉ’’·Y[[ñÅ}ûöuss‹‰‰±··=ztÿþý¹«ÜB6ܤ“¡C‡ÊYH.àÛ½{·¥¥eÑòÈùxùnݺåääT¡þKŠ ¿N=ù“Ûÿ£(~÷ÄpÞœëó•~ÙTRßûØõ9r21~5Lm*ŸŽ†PÃѬž£Ù+¤‹ßF¥EE§EE¥FF¥EE¥FƦÇH *‹Ž¥ÎUé¥FLW¦!£N¯É 23^ÿö“r^€Ê?QC£ô…~Äbñþýûûõë×­[·r†j[X—\¯Gßѹå†V_Ó±±o¾v»<)0A“eïöÛ‘/kI b#ŽëMŒJŒJ‹ŒN‹NÉN–?M)¤ì“x6¶µ€Ç…®è¡ej€-(à0h”}ßRþ‚g%’ÜÄx;InNÜ¥3ê60®œé“R©ôï¿ÿ~óæÍÈ‘#+÷ŽIÉ<¼¦ÅK?ø^lÝÿs¿]}£¢) Üyû ômë&=«ðgÙ‡´ôì­]ÆÅ¼Ü›ù·œqáäïyÛDJpÑaCƒím|,:ÔÐИ0a‚ öîÝ›‘‘±víÚÏ>ûøþ¨ëׯ?yòäâÅ‹> ,,lèС£Fòôô´¶¶ÎÈÈØºuk‡Š.ŽSÔÚµkÛ¶mÛºuë ¸»»çææÞ»wï矾}û¶±q)4h0räÈÏ?ÿ\ tìØ1''' `È!ܲ8¥277ðàƒƒCÉ}±ÃÃÈÅâgÏžmÙ²ESS³¢«áP\HxT´óŒß>3¿3ïuuѰ†E玼äU6¥Õ÷ÒÁ§†¬ê¢÷§ð;>²*…P ´3¶·3¶÷¬÷~uèì¼,nbdj䋸g¢|tmšd$]’^°ha–ô°Ìb«ÈcÍ6m ké/Ÿ>Y³À¦[¡Nñay©IóÆËÙã¥|]VãÑ£G111K—ªé«¢˜šû>”e”v?ø­ia¼¢Ò4±ëórovª"'ªq‚¢3ƒŽg6t0ÞÅαÜQž›7ož9sfóæÍ555g̘1wîÜ&nkk»lÙ²å˗Ϙ1£C‡ÖÖÖÞÞÞ~~~ß}÷]FF†©©iÿþýO*sk) ‹»wï®]»ö›o¾‰ŽŽÖÐÐpwwŸÅ…„/²Î3~#«yI¶â”SßßÔµcEOK¿¡µ[Ck7qøÓÃãäY°Ð&vŒýݘûJ(ž~=V*•䊅:º±þ~ñWÏç§¥7öhøÙ’W¿ìð`Ñ4§q3¤>xuhO^j²]ïAõFMVBÙÊDz¬@ (':tpp˜2…‡ŽbE«ÁA¡ Ã@ PØÐmC'ù¹IŠJ°†ÑѺØéY½Ÿ˜ß°aÃ’oWuuuùånë¹²”|jÙ²eË–-㎿ÿþû •ÍÂÂbûöíÛ·—26CVÈ¢¥ÕÒÒúöÛo¿ýöÛr Vôþyóæ•:«Z!S').$|9õäOG³z_÷ÿ†Çq„ꤶշ,Û®l‰y[vôÊ"3*«½cG;Æ^úrÄüˆe 2Ó#NÒµuÐ46`Þºƒm¯Y™·§ v3­þ„YÉ÷nµÜ´[%áÆ¥æëv漉x²f:ąʉ ÝÝÝÇW-^"³`_Üçååýß †®\¹FðÅ_°,X–e–Ë‚ûîàýI–eÁ¢ÄA±{м»M îwJYnÜÜ@ʾûb•¾+¤`Á"¿ÍÎ-oe`‘ißȬ[ëO27*èµ°¬¼KÕ3%ŽÞßeŠßPl<ªlä\±¶ä°UîÎÒ2*-ß’}¬œBÉG>mMaϽ[ZéjŸ­OªŽâB—võJ( …B@ JÈ~äÎDGG—º]A—.]|||JÉ®ŽXöÑ…Æ{°GÙ½3ÛŒôÛ¢¢2ÉëÛßBBcJßïD$d:¹›÷mkef àè\Z˜@¤)ï¢??-¨!‘n:]ú^‹:šÂÍ-z·²ÔÓ¦è…/ôɾÔ3sRu”ª¶Õ·¤ä¬ä?x¢!Ôháв«K÷ŽÎuŒä§¢Ì"µÝy„_(ÃJ¥W̶ï3Ķ׀ȓ‡J>ˆDïË oÞ¼Yþ›eï³dÁàÁƒ;vTöÚÚéydF©A¡¦HЩ‰Yß6Ö&ú¥Ï¯"qF8ƒÚõ‹%äMV©A¡¶¦°Gs oŠùGŸ/!DX°ë/¬å;Ôiµql×Å¥k§Núå|éi9o"ÍÛv–ädæå‰ôôHóóT]´2ëÔÒÒ?~|£FTUžÚæ¯[qÅÎhŠ]›™÷ime¤ÇKDÈy{€‘uÛU×P§ÿ-þikk {xXône©¯C‹2ЧLQ€“O<{Ö£A¯..ÝÚÕóÔÑPÔZn ¦iljáÙõÞü f-Û[¶ïölÓò¶Û›µhwÑ´&KÖ«ºt¥+M:ÕÎή* r+ø0ÿí¤bݵOÝaãäy07)þîì1Zæ–J¥’B]û~CÍÛÈ·ÇNõôôuÆ«¸lÙZ‚î½[Y–Ø^\±òsâãÃŽšõ†ðš‘Z ‰Ézõ¾³PKCУ¹…w++Š•‰>kBHUIY©ƒI³³.ʶHV¥/=Ã0æ­,vÎ}ñ7Å)u9hU‘m…gkk;uêÔR—@«(Ù >•Ðn×1¬D’òðNðî’¼<«N=«^$5ÄÝŠåŽu4…Ý›[ôn©Œ^«ÌäGáK$™u=–hêTòŸ©::}û]g!E„*DŸ8Q/ݺu»rå QdG Þ%&hÚ´éGoT8®¾É10¯RPÅ$Ç ­¯€´«ç©¨ÔH1\¡››Û„ ´´´>zådE„…ü°EZ¯a`Ø`Öb€½;{LÝ¡ãÒƒ›­,e4$#š·î?rrôéßjj\øäUzDBŽ®–°g Ë^-,øÙöúÁWÀ²’Â윷AâŒW #th2ßÚuÿB”„Þ#µÓ³gÏóçÏO™2%::ë7ñƒƒÃþýû{öTÙÀù¢õÝ]ÊŽ— ¦òúuÄ0ns–ïÝq⑞~ÃÙKʹ÷îìÑ,˲‰¾£s“Eß87,çæÚŠÿw„ðƒâB¢Ž¼¼¼BCC7nÜxûöíðððÐÐP…gáâââääÔ¾}ûÅ‹ó7ÇSNµ­¾J“Ÿž¼kc“eT]õRê<úŽÎ-7ì-ÿ6µZ¾G=988h8ˆ“”–cAn2Ãú÷ï§´IÍFq!QSZZZ«V­Ru)”§¶Õ·Šoý/òÏ_%¹bV"jk×2Ϊs¯’·IóóRŸÜ“3MV"ÉMŒ×±±ãVo¦ˆT‚½½= âssó$™B %ä˜öœe¥YY¥oßLHEQ\H©~‚vmh¾v‡AýòÓÓ ³𥘗š0o|—ã—µÌ,=ø½ê ’ZHCCÃÃÃãÎ; aÇlݦ)!ÇøÐ_´nÝZ y‘Ú€âBBHµÄJ ¹M#M#î8æü_ñWÎÐ2·løÙƒäŠ]éê‰ãbBö}Ÿ›ψDõFNI¼y ÀƒEÓœÆÍxºîK®¿°ÔÕž›,ýöÕ¡=y©Év½Õ5Y™µ&êoíÚµ^^^ožï0²òÔ3mÂk^1/v§Çß455¥åˆ¢Ð|dBHõÓpÖâÀM+5ÿÍ™“y)ïÆre„¼ˆöûÍãë­-7þ ÒÕ‹9û‡ìþR/½ØºÆÔ£MÛGÚøþbÞº}ý ³´Ü´OÇÚöÝc,ûrÇz‡A#[mÞoÚ¼mØíÜé„—š¯ÛÙtÙ†7ÿP·")®gÏžÓ¦Mc¥…Ï/Š >˜›¡øò£/€œ7‘qŽU/îþ’— 2ÞfE„y|åË-ÑÇKùeXÖjÏ g.bD"Mc3iA2jKª›­[·êêênÛ¶-êɦ¨'›´ôÀJ•8ËJóÅ Ü”gƒ;wŽ=ZQ‰Bq!!¤Zhj™µjoÖª½U—Þ–ÙyfD"mKÇOÞ-§'ÔÒ–¾‹ÛJ^âØJ­ÎˆD@k“2hkkoÙ²eÖ¬Y_ýõÕ«WÓó¬2“î+0}ss ss³N:mذÁÔÔT)Bq!!¤úIú÷ªI³Ö"]=ù©Éš&fÌZzFþùkav7E’+–f¦s÷—¼$ÔÖѯçòæÌL`YV’“-iæçÉr‘­ölÞ¦“œ«="ãìì|øðaiii LÙÚÚºö¬6E”ŒâBBHõ“xûJø‘Y©„´Ì,Í[ @×®NÃÙK‚÷lb%†¦YëÖ]{s÷—¼äøÉ„FŸ¯Ú½)Öÿ´P[·Þè)–ž]ÍZ´»¿hZ“%ëßeS‘Õž )‹¡¡!m/Dª Š !ÕOã_—zÞ¼UóVŠž‘-CXò’Ž}óµÛ‹žq_üM±§ÊYí™y&„Ô<4™B!„BHakk /9QÕ)Ž+W>>~~~Ü ÞêƒagggU„òBŒ•²,˲)+•²R–•JY‰”;c$Ôa†ÉÌ)À²}ÛuËxðæÏ#šFƦm´Ì-U]|^ä%'¦>PB·Y×®]ÝÜÜÎ;÷æÍ›””þ2’“¹¹¹]Ÿ>}¬¬¬T]BÈÇ1•[îŸTw{?•Ï;¨Â’š!øÏ›·Ö-ç±iEŸM0,øúñÑÚð»ˆë6ëÚµ«ª ¢.æÏŸÊî:CáõB ÁŽæê^ú|OÚ«¸ =Èhp_ÜÛA}º¸ø@Ýf„jâBBˆb˜5tú×ê›_ :yCÞgLAï:¬–ÐÊÊjâĉ<ŽBˆh>2QSyyykÖ¬ñöövuuexàêêêíí½fÍš¼¼¼—†5£¾"­®&õÜ:CS_Gžû ÛZK­õø+!„ ¡ñ…µ”š/ô÷÷Ÿ2eJtt´òrppØ¿¿———ò*KÍ«oFT⏻“#˹Gê ŸïS ¯!jÆ¢nè=2Q;—.]òööfY6Öøt<<šÁ’‡9ª‰‰xüEGG{{{ûûû÷ìÙSñ¹ÈAV_K [€Fž0·S|.É1xñ/N~%ÔW*‘ÆÞ ÎMÍ*çVWTЫ.…„¢V¨¿°–RÛþÂŒŒ ww÷èèhøôÇü¹`xX¾ÛáwÆÁÁ!00Pùû1ÈêÛs&†ç‘¬?-Ç¥Ã੾¬Dú÷;N§G–»¨2ƒüNÒ:ŠÍT;Ô_Hˆº¡ñ…D½øúúFGGí!æÍá=(À0˜7n £££}}U°0W_çæ˜´Ž÷ #À¤upn…×—•²¯ÎÞ;ÑwÅÿþø‘ (lnIA!!„¨!Š ‰zù÷ß`ô”Õ8Œñ>kåâ2õ™PI9 „ð™õ>k`Ùˆ‹Oú¬¾8ww±Ej„Z6­\ŠÝþ:7©°µb²&„¢P4¾¨—üü|hàªÔ\¸¾ÏZ¹¸Lš*5S.;…Ô7êêÓ{[O%F;/Ð5Ö©åg^»w?Tv^,Íÿ)ñÚ j†rB)Å…D½\¹r/MÊaiù>kåâ2åc¢I9¸ìªXߘÛ/|ÿLxôªØyPà2¨}«9 ìÍ0öûþšt;¥ ¼ù(„BTˆâBBHÅÄݹ·åÏØ€àbç¡À¹_ÛVs9¾ßÒC |6Õõẟ•SHB!•@q!!D^‰OÂ|ÿ|sóyñ Sß»U«Ï™8Û¿$x7yÈÔÕ®ýòQX7‘÷RB©,Š !—ü<òÞÖS‘Wž¿À0ŽÝ›µž?Ĭ¡C© "Í^ÛfŠ´5ù.'!„ª ¸ð%êÚ³:]š¨ºÊSSë›soë©×¢Ä"s›´ž7زi½òž0:¬câ¢ÜA”„B*ŽâB—Ô7÷m5w mÛ†ª.‹2Ô¼ú¾ ¿¿ý¯WgXiñˆÐÎÓ­õ¼ÁÖ-‹¯AS’@(¨ß¯ÛðÎEOr«BQ7¾¸íþdÿy¿1mÛ6ä=Z Å™³xú ññÈ̓ŽÌÍáX `ø'ÐPF;WN}GÚð£†ÌlP߇À£›ÂψNz°ãtÈéY‰´Ø%ë–.mæ±m'oí ìÍ»®ÿôã÷BQ´^-¥œ}ðÿxîÎÆܱœÑÃ…6W/Ê›‡D‚»ñ—Ôs„s}hh 5 ¯Â‘”gNA_ÿãétí…*ïÇUéúþöFÞ,¸¸°çX°,$…ÈLCt£ IgÌÛ =ùv¶ãÒ)Y߬ؔ»þþ㦴PRì’eS§Öó;tr—·¬„Bªê/$<âºÐÄ)bïù R|_ÚÎÝøË6ÖX±}p)6w ÒPX^£Œú¦lx̲À®yxv¾Ó°üh%÷ÓËN|ûhÏ™—ǯIò ‹]2w«ÓjÞ`ÇîÍ”±3!!„Õ¡}ðD:Zͦx={7ÈoÌF¿1cï) ƒÐ0œòƒ®.|7 ØÚ`ð@hk) #ùð^ßÒ0 ¶ÅÊãÐÑGàMÜ÷¯p ┌Ûë;Ö}qàáËÅ‚B;¯Ÿ óûʱ‡…„RãQ\Høå>¶»ŽYñW› ‹–þ9CÂÚêc·* ¿õ-›exO€›§*ðT^zöÝïNí¶èé …¹l‹gTϺ‡ïôáÿ¬uònE!!„Ô~•ìB“Q@´ôø)tìPÙÒ)¿õ-W«ÞðªÄ ƒ¥Òhö7õ8ÒåËG?üS“Wô’½y·“GœÿÆe@;F@!!„Ô"4¾|0Eùª4/>J_Q¹¢öÔŸ¨„‚¿q‡¶õàm‚\7O²êì®kŸŸ%.zR߯´Å¬ ?é$ X0B!ÕÅ…D-È¢%Wëq¼¼å怎ãI%ë[.-ŸF\º‹oÝu߯y£kaÜbf?·‘]…šô;Bj/ú Õ™–òò COWÕEQ=q6èËusˆ8>Dïªc­cjà1­oã1ÝE:´I!„Ôvµ {¯:YRǬ­…ׯáÞ˜·¢ñ¢’õ-WlØ9Ë{ÿéÔ¿o9Ðt¢E„„B8ÖRü­e]RÑÕžKªÒH»&Âÿ®*$.œùêg…,óÎc}Ëõð4é$ïýá¹I-föWx1!„T_~Šóžì?_ê%DH}½qæ,þ>ƒÞ½ÐÀµòé(¿õ-[J,.„†&ºä#yB!µÅ…„_¿þÛÿ£(…EHÜàí…óþX°ŸÏF÷®þ7‘–eŒ¿ÿÁ´)06ªjFrã·¾e¹]Ÿ#'ãWÃÔ†§L!„Ô|•ì3 ,[Œ~}qî<žâñBWöèãïÞ0‘o‚®"(£¾€K¿¾;ÐЂU]ôþ^ãaçÂGV„BjŠ _dg|¿E€fMЬ éËA9õýí ©B!Å…„?¿þÏÄÙ¶×ö™üF„j£¶Õ—BHÍCq!áKÝ®M=¦öQu)”§¶Õ—BHÍ#PuHeâb§ê"(Um«/!„š‡âBB!„P\H!„B8B!„€âB¢nºu뉉JÍ51@Ó¦M•š)€ÿꛣÔL¹ìTR_B!êŒâB¢^455 8D©¹‡°±QÁr\}ß*5S.;•Ô—Bˆ:£¸¨OOO8zR©’²”Jqôøû¬•‹ËÔo7¤%å(•Ào÷û¬ !„†eYU—÷222ÜÝÝ£££áÓóç‚aøÍeá»~g ùÍ®Y}{ŽÃäoÀðü—+ÅOËqé0TU_B!êŒâB¢v.]ºäååŲ,l¬ñéxx4ƒ¥¥â³ILÄã'8xqñ Ãøûû÷ìÙSñ¹ÈAV_K [€Fž0ça%Ää¼ø'¿Gb4T[_B!j‹âB¢Žüýý§L™­„¼öïßïå奄¼ÊRÛêK!D=Q\HÔT^^ÞÆoß¾ªðô]\\œœœÚ·o¿xñb---…§_Qµ­¾„BÔÅ…„B! ùÈ„B!„Cq!!„B(.$„B!Š !„B@q!!„BáP\H!„BŠ !„B‡âBB!„P\H!„B8B!„€âBB!„¡¸B!„B!„Å…„B! ¸B!„p(.$„B!Å…„B!„#ªô“ Ã(°¤æaYVÉ9R›$å£6IÔ µI¢n¨¿B!„Ué/äœóóSH9HMÒÇÇG…¹S›$%Q›$ê†Ú$Q7\›¤þBB!„P\H!„B8B!„€âBB!„©ê¼B!•PPPðû¼xù2.!!66VáéÛÚÚÚXY5rsûdèP …§Ojj“Bˆò=|ôhëŽIÉÉüeûàÑ£óþþóæÌiѼ9y‘€Ú$áP\H!JõèÉ“_}Ų,l¬ñéxx4ƒ¥¥â³ILÄã'8x().~ÅW_}³fMófÍŸ ©dmÒÒà‘'ÌíŸKr ^ü‹“ß#1:™Ú¤Ú¢ñ…„¢<999¾Û¶±, Ÿþ8z^½x XZ«Ž‚O–e}·mËÉÉá%#RÍÉÚdÏqØv ‡ñ0·CçaØv =ÇÚ¤Ú¢¸B”生_Rr2ÜbÞ(aG2†Á¼9pk˜”œ|Š–2&¥áÚ¤ssLZ†ÿ €`Ò:87µIõDq!!„(ÏË—/`ô”õëW Àèï³&äC\Ãð™PI9 „ð™õ>k¢V(.$„å)(,€®J͵ëû¬ ù×0œš*5S.;j“jˆâBBQž§ÏžàkLaY,-ßgMȇ¸†ÁӘ²pÙQ›TCB!„€âBB!„¡¸B!„B!„Å…„Bjµ>>>}||T] BÞQmƒTñ>x´K7Q7üµÉ–-ZˆÅb÷Ƈ l`` À” ©„ò¿xúz{Ï™5Ki…©œ’U …zºº>ýûwîØ±*Éž£%—•®ºò5£Aª2.¤]º‰ºáµM>{›/Žñòåé¿ÿþtüxŸþý%lwAªµˆHL‰‚¬Z†îÝŠ_ŒÂôY°¶ÆÞ]ÐÖª\}½½K=ïÞ¨QåT”üüü´·o­äXЇ«˲R©4;;;üõëç/^<ñBRXØ­k×Jd-PÚ’ãÕЛ,õFA>æîBûůƄbY_X8à› ¥£Šòñ¦ö4H•Å…²]ºëˆD‹ÛkkÛ‹_˜7……·ss7¾}•L»t“µI-={ûƳ -ÛhêÚ(0}©4?3é~zü͸àƒ{ü1==}üر LŸÔ@Žu1m2ví…ïv4m s³÷—òó±æHY¬^Qé €Úv 6 òõ‘«˲'O:ðóÏ'OªÜ×ð?ýU‰§j {WŒZŠC_ã§epk«÷— ò°m¤R|¾§¦…¨M R5Évéž``pÏÞ~¸¾>A!{‘h¸¾þ={û ´K7)‡¬MZÖáÑ÷‚¹ã@Å…M#«öuš-rí¸ `NüñGØ«WŠÍ‚Ô@C‡ YSdfaÓ÷`Ù÷ç÷ü€Wá˜=õUU4õÄ0Lÿ¾}DEE©º,5SŸÉhÔÙ騻àƒ&yx-¢^büWph ºÂ©Ÿj× UÓ_ÈíÒÝBKk£™™"S°ÑÌìY~þÃääS~~cFŽä?ORÍpmRß´©c‹•|oobÛÝÚuB|ÈÏûܰn¯y‘jOÀ`é"Lš†€{øûøô€[·qÊ;b@?^3øèÑòÕ« ÷íÚeddÄz´}×®bPƒ”©hƒTM!·Uv3MMefÊeWé]º÷ýô7{ßO?5iÜXvž¿‰Bå|q?r¤ºOÝR+\ÃÐ7uWNv"Mc-=»z´gûvkkkÍ›5;r쀱ÿ}Ë)??ÿÆÍ›»÷íЫ{wî¤üe(Õ•k׮ݸakc³éÛoÍLM‹^jááa``ðèñ㌌ CCCîä…K—ô¬Ñq!€.Ãqï<\Äîy“‰/Bψ—¼Î]¸°gÇK ‹Ð°°¹_|ñ¿«WmllöìØaei;eƌdz,[´MRƒ¬tƒTM\Èm•ÍӘ²pÙUz—îGwéØÀ£'O*7t”³võêõ7øzÕªo7múèý¥Îäz›?:GIþùS„k SX‘–i^vLBbâGã²Ú˲¿=zìÄ –eë×ïÒ¥ €ˆˆˆs.œ÷÷=r䘑#+4å¹Xƒ¡¶ªF_~‰Sø&O„{ñ¿*çMLLÉ“©©©²c}}ý93g®Y¿~מ= píÆ!ƒÕ­S§Ø#³g̰±¶Ð×ÛÛÿÒ¥'ÿý¦åº.ùøpM‘a˜AܼuëêõëžçΚÅ}W”,´-((HIIá:]<Ûµë߯_EËP*ÿ‹L?¾Øw0‘HÔ±}ûs.ܸu‹K*77÷ÚõëîÛÙÚV¢.ÕÃ`Ú&,ìà{0üK4hÍW^ çÏ·´°PßÉ €T*]8o÷ëÂÎÖVGGG,hél¢Yé©âõ «‘ÌÌÌ_kïé™™™yøÈ‘vE+THBbbýúõ$%%9ׯÿÑûË™-øÑ9JòÏŸ"Ê'Ê;‡´¬¶wü÷ß?ncm½tÑ"ggÙýÁ!!¾ûîȱcšÇ “¿HÅ µUõbb‚‘Ÿà‡ýк•¢R•ç3÷l×®s§N×oÜX·aƒ‰‰I©C´eã·ìíp½×^GDp¬[Wv'wüúõëb)´lÑ¢åG‘Жac##ggçžÝºuêØQöG‘üe(7?¬Y“&¥^íÚ¹ó¹ dßè·nß‹Å5û%²Œ‘ÌÀÑõЬ+5puåda6lð~n‹ ´¿~©AVºAR\XÜ¿%€pùþñJuæìYîëóÌÙ³ŸÍ˜¡‚‘¯dÛ‹‹ÿõØ1o×­+ÖÍÖÀÕõÛuëfÍ™søÈ‘Î:Y[Y¡R¨­ª—·é8ùç»ão7aßnhU~yšŠroÔèú,ËèÛ·üÁUZZZ ÿ±#‹èè¼_¶„ëB΋U¶†¶U,CvN==½R¯º7nlfjúüÅ‹äädssó —.ikkwªì ÆÕKF Îîw¼{¾=ÍÒ'N¨5ÈŠ6HZ½S^¿ùfã7ß=(‹lLý•kצ̘ÑoРy ÆÅÇsW7¬[×ÈÍ À·ëÖ¹—+V!å Þ –]ânKNN ÎÍ=täÈäéÓû 4dĈ_}\2M±Xüõºuý ªJñˆ¢”ÚöΞ?/‘H|úõ+õÝ«µ•Uÿ¾} %’s.pgJm-²“¥6j«j„e±aRRñÕJXZ 2 ?PZæ‡533ðϹsÙÙÙåÜÌ}çÉvôá¾ürsse7p‹…éê(o»*–ûÎÈÈ(õª@ èÜ©˲×nÞŒ‹{عcG2&–Ö$,‹=óñ6óöÂÌ1¡ømƒªËTjmÊ«i“&M›4)zP¾ó.|·e‹±±±©©ipHÈÞ}û¸ó²µŒø  073+9J,/\²äØñãNõêMž8±Ÿ>AAA_.]ú2(¨Øã²yXü•ȯԶ÷ðñcžíÚ•õwéÑãÇòdQjƒ¡¶ªFþ8…;5];cé"0 Nþ‰‡rýãVÝÁC‡²²²Ö¬\ÙÁÓ3%5õÇå…¤‘‘êý÷ŽŒ›ÿYdå¶ðˆõêÕ“'k¶èúx•UÅ24pqpïÁƒ²nà&^»~ýâ¥K¼zö¬Ji«‹s?áÑÿà3 íúcÖV0 ÎîÇó[ª.V Ô +Ú é=2_>¼iýz÷Æ#£¢fÌžý,0°r锜-¨§§·uóæòŸ277;jT±ùS~þ9<<|Ø!“'NäδhÞ|éʕڴ~}ÑÇ‹ÎÃ"ê‰Û»™:Sª:uꈑo‹çRLEQ[åKH(öþˆ† 0i"4÷Àð¡8~6áà(ãu’¢Ÿ÷÷ï×§““Óg3f< ¼pñbçNZxx”¼™eÙ³.èØ¡w¦[—./^¾ô;s¦«+7õò¯Ó§pk–ƒ›L••UõÍÄ+]ŽwïÞ?þùða· dKäääîõŸ‹³³µuhXXl\œ­-×Ë^³½~†#ëP¿† Û£ß4œù»çã»ËÐU›íß©AV¢Aª{\\PÐ=66Ÿe÷YX .ñë/¤  gll‘袭­Žšm5;mòdîÕ›q‘ã )9[аR’eÙ‹—/à^ç4kÚTWW7ðùóÜÜÜ¢+jVzQš¼¼<|8B¥îÅXqƒf>ŠÚ*/Äb¬ùXµ ÿýÆžü)îãu¶íIJÅUI~ÇîÝe]š9}º€avîÙc``ÀíÙhbb2sêÔM[¶lÛ¹sïŽE›ßÆÍ›­­¬Â_¿¸¿¾“Sï^½¸óÞ^^ÿ»zõʵkééé.ÎÎÏ_¾ |þÜ­aCo/¯ò Ö´I“»›}}[4o>pÀ€ªÔ±Òeàtlß¾{×®ÿ»zuæÜ¹MÜÝMLL’““ƒ‚ƒ·oÙÂM`¦k—.ÇŽÏÎÎþdèпïyn6¶Í‚†æî†HãÝÉ‹ðä*¢ƒqp>Û¦Òò Y…©îqa •&&+SS¥¤xjk[ ߯9œÇ²S“’¤Àêèþßz""a•ÖIVÔ Í·oß¾MOpà矋.<*‘HX–MIIáâWN¥çaÕxâŒWþC¤Ò|çvß›Õé[ÊՋôôìÜ{ù`¤­¥%ÎÍ‹ÅeM(9´™oÔVy±uÞÄ`ù]fBS+–búgð¿„ŽíÑY®n†R=¾¬KÓ§L9wñâ«ððÙ3gÊBü®]º\»yón@ÀÁC‡fMŸ.»™[zÃÈȨ¯·÷Äqã44ÞÅ "‘蛯¿>ò‹µ:çIDATtäÈõ7=ybff6tðà1£F‰>¶NÙÌiÓ233ï?|˜›—WůáJ—Ã0ÌÂùó6hpöüùg ÃXYZvéÔÉÔÄDvO×Î?Î0LÏ"ûLÔT–#þ5>Û«÷j¡¡…Ù;°¬/nüV½Ñ¶øoGe£Yé©îq!€i††çrrnçæ~žœü›••ì[bujê‹üüïÌÌÜ”»>¶œÔíOF®{I ¤½}[ô¼«‹ ÑÿÍòéÖwhúEäã ¿6°h¥©ó~·T’vgÀºxúò°³³ {õ*úÍÙ ÅDFG¨Ž‹¨Q[}ïâe\¸ˆÞ½Ð«Ä2õ0y"~ØÍ[áÞ%V2û(yâøýú è÷ÁV{ Ã|µbE…RÓÑÑ™>eÊô)S*T+KËï7n,¿xòÿ)R~Š¥S2Y†aJ~Eq¶UË–Üìœìæ)\?‰ÎÃÐiHñKuaÄ"]ý‹Ñ 5Œ?²0k)J~òòœ9ùÛoò$%C ²|Õ .;ÍÍ;ÇÆþO,>”™9ÁÀÀ¹œœŸ23ûëêN¨ò›þZ‚[úœeÙ5«V•µ #‘‡µË¸´˜ËI÷^ß[Ñ óÀ»?¢žlÊy\¯åj#%£¹‡GØ«W·ïÜ)+.ü÷Îî¶²RPÈj>P[}¯WR"B™Q#0j„KCÊäwæ ¯Z°laÇÁè8¸Ì«>³àSæ2¦DyªÒ «Ç|d‘h½©)€U©©……±……Ÿ''Û‹D¾ææêÕ)§–¸¯]]ÝzŽŽ,ËÞøPÕ%ªæS›o…"½·ñ7_àÎ¥Å\N;jjß˲¾’¾§ûöî- ÿþ矄ÿÖk-*>!៳g…BaŸÞ½‹ž/ºÿæ©Ó§KMY…ñ"µUR¥§§_»qÃÐÀ me÷; DªØ «G\`¤¾~o]Ý–ý,)iFrr†Túƒ……ñÇ6ת帱eYYY܃ðÃþýÅæ¨J$ù¶ë&-=»ºÍ—ˆ|²17+*_~o¹¦®M½Vëd݇|³¶¶;fŒX,^¶r%·ü½LpHÈÒ•+ʹãÇŒ‘-jÍ CäÖÓ—H$ÇOžüå×_‹¥Y¬Á(µÕ꫉»{w%m,®žÎùûtëÚU£V rPWÔ «Ø «Á{døš™uÌË È˰Ôظ×ú¯¦ŠÍŸêÙ½û‹  ó.Ìœ3§M«V¶¶¶R‰äMllàóç{wì077Wuy«‹zƒÓb.¥Å^ X F )Èrí¸[¤i¨Ì2 :477÷øï¿Ï™?¿«k)ËFFF†½zÅ0̘Q£>:Tvs«-®ß¼¹|õj§zõ¢¢£322–,\øÍ‡Ãe8ᮢ¨­V_ÅVª…F~òÉÈO>Qu)È;Ô «Ø «M\ÀB(œmh¸&- @7%β¬¾ŠÍŸbfî¬Y-=<Μ;÷èÉ“[ÿþ«££cgkÛ£[7=}}U¶ÚaêµZ›ya@fòCöîs Ì•=1–a˜ cǶo×ÎïÌ™§¡aaÀÊÒ²¯·÷€~ýŠn¾ `æôéùùù?~ÔÈÍmÂØ±E7}wâ&ÜUµUBQL¥Çqóm+·2·íU’£c…žJ‘HºÄÆ&H$\54.ÛÚjWpίED·š) ÷ï«üajUo“m‡¿¬ÐSqA?E=Ý À½ç =Óï‚SÔ‹+ã2“î÷í·UÜbŽÈC}Úä»Mÿ®^TrIеè·Ÿ:Q·6ùÛ%#íj“ê„k Õf| ÌNNNH~²°°‰B Ö¥¥©ºP¤V+ÈK ù…;~°T*©äÒå¤Vy·“ai³…x”˜ø>kB>Ä5ŒäâËÒó‹ËŽÚ¤ª6qᾌŒKbñ##=½ææ ðCFÆÊn"BH•±áK r“\<}5u­Å¯¢ŸùªºH¤Ðà–® Qj®Á!ï³&äC\êÔL¹ì¨Mª¡ê>ÍÏÿ:-­¹–Öccµµg˜“œœ!•ªºt¤6Š9ü6îºMÃÿ·wçaM]ÛÀ×a$¨L‘Q¦Ëà8`«"(ÔJeÄ÷D,ÚZÛ: HEKoµµ_õÖE¸Š("µŸ×k¯Šµ µÎEyL"ʨ¢‚€ pÞç6 C’È„¬ßÇxr†¸ôìì³×^+ ,æÙNù€¨-=öæå-e· ©º±T­Ò…ýßÕÕÿ:ù×¥êŽ Œ´Ð¥¨\ÿ.>¤øëÒH¥ ‚~akW×ÊW¯qhäHÆŸ ¿Ò×Ë`<åñ¢_¿VnóÐÔÚPTu—޳…S8Œ0šj:z9<Ήæw6+¹qHµøùd³¡¸bãAsËHb㡸d$›@MmD¨;*&Ëò!ùk åÿm…ì‚䯡,0&UÓ ènzýúIgç.k¡g-‚H`³5 âç––smmJljø¼¶²ìH55†Ý´Ý„ÚW‡åÎÔµç¶ÕVä}¯Üæ!Çb±Ö‡‡iç`I(\Ì’×\×/áb, …´sA¬UJ[ #33bưõë¯Ý¸!—&!•$ˆÉß~‚p7¸vJ^s ëžÂµSî¿ý“*KÕíŸjm=ÙÒò¿Ã†-êµ8…#ƒ­§÷]CÃuuSÌÍÔÕ•ÒB4ÔTä}×ÞRi;u‡ö0KÁF5u-»©; ~[TW™¦oîe0j®[ˆTܤ ¾ÿöÛØøøWÏkaûNy_n$›6iÂñ»]½~}ßþýÔ便¥3ÝÝåÝ0Y¡’(1­u 1ù²ºî@„Ü/‡1©ÊT½_¤£¤£#êÕ0]Ý0]]E¶ qu•éu¿°­ýÙV=°ôÆX8ETÝß]žûÍp¶‹¦6®½ŒDr™4éHbâNŸ.*.~þâųîe]dÂÌÌÌÔØxÜØ±‹.¤SöàÜ… ¾fÍ{õ"æçx÷zê§¥¥emeåïë;ËãÇKÏž??›–vïþý/_vtt0 }=½Q£F9ØÛH(¢<*+˸x± °: S[ÛÐÐÐÒÒÒÁÞ~á‚}e-(þ–\U]½6"¢³³ó˨(3z¼Z]]ild·g– —cÀ˜Ä˜¤¨z¿!•¶òe[‰\ðÙtÌ Ó1+Ù4xijj.Y¼XÙ­øË“òrð˜9S[[ÛÜÌL̛̞$Ir¹ÜòÊʇ¥¥;cb:;;çΞ-ا¨¤ä«Í›;::,,,¦»ºj1-­­Ïž?Ï¿{÷N^ÞlOO‰÷`>Ÿððaªg`me5ÝÕUSC£±±ñIEÅÙÙdgûx{÷yV“C}T.—ÛÐØhldÔç«–…†:räŸ NŽŽ†Âþc×.’$£7nTåN!cR|{†HLb¿!„´µµ€¶¶¶Ä=ÃV¯þãÙ´´Ä¤¤S©©Â÷à¤ääŽŽŽ—/  „ pÚÛóòó‡Ñ(Z“˜”tîÂcã_|1vÌá—jkksîÜéó çÏž•xriùØñž~~Ù·o?((ˆ‹ûî›oo9éèÑòŠŠµ«Võ¨?„èÀ˜C~19òNB)!e)˜7w.<}Ú-UáQYøûøô8!S[ÛÍÕuÄðáâÏùøÉ“ôóç™LæÛ¶õ¸€‰‰‰ßüù*5üFÄL&37/ï×ÌLjcöíÛéçÏ»¹ºR£Y¨0&û§ß1‰ã…ddffdeñùüE ¢I¯è-†1‰úÓÞ~üĉ«×¯××׳ =fÎ Y¼˜‰I;>!1‘ÚÍÛÏO‡Å:õïÓ?3UÉM‹ÁÞÈb±Þ¼ySQYé`oßÖf\¼þ>>¢“‰Ñ{.§½ý?§O_½v­öÅ --­qcÇ. ®.8äòÕ«ÇOœx^[kog·iÃS“’‡×GE ïöSr2›ÝÇìac#£ÏW®Üw89yÒĉš{ãâŒFŽŒ ëGÏf(À˜T͘ÄñBq¨d¨‡¥¥e—–*¶>R¬îîŒ> z;’騾¾žÇ}ÓÚP¨k<]—ëâ·sš©«Q__òÄÀ˜„!“2ôkffqIÉ 7·è ‚ IrûÎ7nÞ̼xq¾·÷h‡ÑÇOœ€¥Þo$êêêªý:ûÖ­”cÇ444>\²DøÕeK—¾zõêúÍ›ñ$&%¹Lœè:mšëÔ©Ã%=­£Ô¾x£ÌÍ¥|£}8qòä“'O‚W,_Nmq™4)zóæ£ÇŽíܾ]xÏ£?ý´sûv'GÇʪªÏ×®¥úl6{ip0͇ ˆðµk?_»¶¨¸BCBÆa=0&U6&•Ó/ïì|ÿÁƒo”k#Öðx`cmMÿúÉPý#H¡êêêjmm}R^^XTTXTÄçñf½÷žÌ/'Ê[“L7ö¶¶EÅÅugÓ/¬«L'I¾¥¥ £û“‰0&‡NLÊЕk×`Ÿõðˆ ˆ¾¾7nÞ¼ríÚ|ooiÏÖã+„‰±ñ£„72ŒèßÏÏO¿páN^Þ­œœ[99ñ³<]±ÂÉÑÌÍÍ CJ ¯§˜œ’“]\Öü·Æ¤ÊƤrú…T©ì{\®"û…÷¸\0æ±ýd¨þé‘BE’ä©ÔÔä””S©©Š¼&ÓøùøddeÕU¦Zúê™ö ’­ŽÖšª»ÿiŽÆäPŠI*¯¨áOŒú½¼¼¼g ™4·´455Ípw§n]=1ÙÅe²‹K[[[n^ÞÍ?þȾ};ëÒ¥[99;¶m£¾¢¿xùrù'Ÿ1|øÉãÇ€Á`p¹\‡CsI9Q›š 9%„&Tñù|’$ëëëÍ…†<ÿŒpTIhjj:ûË/Ôï»ccÿ¹w¯´ßý†ŒI•IåÌ/¤JeÇ55)ªH7ðâšš _Uº6e˜ ê DUU•b®(|é!žLgfföQh(<¼ñyåÝ¼Ž¹\†ìª«LéÏçqÜ\]{?!¥ cr(Ĥ q8è>ÔA}µhãpúq¶Ã ÔO\LŒ¶¶ö©3gJ>³?‹Åšéî½qãIIï¾óNssóÁÇ©—4ÔÕG™› ~LMM©íÆÆÆPQYÙæ £ÆxÔÔÔ„8ØÛ;;9it_Zyàÿ¬H’ŒÙ·ïuCÃW›6d³«««;6Às¾­0&U6&•3^àç—yñb^]ݦúú††òîœvlª¯ÏëèªJ·`\Z8JLþ”ðQgNžÜ““›»ß>éF5H¡50%f-ÑLk’Ø$L¦ó÷õåóùGRRjKSjKS´tÌ5µÙ‚ ȧ¦Æhz‘ @Àxg爰0iÏ€19ÔbRV˜L&‡Ãioo܆©gÖÀŠ…†„:rdwlìþØX‰õõõõׯ[·$4”šê†††‡zïé8n\uuõÕë×8?oĈ@’äw[¶Èo”]à—ôôÿËÍ]8ÃÍmĈÑ_}6-mÚ”)Æ—÷¥ŒI•IåŒ ªtÿØÜünMÍÏ--Ôä?™«áñ~niy·¦æÇæfšUºz'C‰ÏŸv(9ùîýûv¶¶êRŽýÞÊÉ ê³–è§5Ñi&Ó.XpøÀÉ..jjjêdcKý½æW¹²úáóÚÆ;;µcÛ¶~|°“C0&e‚z@V)4èû¤¢lllxf?{;»§OŸ¦Ð£n„š’f½?{6\ÈÈ Öœë7‹ecmM’dn^Þ@ÎC¡V?¥ìñã#G:ØÛ‡.] œýý &6¶µ­màWË`LªlL*-YP¥»ª®nM]¼/G³J·°Þù>âó§„ÍËÏOˆ‹311¡9.—{ýƇÀOOj£Ä¬%úiMtš„Ét`fföý·ß’$YU]ÝÜÜ,Ã36ÌÊÒr ]“C3&n–‡GQqqÚ¹s£¨8¡æõ{&ƒ€ººúº5kÖEFžMOŸîêêìäDmß¼uëûsæ¼ãâ"<"B’ä™ÔT 1ù}ÌèÑs¼¼².]ŠÞ¼yÍgŸÍœ1Cðå$ÉÒG.dd|¼l™®®®ÄøûïÙ·/1)ÉÆÚZ8U‹Çç4¿&Qƒ[---¢rW9íí?ìÚ¥©©ùeT” èEèÒ¥wòó+*+7¬_OçBCÆ¤ÊÆ¤2שQÁ*ÝâÑÏŸZ·z5ðÊU«¨_:;;ëëë©1×iÓ|æÏYKZZZôÓšh6 “é(AXYZ*»’aL":æÍûû•+—¯^mjj²·³+,..(,;f Ub€ìlm,8š›O=̽s'÷Î uuS–ŽN'—[ZVV]]=’Í^ùñÇO¶zuWWץ˗wîÙs0)ÉÎÖV‡Åjmk+//ohl$â£eËè4o¶§gQIIFf檰°)ï¼cffÖÅç×<{VPXx0>^b*e¼³ó휜Ý{÷ºLšäïÛG…ôý>}ö,*2ÒT(¤ FTddxdä¥Ë—§Mê>]k “*“J^¿PÕªt‹G?ŠæÝ«æÏ*=AèéêÚÙÙÍž5k†»;u—˜µÄb±è§5Ñl&Ó .“ˆ m[·;~üÚõëù÷î.  UÎUZKƒƒoܼùâåËÃÉÉëÖ¬€Û¶Ý/((}ô¨¦¦æVN—Ëe0£ÌÍ—,^¼ÀחΊqšššÖ¯Ÿ7wnfVVQqñýx<“Éen>ÛËkŽ—— bÝêÕ“'N<÷ë¯ù÷îÝÌÎf2™æff^³féО°êÓO›››sóòÚ;:z߃/_¹ré÷ß½<=={åìÿÍÆ&ôÓSRâ÷ïw;V_Êuìßb“*“¸®µd›?b+^C÷¬%áíT  MM‰;HÛáÄ¥ÃGŽP‰KŸ eì#Uƒ1‰hb2™Ÿ}ò‰˜Nü_½ø}´µµS’’„·Œwvïì,m#{srtìsÁ1­êÝH‚ ÜÝÜÜÝÜhž¡÷c#£˜;D>ë½÷Ĭâ´(0pQ` ¨W‡2ŒIÕŒIìJANùS¢HÌZ¢®.ô&L¦t0&BÉÖG–‚üò§ú$1kI¶iM˜L7aL"„’!ìJa–‡¤;Ge†Ë0J”HLJzÚ=)‡Ççóù|:;Ð$*qÉÚÊêU]]Bbâß’ŒI„B2„Ï‘¥ ×ü©>IÌZ’IZ`2Ý …1)Ÿw‰BCö ¥ ïü©Þ$f-É$­ “é/ŒIŒI„’!BübÙâŽ$ —.„†ªÊY¿C«ß0&‘(“HÕ`L"UCÅ$Î/D!„BØ/D!„Bì"„B!Ì;A!y»“£ì& Ô Æ$û…!$_ß~ÿ½²›€P7“Hì"„¼øöªgraL"ñ°_ˆBò’†« ƒ1‰Äü„B!€ýB„B!DÁ~!B!„x<„DQV}'„DQ|L"„ÐàòÿUÍ—±º,ãIEND®B`‚quagga-0.99.24.1/doc/fig-normal-processing.png0000644000175000017500000007240612476520570015725 00000000000000‰PNG  IHDR‡V”ü ¢sBITÛáOà pHYsÐй‹çŸ IDATxœìy\TÕûÇŸ{gc†}@%\5ÑT´4JÍ}ͰÜÒŒ’2-Ó,ñkYÚϬÌÔ2·J%ÍÂ]sTdsؘ}½÷÷ÇÅq„feæ¼ÿðuϹçžç¼ç~î9÷œç`$IÑ2r¹<55õòåË………ùùùF¯¿{÷î]ºt4hPJJ ‹Å2zý„õPWW·iÓ¦ .°Ùìÿý׈5‡………††¢vd`H•­žžž””ÄårÍ`+88xÇŽ f°…@˜‚ ¶nݺråJ‰DLG?…´Ò†‚ƒƒüñÇÑ£G›¢r„@ªŒh‘S§N%$$$Ù‰NOqsäàD§ÝJ©JuY&K­¯¤Ra–žž>räH£[A ,ËêÕ«?ûì3ðÝÕoˆ‹w Ž3X¿BR!¨Î,½û­\\ŠÚQ‡©2B7 22’ËåÎqqÙè鉛ذ¢¶v·P|ç·cbƒ„ù¸~ýúÀU*uØoÝ^0¡%’(Ê^[]p 88øöíÛ®®®&´…0 ¦~Ø":*›7oær¹ýX¬TÓK2ਫ਼žýX,.—»yófÓD ÌÇŠ+T*•_ØÓJ2`xH¿Õl(.—ûõ×_›ÖÂ4 UFèæÊ•+°ÔÕ•f.‹4€¥®®Ó„m V«333 °ç[f0‡a´€óµ£ Re„n ôfóÓ×3¡ÌQ¦Û ¬¬L*•²œèL7óXtvïæ1‡0.H•º9{ö,˜bzW+Pæ(Ó„mP\\¬V«éžf³Ètò€œœ³YD¤ÊarpZCŒÐ ¤Ê@X 8`Í7nœI­jÛÂqÜÝÝ=11±¼¼ÜDæ 0 ›8q¢‰êG „e™9sfs-Ã0ŒZ&®V"L_ ?Þ¥KM®³³³‰üÐ@Y$IR,ß¿ݺu ,HKK3…­½{÷RìpŸ¼ò"ËïyK{@ ÏFZú¯ƒûìƒ>˜;wî»ï¾›ššzèС3gÎèóãOž<$I&&&òùüÜÜܼ¼<.—»páÂVò›;Ù„_ýµwïÞ={öœ:uêéÓ§›ü:{£;²Ã瀼&ËlÚ¼_$%I‹Mm @Øì €ó·þWý÷hñÃßHÂЭˆW+XD˜G°‡ª}vpì””ªs­P(öìÙsñâÅððpX½zõÆßyçÍož>}ºJ¥JNNž={öŒ3¨ã–>•×ÔÔ¸¹¹ÁãñŽ=º~ýúƒ@FFFFFFVVVPP,\¸ð­·ÞR(ÙÙÙ:ó™L¦¶“MP©Tû÷ï§œœ:uêÆ<¸téÒVÿ#lç®SE÷wò:×dÉÏÍeyÇšnL;_©¼.—Ó1LE’E¢×]\La°aª ö]ÿÃéýÿ£3ík6Œƒÿó ÷žJ~.¨e5 7Ö‹îïté±À1äU oO…ÖÅKk¦Æ_˜——×Ò(ü Aƒ¨.—+•J###©dddä½{÷4Å¢££€N§79n Í{€««kLLÌÑ£G©­Çrss)G©Ë…B¡R©äñx-åS4N6áÌ™3UUUñññ•••~~~;wÞ·oŸª2Õ]älÒä˜T›ˆD°ÒÍí3>ÿš\^ Tve0Œk°mjŠI¨j¹ûvfiwÌ æÒã­ºËË4iµ¤¢þú'¢û;Ø=9uXÛÖô¶.^ÚXƒ0µá½ÇŸúC$‰a˜þ—7¡¥÷êcÛ¶m>>>šLooï–ò[·BMrÓþÓ”””jO8·´»ËL¡Íj€ƒ"Ç“8œË2Ù)©ô Xü¡›™b "6€TX(ªÍÁ0IªyÅGíO•Á!àºkwUC¾v¦JÄ­ÏüP”÷ƒK¯%ŽA úk³þâe ÂÔU rrrÊÍÍíÛ·/äääP£Æ%66jjjôÉo‰DòçŸþôÓOóæÍ£rŠ‹‹CCC÷íÛ÷ÑGÕë@óî²ãjó©´B­žíââˆaÓÙìSRé!‘(ÅÍ ¬A ô„Wt‚Ÿ[þèöW¢Ú[2a±ƒKH;ê©>10`8`4 0êkÌÁµŽiXcÎã€=Τ=.‰7»üqhõ,öTUÎT?.I4»üqhõ,ùTU$šŽ²Iw¤øÖËëÛ–w÷¢Ñ*:·iÜ s‹ý¬æäDµ¤€$ø™x'üIsxF(;¤„BRtXto‡Z¢{ßæÐ]ôºó5™ I…GÐ({Qx‡Œ/¹ù¯ø¨øëúD³ê¸¨„Å’’¿0º³s×)ì°¹¸ƒ§¥=27( ¢í#.ØÏàtõ¶ËsØ.I²)À™nîþXãì0B^WŸñŠ¥€°$$!¼³EZ|„UëyFcÑýõ)YS|¼:¿¢ó¬gç±F“4<óuo«`3ˆó÷¸ôxÓwl:'*Ù%P{@%xØŽùŠTDÒ¶F1*Šˆæ¶æ}/¼ód'TNä2v7ÍìÑ’P ‹”õ÷”õyÊú{Êú{„œ¯³ Ã#2±8>>^ÿ("FŠ"Ò!ï$ÑÖ-¡l »þñvB‡^Bà1Ÿå3@“ÜýVÁ˶ ?†Ó9];åD½ç9t‡KÏE-´Éµ¦Å¾%*#¬ wг<“¤šŸñ>¡h°¨OÄ”uw·6¶t©2¢­ UFX;4o÷þ_hf¸¨%•õY«:àÐÂæ  uWß% %•Äì&s»nþþþlÏ>jeÛ6h1•¢ÎäLš4ÉlF©2¢ÀòÂ]“”•Ÿçïµ ?õ™ªÅe“˜[ìz—^Z›a8Ã5,88X.¸+mÈ'Ô2ó¸%æßU)ååúÎGXH•º>|8”ªTæ4J™‹ŠÒkÞ%rÓ³·&)ÈùRYŸg>ψfˆîý$«8¯I:‡Íré”@w ¥rèìÎÝÑÁÁ¡W¯^$©æ•üeǨh$ÑÑÑæ1‡0.H•ºa2™pK¡xfI#B™ó÷×±’Ãéîþ‡3#l“„‚%™T‰Íé¡AQsM µ:€éÙ›ó\2†»ôx‹Êd¸EP)))ðèær=¢ŽH}ÅE^É_NNNK–,1µ-„)@ªŒÐM\\lihP›Ë¢`KCƒÆtshή1k5I•¨¤>{™œC ´ dµü«ïÙØ8p–»ûÀ¯4¡Ú;¥¢lj¦zM:u„ j•ôö¿¯ðJþ2Ѳ{•œ_r3õÁ àóÏ?ïÞ½»)¬ L Z¯ŒÐ@ ˆŒŒär¹s\\6zzšúõXQ[»[( ¾sç‡Ãi©dCöZqÁMÒ-v½SÈ«&öЂ$j/$É«3“î9ä;–ßí"’âÃõY«<‡þÈòDåðùü‰'ž=K‘Å\}çˆÃ#¥RÆ“‹Ë€F£¥¦¦&'£¸ñ¤Êˆ9uêTBBI’èô7·AAtã‡h-U©.Ëd©õõT* ÃÒÓÓGŽÙJyR-瞪Ù/£;z<¤ù’‡@˜ÁoDy?h’.=Þr‰\Ú¤ I¨ªÿyÉ{Äþ'‹ú`ÿþýßÿýùóç=z‹joÑ+¶ G*5jË–-¨—Ü¡AªŒhôôô¤¤$.—k[ÁÁÁ;vìHHHxfI• °æôdR%¥’ ·p¯öa4–‰D @^y±ö¿Eš!h–Ï@Ï¡?ê |!«¸àà?Tg%Aܽ{—Ï׬}xzzöìÙ“ ɇèÐ UF<¹\žššzùòåÂÂÂüü|£×ß½{÷.]º 4(%%…ÅÒWY©BMÒ¹ë×~Ý7Bµ¤¢æÔ$MpMš£÷Èßí3V3Ât UFtTø)ÒGÇ4I¸¯‚FYЄmCÊÚssµ·ÓÍ+~'Ó;Æ¢N!l4ÑQq‹þX{?ùúk«µâ9 FF³é‰$p"—!IF˜¤ÊˆŽ Fwv¸ ÙT’P ùïS›¥#ÆEVzR;œœCÀ0vÄ< úƒ°a*#:0 ÷žœ¨'+@µ·„w·´Rh*QIýµ'¡×iÎn±O³#Æ©2¢cãÜ}†CÀpMRtÿgyå% úƒ°1Hµœå]âñÞÎôøÎlq==a H•Ì-ö3š“_cŠ$øY2žE]BØ 7Ö+ëïi’œÞ+‘ôaó UFtxp¦›û€€Ñ¨$!«åg~`¢ †»BR|TRô‡&éü¢s·iôa UFØL¯h—^‹5IyÕѽôa¨ò²ŸÄ]§»„¸Å|jAvRe„à1Ÿå3@“ÜýVÁ»aAR%®»²œ|¼#2Fsðˆû£;[Ö+„=€Ta+`¸Û€Ô'a‡I5?ã}BÑ`QŸ•úkŸ¨„Eš¤k¿é®(¸4 UFØ4o÷þO–¬¨%õ×Vk´ z"~¸OÊ=¡I:…Np yÅ‚þ ì ¤Ê›‚å7„>W“”•?ü­¥Â*ÁCsø„èP(ëînmÔ$ná®}WµR0.H•¶†Kä;L(MRpk“²>¯y1BVÛpsƒýBt… îê»$¡ ’ƒí·mG†0'hw „ ¢—ÕœœH(…T’îâ=òFwÍVwŸÎõ›2Ì­Çë÷P @<~ ’u—–ÈÊÏ=ÎÆ<â6£-Ofõ•6Í9ÐUk‹JX\¯µÄü<è³F¹»8áþ ³{‡°RD÷Ö’dpî>I2Âü ¾2Âf©¿þ©¤ð &éû¹SÈ+T_ùüϯus΀‹µc*dÁsai–/_$I*j®ñÎÏRMå3={{Ûáè¥ anP_a³¸öù€¡µš¥áÆgÔZ—@/F§ûT&‡Î·Œsk‚Õò3Þ×H2Îtsø%’d„E@ªŒ°Y0Ë}àWÝ‘J’* ÿj2‹½3Ñ ÇŸ¿nŒ:Ë9ˆ° h8ð3V¨¥Õi w°æäoQ§ö ReÄ3Ëåk×®3fLXXfÂÂÂÆŒ³víZ¹\ntçéœ.®}Vj’Êúû›Læ¦ÉqEªl÷¼;É[^}U“dG$±üž7º•ÝŽæ}WF´FzzzRR—Ë5ƒ­ààà;v$$$½f~Æ é£ã:O©Iڟ寓h¯\{åèîÕ¿|Ø üÿÏòà9t`Fî®ØF;B˜¤Êˆ9uêTBBI’èô7·AAtºÑ­”ªT—e²ÔúúG*†aééé#GŽ4® R)ª95I%z¤ó쉪ÉB•«q-":N4ñ ç_<\w£9x{úwð4®M;b9õZÂñéÏ4Áð¸BR!¨Î,½û­\\j¢v„0H•º‘‘‘\.wŽ‹ËFOOSê VÔÖî ƒƒƒïܹÃẫ<©–«„Eª†|¥ _Õ¯äç©e5:K^®Y* 5ТÃcÄp¯¿<™šÏÉ4¯øLïãZÑ´#Ÿ®SBû}lô^xSH¢({muÁcµ#„ù1~×alÞ¼™Ëåöc±RM/É€¤zzÞV(²¹ÜÍ›7òÉ'í«‡ón|¦¬¿¯•è¹Å²+_ H•íŽ(NæIàD.5º$ÃãvÄöˆ é·Úä’ Òoµ„ŸÇåæÒŽÍöBèæÊ•+°ÔÕ•f.‹4€¥®®Óíg¹»ôZÂp‹Ðÿ4áË r,cßÖ$üãÙo˜Âu3ûG$a˜™Z†Ñü#’À°v„° H•ºQ(ЛÉ4§QÊeºÝÐ]BÝnòõ§CàHÐc—+-Y¶/ØtA¬ÛyM’[£tÓÚj̸P73Û#Ò•·eÎÀv„°è»2B7†@MHˆ™ízӸĆ¢¬ÏÞýVV~¾•ýIÀÿ,Ÿ«&Í6(€°$4L=Âû¨£–J*Uä«ßÈ—˜ÈÕŽLÖ±?ŠIÉ8،׎æõ•¶ í‡Çàÿó±å7¸¥2.ôzsz…° }]/k$>ÝSuó¡Ô‚þ M@ªŒ°}Ïy>ÿƒ×ð_Y>t@Ÿ–í„ÎNù]œïi’\i—ŸÿAÿõë€æabÆgR«Ú¶pwwwOLL,//7!&“uäÈ£›@t˜^}=ãwNú´$ó^ÓáJôiÙà0øÑnÿi’B•k¨ýA—™3gêŒzöÙgŸéYƒ•F’$†aÇïÒ¥‹&×ÙÙ98Ø„éh,’$)‹ïß¿¿nݺ°°°´´4S ©¯¯ß¹sç¾}ûjjjœœœŒkÅʹZte`h\[¯²ïÊÍ¡~×¾mÉ‘œëÆTÈ‚/ÖŽ1‘E„5@Ç”£|Žh>U¨Iú©šW”š=£Ld}Wn+í{^@yy¹@ €Â±cÇæå5þͽ¼¼¼¼¼ô©ÁJ„©q½r—.]""Ú°˜Äp´-ÆÄÄøùù%&&šÔPŸ>}~úé§²²²îÝ»?ó*[¢¨¶ð·k¿¼—Ô7¨Ÿ¥}±*åA•5Azq®»3x® ~UUÕ‰'JKKkkkŸ}}ÄËË+00ðÅ_ôõõµ´/ Æý¢öìëõƒ”ôÑí~^h’íS4k¦gDÁ0ì·ß~{ï½÷Ö¯_?wî\±X¼xñâC‡±X¬·Þzkýúõ8Þ8žžž¾|ùòµk×Θ1cܸq999ãÇÿí·ßèz„iôððP«·ñ©®®^¶lÙñãÇU*Õ‹/¾øý÷ßSo:-å7q²%<N§Ûá#i|ï û®ýºôࢾÁýLªÍT7Wƒ Žw¡Ór8 ÌM—Ë:•Ë::_ÿ/mãÞԎرÐÇãñrrr‡ fR[VõŠãååÞ™ÓgA,*§H^, ³¬Wˆ–0Ñóª%ñj‹S£^ÖÔÔ¸¹=ÙHÇÏÏOs¼fÍšõë×ÇÇÇ@rrrQQQvv¶H$š>}º¯¯ï;ï¼CKIIY¹reeeåŠ+Nž<ùî»ïVUU%'''%%é'ýäÉ“QQQ@’dbb¢››[nn®Z­ž4iÒÂ… :ÔR~s'›£V«óóó—.]úÞ{ïÙa:†ã´˜™Û.l½Á;Á5¹6Ïqq!$ùH¥ÊÉn)jõÖÛ/9[µmo1à´°yo{ôéÏòò±´G&AΫ®»™™¿skZZZPPP·nÝLdèܹsiiiÖóŠC½Ž¼ Ïò}sœg½Ò3»~¥B´ˆ‰žW­ˆW+XD˜UyèЧf=h·¨””Jç Åž={.^¼«W¯Þ¸q£æ‡%''OŸ>]¥R%''Ïž={ÆŒÔqKŸÊ©÷‚ x<ÞÑ£Gׯ_ðàAÈÈÈÈÈÈÈÊÊ €… ¾õÖ[ …";;[g>“ÉÔv²9=zô ¼téÒ–þú¶ õúÉ—ðÀÔÚ¼ÉóIpÿ3R锪ªßE"kVåÓ§O“$2q–ÿHÓNr´,,/ÿ‘ã õÅ>}ú´‰TùáÇiiiVõŠ£yYûKUDˆ‹È{„š´êHÃÔ'a 4ÛÝÙ#xŒØ\ ·jÏ…ÑŸW­‹—6Ö LÿÇyyy-ÂÔø^Éår¥RiddcšÈÈÈ{÷ž¬1ˆŽŽj°Zû¸%4ï®®®111G=z4äææÀÔ©S©Ë…B¡R©äñx-åS4N6'///,,¬®®îÂ… /¾øâûï¿?cÆŒV³I4¯Ÿšóô›‡88€Ð+µ¥P©Tào;ßùÅ'ü™šc ¬ðGûudý!â7;Æþ`>]§I„B!.ò²Åü»JiUç¾YÚ/s`ôçUëâ¥5SÞ¼šŒÂS“·õ¿¼¹O:ߨWŒmÛ¶ùø@­[ÚóaÜç•áâeNajƒ*3Œ9sæ$''oß¾] ¬[·nñâÅíö£%ÂÃçNºlÙ2LJ "‘H233'L˜ÐRþ3{½………$I*ŠŠŠŠŸþ900°S§Níóíù¯½ß 1 IDAT¶ï±´9®¬Œ¨'ˆ:µº‹uØÏoƒC[+ùá¿ïÞô& G±© ÀѵÍK:mø‘Õ¦ç•áâeNajÛÜM›6-\¸°oß¾L&sÁ‚&š<µk×®5kÖ¬X±¢¬¬ÌÝÝ=::züøñ­ä·Îرc©&“Ù«W¯C‡é³RËnÑÜëí®µ¦¨W«o*Ñ,«;~ÉÜ}þá¹·ãßi_<Âf6äf­ Ž\fi_¬ýµÙpñ2›0Ñ¡Õø/MN999íÞ½{÷îÝ­k鸕j›Àb±¾øâ‹/¾øBÏ|ýýG˜š@D÷•ʽBá'uuûE¢?}}½hmëø>ª+yÿðò¸ÐÁo[ìÞÎá Âp y2•L¦”É”2™J&WÊ´’Òòer•Lªlÿgì['^’P)*9ßÙ#²Ç°]ïX#þ(&""¢ù“¿%ñÒÆJ„ õO¡yëÜ ßµ»€ƒã±,V,‹åO§oª¯_UW·]¿M¸Rtéڣ̉}&Í8Ï™Ån·KD»)o(Ûxò‹&3ôÁ‹­W GÈ„EšcµB ®»ÃöˆÂi¬vWh“˜z‰E@ªÜ.¾{ÕÒ.ľk{uΞ 0Ñý=ÏÅeS}}º´m›åáNë©”jåþë¿¥çýóæ…/ö‹ch£3„YÒuh/ÿçþwjÃŇçõ¿ 샄UGàxûŒ˜œ$¡V‰% kŠþxtk#¯øHİ –ç³/~L‡~dYäye  œ½ SJ÷]ûU穾Áý¶LÞ¶eÒ6SÜâY?%옹»wPíœ:I݆ôõó÷¾žSv˘þ!zàîäþybêÊÑ«õ°y¥÷ø!†M¶ÂpÃÅÅ«o—ØÏ{.’4<(¹±Á  ;–z^Y¨¯l/¾õgó!83¼oî‰ ²K–»{wß:ù»³Î|wak¥ R“ÿ úþ’ ^¹hè½Bšò »xYf!Üù)#¼}I’$U*š£cÐK^ÑçBR­–UW:úšÚCD›x±×ؾÁÑ_ü».›{½õ’AnÁ‹‡¾mDӾݦ—ån«¯8gÄ:­K=¯¬¤ÊvAóOÓÝßïÕÖ€Š$â¾R™¯TÀR×6TÂ{!lÄà.Cö]Û»7sLÕ8q†òôý“— .Îè?{ZÌ ý_Ú~¸ôÝ‚!‹B¯¬¤Êvö‹§©ïïÝB¡æ˜ã}Y¬…θöîiÍ¢³æœ÷R¯±Û.|{æþ)Ÿƒ2•ì§Ë?¿“¶pèÛÃÃ^À Å•W|q݆ôõÛ¦þ`©Ò$A(øµu·²q÷øÿ}W'©Óäß*½™ôëœq‘‰ó‡,pslÝS$ÀŽKßéú|[°Y=ˆ?pšP*ÄŠ ölËÿykØüåõwnÀƒ7€¤´D-•0\Ý9Ý{Þød™_ühÿ^¢³]Ìì¤E8?e„áCô„B^w+Ë(þ´‚X.ú%s÷¡*…v>†aM±4ƪ1k4†áF« hŽitggçüÃæz2¼f+ÇfžWí©²í304nZŒl“…cøØÈ—‡u¾ëêÎ?nRªãˆ$‘vûÈ™§_{cBŸ×èZÞ‰äB«ä_ü»~ëämð™ÁtéÞíõ·o¬z;lþrŒNwðñ™4‡:Kc9`8ÞçÓ¯ëneUžþ»âÔ±ØÍ?›ßI„N”jåќû®îlÖ79Ûy@lçØm¾ÕÎ|sð瘜g` [z^µ¤Ê¶O¨§­mÅáÌb/Ž_šõêÖsß\)º¤ÉÉ…[Ï}}4ç°&T§R­ÔôorÊn¾ù‡e<&IQñCÇ<£ãJþüU%¹t µLJÈåj…̳ß@N·ˆËó'ªÄ"œÎB!Ç™v5BTüðÁ÷_JÃ…¾(ÅÁÛWZQöà‡/e5•:5É{àÐòô´Êsÿ(øµn½úD,þÀtÎ@žÏ?»ýâ¶²úÒ&§ºzu[4ôíþ!.^ÒÎïÔgrô4Ó¹d'ØÞóª­ UFtT‚Ý;mÿåÕ¢+[Ïý¨®D“¯ª³ÉêÒïÿÛæàÁ’ÕÉÍædÆ’é$A¨¥º 'ì­dp ì±äƒûßm$ÕjœÁôŒ˜ðÊ­ÏÞ’$TŠÐ)ó7 IÏ~¯­x³ÿ×­4 …‚Á`²m«^dÞÖÏC&Ïõ0”›vàáÎ-‘)ës¿^ë3hxpâ 5xÅõ²R$¼œ4¾ËŒ7MäËòÛßžßr·âv“|o¶wÒà·Æô|‰š9èÀx²íŠÓé£Ñ£7ÃAªŒèØ ‹éûçÍß¾ò5XMA…êLˆ£]Xª”vŸÒåöv3¶ôÝÔ+f°WÌ`휘ÿýøT ‹LYo:ÇÚDCCÃáÇgÍšåèhÌ¥>MP $¥%ž}€g¿Å¿ïV êEÅû¬Ù 4Ǫ '¥Õ@¨”­×ÙJë¹Û/n»N3۟™é<=vÖäè©ô'J¬­ÊK‡-÷w 0º?;½Ù!:¹ßÔ}ó%>÷ªvgE©V¿ûW“®Ý8~­n÷_k†F£åååmÞ¼¹ªªÊüÖŸÚí† ²W-!”Š€Q/ÝPƒ´þë³_ÎÚ5í|þYmI¦á´ñ½'î›÷ûìsµ%4ÉÁ]†Œ4¾Kû©2B7Ç€R•ÊœF)sQQQí¸ÖÍÑíýQ4ÕÙœÐq¤ iv ŽãPSS³yóæÛ·›ê ÇÕ)¨sÝÍL¨Í¾êÖ³ƒãÆí^zì$I*‘PÙÀ—”–x JÈå@ýk88ß›µgÊÎ×þ¸qHE¡ÑšjÉíÛ·7oÞ\SSc G —ÈóɳõðÔþÎÛÃÞùuîþÂG>S’À‘á¸bT‹c×T;Õåg¯ƒVƒ‚’(Î^'ªË1¼!,ê+#tÃápvîÜ™°[(<+•¦¸¹ rp0Åhv©JuY&K­¯¤Ra¶sçN‡Ó¾ªjżM§6þWpAŸÂ Pd“×aÏ·ÏVGG­V«Õj‚ ¨)š«Õj…BÑüòªªªÍ›7Ïš5«GŽ™™Éa^'3KÈ¢&S¬4ÆÄ¾“g÷ŸëâІÀj8†ã´gtl4í¨ºà@C奠^K8>ý™&ÍVH*Õ™¥w¿•‹K lGËÒ4b¡MzzzRR—Ë5ƒ­ààà;v$$$´ïòwo=ÿµP&|vQ-úcq_½û50jD”BAÑþŸÂæ›¶‹£ Í­' C©Ô½ Çñ±cÇ>\ó™™êŸYó9¶LMì„ÓŸÖQjnÖžû¿ ~~…í@íaqP_Ñ ùùù©©©—/_.,,ÌÏÏ7º‰îÝ»wéÒeРA)))íûTI¹í·×e¹°8`B™°IO¨n’Ù †Rhü•¯p~Ê–‡à8©T@ð«Ó‚^šØ¼˜f7eµLRq꘩U¹­D‹ã®Aüõ×_¥¥¥S§Ne¶q móãàéà"eÅüç{yd¹’A€øœú挈+öûÅ´£:D;BX H•Ï€Åb}üñÇ–ö¢50À´w˜'”*¤"¹P$‹äB±B$’‰„r¡X!Ê›¿ÝLw¤÷êÓSI*• P€2ôåN~+0‘o}Ö~ãàí y9·Ö&û‘æØtSK+ßM¹U¦¸qãFYYÙ‡~hÚølýÈ’!lã…´NYãê#¢ü±€#ܦ+ÚM„õ·#„•€Tak`€91œ˜N>º>.Ž_ oõ]`u2ÚÃúœ3ÀTª¬Ú$µLJstjÌY³›r—Y  îffÁžïäu¼Àѯ†N{ÃÔŽ=’$qoE›ƒƒƒ“’Œ°w¡IqH–yŒb‹àUå8ú/Oå+¾$êR"¬¤Ê»ÃŸéFϬ¤=lÀêdP¡lº‘!I¥°¡ø÷=NÁL7hÌY³›²¬¦ª.žêûÙ·’Òâ[k“­A• UŽŒŒœ5k–õ_+Y ¾JâAoŒ‹ŽWKG ”‰M—E!©2Â^àç—üõqð«þL7È|<òº¨ØtF3–Ìšƒ£kDd¯÷×Q![æ±pF§3Ý<‰æXF£ÑpÇq¼ù&Iåp¹\•®(oñññ‰‰‰Ú šÛÇù)#¼}I’$är:›Ýuö"Ï~©üß%3¨¤JEst zib@Â+m2¡b1¶Vœ\â?²›ƒ/•ƒWK™G œi,±Ú|»• Ï©2ÂÆ¡Ä¸àDÿa9ø3Ý´Ï’&ì+øv/õ]ù‰E‚È^µ$èÅ £^.ù}OóK0jù™‰·hÚ´© Q±V®lº*ÇññãÇ2ÄXþ øö7’¬8{âÁ_Åm?¨»@ÝÍÌ»›>n«*€œPn­8¹yȼLDå`<éò€1_—ÿkë„QAªŒ°MšˆqK¨»¹B–ÙœÐsVKÄ@Èåtg6 ëí±5é ³X¬Ù³g÷ìÙÓø–0ŒÓ½‡J¤{yI ~mÝ­,ÞýÛW½‚P)^e+ÂK…9éþNÀhi­ÀÑ­îEXH•6…žb¬AÝÍíÙ…Œ ÓÍ£I0çßüBí¦üÜŸ›Ù=ÑVeWW×ùóçß IÊxUÅwyÇéQ®Yfí×ëÝ5í·BÇãB™Ç‹pîaN›¹1ñ—Ž^H˜–©2ÂF¸ùÃßw~=#*¯ÕÿÒÃôpxv¹ö¢{±†5æ¬ÙMYs‰ƒ·Ÿõ¬•ÒÝ ˜?¾››ñ_ežˆn¿ao¾Û¼@üÓ„R!~TT°g[þÏ[ ZÕMÇcC™ã;åüü²´^þu…“·¹ßÒˆ& 8Ø¡ÏüG~½ jn‚³ŸŽM÷t¢îæjR—lª¯Ü£G¥K—šB’ þÀéø§{.ÿ¤>/GV­{[œÁtéÞíõ·«Î§jŽ+ƆŸ,žãT¤ÍHW›xB>ñ,*#l óë×mЪi³.~ùêÁô‘gó_wPh4ÚàÁƒ“’’L4Ê{àÐÀѯÞùßj•D¬»IŠŠ28Æx¢aŠ—BoKJ5õ…•iÓ7ˆ+ù­\„@˜¤Ê›CKžc—½ÚÒNÀ¦¾¶%†þÚk¯¾JB¦¼îèãïÿ6ÀÓ!ú3–L¿ºhê¥y¯”üùkØ[ÉÆ1FÃ~¨<“#~žº¡¸êèô ¢Š:ãÔ@´ô]a³<<žyýÛ´–ö_AÃ×úcêzµ¿ c8þÜÊ MòM÷‰]E?V=¶àë¢ôl*Gð¨:mú†—Mq ô4‘Q¢P_a›<<–q&ùBÝ‘ªy _#(T$1jË¢.cb49nMÚŒ ÂRž½BØ-H•6HIÆixÌÒ§‚N ák„686ò›…]_ŠÕäKyG§opk,èÂ>AªŒ°5šKò _¾½$Q{ò—Ù†¯ üÛŸ`[CÀiøˆÍ º É•צMßÐPRmA¯vRe„M¡S’»ÖuÌ“žáÃ×Õ—Îd%Ï»ºxÚ•“3ß™]uá¤Îb„B^wKßàa¤Z-­(YM¥fý.Âlà4|Ä—ovåÉGtQE]Úô EºWj!¦©2ÂvhQ’ ËãñÉ E½áÃ×÷þoCÄ¢”ÿ·/nûÁ>Ÿ~ãÒ-ÂÀ áñFËÀòô‰ûþá"Ú FÃ_ؘ>a°&G\ÅO›‘Z_XaA¯všƒ°Z—dðëÛÕÙÏ]\ÉÏ1Û ©nÜF‰éêÎtm/ûçHåÙÀòò‰XüÔØu“St'giEÙƒ¾”ÕTbtzèÔ¤êÿNÁã–s>{Ÿšx,*~øàû¯¥‚á _”@f,™ñ܇_XÕ̶FÇmxÃñ{¿_¤rÄÕõi3R_þ5Ž«¿e}Cب¯Œxr¹|íÚµcÆŒ ÃL@XXؘ1cÖ®]+—·{†gJ2h±²ucÄ¢”;WÝ\³¼ôØïòÚÆ9A‚¹Ü´ý}>ý::õ{º“sÙßhÊë<•ûõZ>ýlÝÛón¯ØA]ç,€è?8ú4^F’y[?~uj̦}<ܹ…ʦö`ŽZ¹¡ô8êR Çâ?½Ç䡚IMCÚŒ üü²v×Ù!ÚÂ@}eDk¤§§'%%q¹Ügm/ùùùùùùÿþûïŽ;vìØ‘ÐÖô’dèòRì¿?¬P!ª¢Ï^ý‡ðs®ó²þ+ùcOÈ”×ÇŒ¯¿sü¸$¥%j©Ä7¾ñç4?¥Ô‹ŠöY³™Út£éhŒJAƒ¤´Ä³ïðì7°ø÷ÝT¾yö`¶g0‹_?£á¹ûÎQ9Rž mFêË¿¬ðÒy‰J*ç^¼šÝüT‡hG+©2¢EN:5fÌ’$;Ñé)nnƒ‚èÆ¿aJUªË2Yj}ý#.w̘1ééé#GŽÔÿrý%üúv=Õp×NS¶˜,ϘAž1ƒ|ãGßÙ°2pÌxŒNwðñ™4‡*@c9ªFÕl~Š:h)ÈIë˜gf{Æ®áøÝ½g¨ i0mfêË¿¬ðŒn^¼ä\΃?/5WeM;b9õZÂñéÏt2þH¸BR!¨Î,½û-·]ía= l„nÁ¼yóH’œãâ’4™Í6…$@>™ÍÎ šãâB’ä¼yóž×¶I’0ìŠ ßpŸ æÊ9M¬fEéî žÑq¢â‡*±ÈÑ/ÐÑ/æè¤)ßüƒãÆí^zì$I*‘§3àé–W§ Îu73 6ûª[Ï>Fq¡/öü𙑳ŸÈ›Œ/úkæF^î£æe ÿ¹Æý﮼á©ÞšväÓuJŸ—þõ yÅ’ L'¯Wú¼ô¯O×)mmG«©2B7›7oær¹ýX¬TOO3Ü%8@ª§g?‹ËånÞ¼YŸKÚ,ÉОž©.ª/Ÿ½¾âÍ«‹¦f,™^~ò/jsF§ÀNK>¸ÿÝÆ¬ås¯¯x“û×AMy§z.[Å¿}yþ„Ì¥³êr®1Ý<¨–Iµºñ2 ëñöÊ’?÷^{/©öú•îo,5’û½Á°!«§GÍ}2 ,«ý5kcÍbíR*™âÑÙ[„RU|ê†v>ÕŽØQ!ýVfú–„á!ýV³=¢ôoGk`#tsåÊXêêJ3—EÀRW×¹ÕÕ”éÖiŸ$‘^ÉŸêÌ÷Šì3X;Gùù)Gÿ ¾ë¶hç4ßh™Ò-zÃvZÕ̶ † Z5 £ã·vüCeÈÄÇfÿoì®dŸ¨.TNéw•9<<–>qˆæRêföHÂ03µ$ £ùG$å_^ªO;BX!¨¯ŒÐMEEôf2Íi”2G™n‹K2‰û`JŸ7_Ò$åɱ9›ªnPÉ‚±bÊ.çÊø"M1êff{DšÑÓFsÏlGë©2B7999`¢oÉ-A™£L·’dk¦[·n çY]”JÊ¥€€€g–l…+&õ[8N“T¥Çç~Y™ýPª½Eej¢ðŸkš2ÔÍl¢oÉ-A™k½!¬¤ÊˆŽ’d+‡N§@åùtK;ÒÊ%7wC7gìŸ<1zq¢&©I¿þåí]§ä‰&óáñ ­ ì¤Êˆƒ‰$Ùj»w¦À(]ÆV1b†a%üRqꘕüIå¼êŠSÇ*þ>Ò?qùÀY[ 0ôûnìòñ1Ë^Õ$•bYÆ—¿k¨Èz ©i0Ð Ân¡ƒ®­gÇŽ{ìØ1ÓYÕ¶ˆa˜««ëóÏ?¿}ûvS<,ø|þçŸ~øðáââb:Þ¹s瘘˜;w²X,£ÛB˜Óõ’5Ý»Îg^›•Cu9މêïÖ­[bbbZZ/ÅJèÒwÌk)‡™Ž.$@ ä‹—XaÌÛ¯à4ZæW±Û•Zû,©& ÿ¹9 í/bVfΜ¹wïÞæùëÖ­[µj•>5X‰05~5<~üx—.]48;;݉&PI’‹Å÷ïß_·nÝ‚ ÒÒÒŒk¥®®...ÎÝÝ=55µ{÷î ׯ_?qâ„J¥²U~tþv§øç,í…A˜tàzĈ÷ïß/=ºŸéêæÑ§?ËËÇ(ÕZr^uÝÍÌ’?~Á0lÄ ưaÃzôèqâĉÒÒÒÚÚZÓÒ//¯ðÞƒ˜Ž.T²† ö€J–²ß¢q²zaÎNÝcõg Uní~^mܸ‘Rß±cÇæååQù^^^úWb „‘$‰aX^^^D„6½Ñ“æOŸ>˜˜(‹[¹ª¼ýöÛYYYçÏŸ· nÎÍO<:—³ô•€mø/¦^kBBLåV xÃÓ¯Œ+ÉÔïÒ^Ê©VÏ+íûdÏ„­ Ç fiGÌ ´{êX4.(pǪ‚ñûÔñòåˡ֊* þÎzx<£îA‹a±1›yáKg?wê~09¯ýÞ·‹Œƒ= ½‘ã,KûžWÚÜ»w¯GíøíV"LÏø®Œaؾ}ûwíÚb±xîܹÎÎÎ~ø!Ašb'OžŒŒŒtrrÚ´iSEEEtt4ƒÁ˜ptíî4 ÙJORŸ_vŠ_vÊ·Û4š¨²ÑŸW­‹—6Ö LmˆÜ„ãO}„¦¦‰éyZz ^1¶mÛæãód*¬··wKù­˜ð÷÷www?þüĉÛí§Í ýú©ÁXÚü«PI..Í%¹}˜H’3ïó_}[“|è5ûÑÑñÇ …jw0P€lÏŠœN Ü+hp¯ç×̪¸ž_x"«(=[\Åo^òá±¶…)¹ñyÕÃ},ç nÿÇö|j0¹˜[_qÁ:ÊÆ}^é/^Ö Lmx†999åææöíÛrrr¨Ñã 555M¾F·”ß 8ŽOž<ù“O>IHHpqy2¹ƒúÎßäÿÉæiþú©Ápm¾,“ÀKNNÏ,©'F—d¡TõË©G×Ô7—dÀ1ÔW¶ X ñÄ*4b\Mtrpv—‰uª>`4< x@ÿðÁ«gTÝ,(üçZѿׄeOƒéÜð±%Äü¼ª‡¿ÑèÎ=†íb96õÜ9Ø·ÛŒöùÙ1îóÊpñ2§0µA• Æœ9s’““·oß.Ö­[·xñbý/דððð©S§.[¶ Çñ!C†H$’ÌÌÌ &´”ßúÒêuëÖ 0 66699922R&“eeeíÚµëòåËÚ³Ûôd{·× øeÖŽ!Ú\¢R@7†‘_ä%É×óë9õH i±CŒF°í_¼„¯ö¡¦¨Þwô[WþÜ``Žùõëæ×¯Û §Tß.¦ä¹¡¤m¡ÍjŠ€o÷™Í%¹ÝØð#«MÏ+ÃÅËœÂÔ¶ñÆM›6-\¸°oß¾L&sÁ‚K—šd·×]»v­Y³fÅŠeeeîîîÑÑÑãÇo%¿¼½½322Ö­[·~ýz.—Ë`0"##ßxã jdÑͽަ«¤$ ÎF~0Š$‹¤ª½g¸÷žÑ¢!U¶h ôÅ•A“ÂNÈ»¤£CÖN0Ì'*Ô'*tàŠIµ÷¸…'®Á»»ô¼TP“(öHÐ_› /³ Ö—™[ ~ñlBÀ€ˆW~ûôŽ"\R"#ÉÂN\ f*ŠÈ÷aó —ä {N>j+ŸYÒãuÆs ±…è@€ÝWÇ(À‘J–Þ»œþãÙÒ?ŠHÖ} µ,f|a„>Eä»®s ¯Êú1ÑjOKaÖ}úÖÏ“ûû·ô¿ªþ@©ÌS*û)`Ë+ûWúöíÚîË%2õÞ³Ü+¹úΰE#Øv¤?^TBô¤’Aƒî "CL\Oµ ht£MΰlL)*·¶´ qóÇ:gOPrppx T‹¥Ê†H²BEì;WÊ*C|dJB¦PË„LÑšî¢9Øö†+Æcc "Ò•J8_Ö³³ nÀ¢ÃÁi„Z¦VIŒÒW¦èÐ,Ó=¯¬¤Êö‚J*¿µã§ ¿¿§³Ù¿…{„Â)ÎÎ},ß”IÇßÓ¹y~æ}þöcE:/A}e;Ä+È'ûQÇe<é…۵â,Ø€å(H¸xõ³ V‚IŸWVŽ}­²gîüz¦Éâ?‘¸7%qoŠ·x ‹5•ÍVäkUU¿‹Å*­É $@¶\¾ŒÇ«U[RùÔyär…&‰=É‹†VFÙŽ˜È«Ò$\*—¶: bj(1®ãž° ÖƒIŸWVê+ÛÍ_<þ¾ù¥§'pP$ZXSóÖ›ÉtÁq!AÜQ(jÔj `µECŸž¹YSY'£ŽI‚¤”‘Ý5gq4‚m—øáE5Ré‰êØÕÊIC¶*©­x‡N¬.w~=ãÞ-`Ô–…vx@eìì­'[÷ÌHÿõ£Æ˜ˆ¹%Â/Ï'þùû¯Ú¼á.Â6¸’[÷ã‰bêøÚ}þþÞÝ-eÇ™]¤út™T]ô‡ˆ—-¨Î$ %îìÀ õï:žÁ²Ùý¿5Øùó *ÛaA}æ¿hi/,Æóej¢qö™·+kT¿'Aä{vvÖÛûì­¦ÅF×g`“ÙÕÅU ö+[5#Ü‚k¤\¼c\¼c,gßÂØùó Ðl{ Süs–vÁbä–o6h’“†ÒiO=o'Çz¹2˜¨!Ø/S‡i’E•⌼6ìðˆ0.öü¼¢@#„ÍBäþó¥šdX ;&¬é–$,þƘ'ê+Û5Mîß/–+TD+åÓTa³\¼][Z#¥Ž›ô‡´ b»:Û˶µˆ–ÐG©*þ½Ö¶ŸcTa›Hê×Ê5ɸ!¾(Â0¢E¼]Y#µæüY©Ï¾&„ÑAªŒÐMTT”ªÌ^ƒ2G™6cW+5*³øÄç-ÑQxy€Ÿ‹cãX¹’øã¿òÖËëÃðáÃ@!©xfI#B™3J;B˜¤ÊÝøûûÀ-…œF)s”iCà5(NݨÑ$_Œõug£1jÄ3pdÑ^ôäÞ»t·öQµÔÀ:™L&ˆêîXO› ÌÞŽ©2B7qqq°¥¡Ál¡Õ[4¦ áÐÅ2åãÙ:î.Œ1±¾†:‡°⣼<Ãà$К-Ø>¨›¹âÞ’4SK"IuŽ`Œv„°H•ºY¾|yppp¶\žR[k†Ù¨@Jmm¶\¼|¹AŒ–‰®Ýçk’¯ dÒÑ}ŽÐ ǦÄ?™˜÷Hx£ ¡•òÏ„jG¢ºœâìu@š¾%‘Dqö:Q]Žáía)ÐÓ ¡‡³sçN Ãv …±¥¥E"}c.U©ŠD±¥¥»…B ÃvîÜÉá´ÿy`ß¹RÍ–U¡~N{Ø~Ü`„y.”òäÙ“G<ãiôCµƒ׎„¶fÍKû€°^ºvíºhÑ"ƒÁb±p¯«3~Ì£îÝ»ÇÆÆÎž=ûÀááá†T¥P[Èã„1aîcbÐeD›á8ÑëÅJ*'UJâ£< ùÒ±Ú² ¾2ÂvH»Rqärãð †}þz/Kíʇèè$ªwޕʧhêç3­…(4„qAß•6_¤<‘U¥IŽêçƒ$Ñn8Nôqü4É37kªør úƒ°*#l„?ÿ+—+Ç®9NôqýZ/@´Žö‹š _%…@èRe„-PR%¹œ[«IŽàˆ6gD†Mú$$ÜÍ‚†¼GB úƒ°*#l}gK5$‚¼ŸÎö7‡G˜è0÷nZsøœ/%ÐD„‰AªŒèð\{Pÿ L¤IN„cÜ´a;`Ó†jn¦GÕÒKwÑÖËÓ‚TѱQ©ÉCÊ4ÉÞ]\{uv± ?#ÔÏY;öô UFtlNeW×44NŽ¥áØäx´7ÂÈL|>@³X¹A¬<žQiY¶ ReDF Qý¥õˆÞÛËßÃÁ‚þ læè˜'±½Ò¯W× Íº—®@ªŒèÀ¹\®‰óàì@OŒC[×!LÂKýý\7U¨ˆ?.aëeB'H••2žôBΓÕP‰q~ìÇ[Ö#Æ…ÅÀ' Ð$3îÕVˆ-è†AªŒè¨ì?W¦Y¦âëÎz¡·eýAØ6ƒ{yvòq¢ŽI€ýZ[“!F©2¢C’S$¸["Ð$§ÄÑðÿoïÎã¢*÷?€Ï0 0ìûŽ ¢ˆ"^S£P3à sÉ$½je¿ÔÜ®–¤7Ókja–f›šÕõšš•Z)𹿂†; %Ûˆ û2Ã03ç÷ÇÑqB–˜å€Ÿ÷Ë?fÎcXüœƒ¦>|xÆŒ‰ÄuùûûoݺuذaMÈT­Ýý§æéÌQAýBMÐ0€‡]¾U±ñÇ[š§ ÆurÐ.{·vÕŽ››æ÷æ®ÙS«ÕüñÒ¥Kkkk‰Hdã¥e>mÿ/¾øâ™gž1ÆÊÁ04é×_eY6@(Lprhmí'4|‡¹­Tž‘ËËËó$’ØØØÃ‡:ôáb,Kßj] ÕÕÇöˆd0ŸÞ]ÃìÓ󪸧»Žßï&¸ѼRÅn=˜«R³r…Š;½|ùòU«V‘w苎^Ñöî}‘Û£¨-¬¼›rûÆ'‰døðáM}€ÿ°WYYùÒK/±,;ÍÞþ‚ŸßD;;cD2ù …íì.øùM³·gYö¥—^ª¬¬|¸Øé%ywï½cˆâûaÒ0¯IZwò.,•¿*Õ¼´ïL!w°Y®PÑüñÞ{ï1!ÑŸôZìè9а‘LD"±·[à˜Þ#’=º<Ï}*** [˜R·~ýz‰DÒÇÊ*ÑÕÕ½D@”èêÚÇÊJ"‘¬_¿¾Á«r…êûÓÎt},Ì%ÈËÖøhŽ¿»Íã=ÜzùÇ3…µu*"Ê*¬9x¡ˆ[(W¨ˆhñâÅJ¥Ò+dš³Ï㶉öYfç!‘H6lØ`ܺÀ8Êи³gÏÑ ß `ã¢}¬E÷¾"Õ2ås… ¥zÛ¡\Í íòzµJ¥JII!"ß I cáö 5ö=‚v© +,,$¢^"ïgkWWµFI¥âÈw5OŸéëáboÒV4ÅÑÖrD?OÍÓ£—Šw•h&ž#"¹BŸŸ/“ɬÄ>B‘“iZeë܃úA{T†Æ]½z•ˆŒt,¹)\u\Õ{Nå+îÏ6ìdg9¢Ÿ—)›мaQ®÷&*Uì©ë%گʪœœ•J%´v5Y“Dbozè{íRxíVAÍ…Œwæíce‰N æWW¯®¨©/*«+,• wiªw\™ˆV¦j´o¸2 ø«Á]l;yˆv7Ý@•µÊÏögIŠe²ûYÛ"¹BÉç@/"zxš˜Q£FµVíº³³s\\\Aá§“ÕÔbaaÑ©S§W_}Õ4b€AœÏ(½UX£y:i°ƒË¡À|ÄÂEº>áª{?¬«Ç­MdÊ”)ÎzÆ]&® žÓ½måŸþ¹sçΚ¥¶¶F¿ì„«‘eÙššš›7o¾óÎ;3gÎÜ¿¿1* ¬®®NKKÛ°aCTTÔùó烂‚ ^oå—È}]­ÍÝ ½)”ê½'|¢‚BýìÌØ"² žñ‹êê´-9·¨¬å¹-e z­^Z=^­]»ö­·Þ"¢¬¬¬‘#G¦§§sËÝÜÜt_ ‚‰aY–a˜ôôônݺ¼â¦<\ãÑ£GãââjjjšyWÛ+ª­­ŽŽ ùöÛo [ŸºPt5»rÌïP=Ɔaˆ¨80ÐXÍj‚{N±,{àÜîßGhÁ¬šÞÝà Gæ€/Jõž“ù¿].n~Îâ§"Ýý…Ù111öî}»þÆT­£ó»Ãˆ¨=N¨ÜºñJ[FFFXXX+þvžS 'Î0 ³sçN__ߤ¤$"ª©©™>}º­­­‹‹Ë’%KÔjµ¦Ø‘#GÂÃÃÅbñºuë £¢¢,--'Nœ¨TêtóQ•êÞ¡š»wïÆÇÇ;88ˆÅâñãÇK¥Òæ—7hd3ÄbñòåË÷ï߯c«:†Á½Ý Jd‰»3×îþó¦¤ÚHµ¸çähÿóËÍí—Ÿ?³¸øW™¬CEMý/)f éH^ “‡ø/~.Äͱ¹ëô¸¹½@wF¯š ¯æ™%˜îíÁ...vrzp-—׃‹OV¬X±zõꘘ"Z´hQvvvjjjuuõ /¼àéé¹`Á®XBBÂÒ¥Kïܹ³xñâ#GŽ,\¸°¨¨hÑ¢E3fÌhæ~Gމˆˆ "–eãâ✜œÒÒÒT*ÕsÏ=7kÖ¬={ö4µüáF6/::Z&“´X¸c°²ÄöõÜ}2?CR•!©êæoߖߡ͛foÏÕ³l™Z®Pì­©Ù[S3ÈÆf«»»£@s§÷ž.г·Žê«¡€BýíÞ™Ö}׉Û'®Hýõ)W¨H¬ß:¹Í\ …•ÈÆÓÖ%­Óh'ï'ˆ:ø¹F¯š ¯f˜%˜î¥ò“O>©]B{Û?!!aúôéD¤P(¾þúëS§N…††ѲeËÖ®]«ùÃ-Zô /(•ÊE‹M:uòäÉÜ㦕s¿ÔjµT*Ý·oßêÕ«wïÞMDçÏŸ?þü… üüüˆhÖ¬Y¯¾úªB¡HMMmt¹H$Ònd‹‰H.—·X²#ÜÛýÐÅ¢ÊZ%5›×¹>8Gš%:/—Ï–JËd/ݽ»ÇËK÷Xþýƃ‹>Ÿ}Ü[le²Æôce)˜:4 *ØùËäÜÒ*EƒW[½­ìÑåybY–U*ëÊk+þ,Éû©$ï'GÏÁ7XXÚ·¹Õ¼fðñªùðÒÆ‡`º—ÊÍW8p ÷@"‘Èd²ððpîixxxFF†¦XTT …›¢ùàèèØ·oß}ûöq·KKK#¢I“&qo¯ªªª¯¯—J¥M-÷ññÑnd‹JKK‰ÈÝÝ]Çòƒæç§f‰ ¶›¢þÖÖ?zyÅœ”ËÕÖŽëºÕ ùYèëjÓS“5Ì¢G'ûw¦…í<~ûôßg©«×õª‚¢Vh=c«ŠSo¥$TÉ<3/ìÉmÄtä«ö >^5^ÚøLz\¯,øûHî41ÝßÞ@S¿¸ŸŸ}ö™‡ÇƒÚ»»»7µ\ßzÿý÷Î;;;?r7Ôþù©a‚l _±·__Qñ]Mñü ?ÍÝñøÌÆÊâ¥g:õ vJ:’W^}oÚvWfìÝ£Â%]K~¶²è\YÁ1gß§ ±Zþ2ìx¥{xñ!˜ôHe???±Xœ––IDW¯^åöÖ?þñ"*..np4º©åz‘Éd«V­Òq—BóðÏO cgóp±x}EÅ庖/#i gCx CËåx#¢³ãªiÝwü&9›^JZs{µ•­ŸWð?óÓ7IstøT6ìxÕöð2e0é‘Ê–––Ó¦M[´hѦM›*++ßyç×^{­ÕíhJhhè¤I“æÏŸ/¢££kkkSRRÆ×Ôò/­ÎÊÊ""™LvíÚµ?üP$½þúë­kÛK¤¶îí‚ñ²9ØÒ’ˆŠTú Oó|ŒŸ›`bk‹WFö qúêHžÜ ³ˆ8ûÉOßTSzMÇòxÈÒk¼j{x™2˜ô›qsݺu³fÍŠŒŒ‰D3gΜ7ož^o×QRRÒŠ+/^œŸŸïìì5vìØf–7oäÈ‘D$:wîŸ`cccŒfw š¾nÀuÚD¤ÔóòÁAn>ípòNdW§`_»Çn•jÖ‰H!/6Ô Û;ݳ¹íáe²`bÚãeææÒx6ÐÍß>áùÒgnöFËW¨Õ]óò\,,núû븞Õÿ˘÷l;ÌÓíÞÉ“'õšE„»2걉é¿Ä²ª”=áÄ{î†.+yqÝú··ý1ê™1¦‡QþFÓ¿ž7Ø:ÿ¬¯§ûû±u´4Þð§,´wje- EŽæn_t°<æ •õ°}Qs7¡M](jôì Žñú÷áÚZ"dÝÑm"«Ì""ûÎ-–ä´ë!Ë\ã•Ù!•uõêC‹}ɨý;_©ÜVU%b˜ì:à÷À”Ê Ž‘£—®WÁ¶_æ¯ø©ü¨8v¹¸ÁÅdüþ}¡®nvqq¥ZýŽ‹‹O³³Ê@óµwîüµC ¹3w[ŒÎ,ãO` |$<üÃÓHýûõ’"b‰ªÕêë Ef}½Ñ¿_uÀeÇ­W%½”•ò¦ª¾ªSï7E6|Zx“Wü„T~$hÿð4jÿþªªŠ{`Å0Bá ‡ííCô9Ï ˆ(ûDD,«RÖÔ–gÈ*o1Œ…Ïy…L5sËŒÏdã?!•;>ÍO£öoÓ߉ »{k÷@`aeeëçÙu²g×x‡.æm• ˜f¼â3¤rÇwìr±«Í¬Qbÿhw½RùÑñ ©ÜñùºÙÄþÃÓÜ­hYÏÎŽøxÕ‘oœžA8Ó ÚßG~ž]¤2_`6€y{{Û¹öVÕW›¬F¥¢B(r;æ“Õ„T0"ÿºÊJ¥Z­’ ,L±{¶¦ì†RQYPP`‚ºÀà°7xð`"º­l8½ŽQqÕEDD˜²R£²¶¶îÑ£˪¤¹LS£4çG"ŠŠŠ2Mu`XHehœH$"¢+ …)+åªóöö6e¥Æ–@Dy—ß­«¹mìºÊ OIsˆÅâ9sæ».0¤24nÀ€D´±¢BeªUD+*4Ut“&M7nœJ)»–YXX$&&.Z´ÈP+C*C“~ýõ×aƱ, &89 ´¶ö3Â}Ÿn+•gäòÄòò<¥’a˜Ã‡:ÔàµðÁ·ß~»yóæ'Nغôª.¹lÀ5ÛÙ;Èjkž~úé7b+¹]C*Cs>þ¸X*5^\ºtèðásçö‰Œ4^]ÀFíW×Ò ²;iééûxqêÔ¸Q£†1FEÆ€T†&]ºrå­+X–  œœZ[û ßan+•gäòÄòò<©ô­+V¯\Ù«—ÁkþÐô++[?¿s<ú‰ÄÞ\¿Z­¨*¾XqçtáÍ/7}ñEEEÅÔ)S ¸~£Âqeh\mmíú>bYvš½ý?¿‰vvƈd"ò 'ÚÙ]ðó›foϲìú>ª­­5FEÀš~åÑåùÞ#’ÝÇ6’‰H 9z èµ8$úS"f÷Þ½ݺeØ*Œ© ûaÿþb©´•U¢«« z‰€(ÑÕµ•U±TúÃþýỮëWv.}–cÜžåì3Ä+dšJ¥Úúå—F­À€Êиôôt"šçèhaª-ˆæ9:jªn…’ÒÒ%Ë–QII ÷ u†ÇÅ ‹Ó~`(_a»Ã}¸ÞÝf0Œ)z–o÷W‰(33S­V·XØPýG_èo  Ç•¡q¥eeDÔK$2e¥\u\Õ­°eÛ¶ðîݹ={ôÐ,禃FØofÈs°·ßµc‡ñªn§¸×Î%Ü4Õ ENV¶¾u²Â’’ww÷æ 7Õ8YÙÙ~ùåêÕ«wïÞ%"^£GŽ 4NÛþö(@*Cã²srˆÈHÇ’›ÂUÇUÝ —._މŽ&¢KW® 4¨ÕÍxgùò5‰‰DôŸ·ß~wíÚˈ}x¡µµ5 -ìŽR(eååž­jiûÃ}¸?–Ü ¡•K]M~ÑÝ»-¦rSý‡eÙÿþï;wïfY¶k—.111D”““s09ùÐáÃ/Lš4yÒ$½Nón𡣿6¤2tUUUÿݹsà€UUUßìØÑ¿_¿Ö­§èîÝ.]ºQqqq×.]Z,?wöì¦^úùÇ›ï˜ 7Æ$°°Ò±dSýgמ=ÿÛµËÛËkÉâÅÁ]»jÊßÌÌ|ïý÷wìÜ)²´œ8a‚îMj𡣿6W†E³•Ýê•üôË//NÊ=˜†‹j%÷ŸÂ;wþ»s§Í»«ViG2…†„¼»j•µõ7;vÜ)*ju¥èo  ÛÊÐq$®^ÝàAS4‡ßŽ8±cçÎÂ;w‚»vMxýuo//"zoÕ*GGG"zwÕ*'GǶ4©™ã|7oþë7´‹}³}»›››L.ß³w'ïYYYu ›ß-4´Á:¿ßµkí¤\¼Øâæè¨ÑþóË¡C*•*näÈF÷úzyzŽ1bÏ÷ßLNæ’µÑO\³°Ñý ´a[:Žˆž=#zöÔ~мCÉÉïø¡“““‹‹ËÍÌÌM[¶pËïŒm"›çæê:9>ž{<9>~r|¼X,–Éd¯¿ùæÎ]»:½<}ú¨áÃ322ÞX²$=#£ÁÛ·lß~ùêU]vx‚Ží?©—/Ñ€þý›z÷ҥ˗u©¢Ñý ´a[]_~óÍÚ5kÂ{ôÈÍË›9gεë×[·žWfÍj°ÄÖÖvúuÍ¿ËÍÍmJ|üŽ;‰hÊýár{RRVVÖ„qã^ž>[Ò'2rɲe_~ýõÚ5k´ßžzéÒç7zyyµ®Í #nŽn?¿¦ Q¾nSy7ú¡ë ý­cC*C[ݬ¯RP `Ù-îîcmm¼šY_?´  @(<âãcóéˆÿïå—Ã{ô "___"’Éå­[ÏíüüKZuS–e=JD£FŒÐ,ì!‹¯ß¸!—˹ól9ófÏÆiuuuDdccÓTkk"’Éd&kú[džT†¶ µ´\æì¼¬´tqIÉkk/‹³CÔ±ì+ÅÅj¢/ÜÝùÉD4äþÕ/B‹6Íha¨3ZËËËË+*ˆh{Riýw©T*–eKJJ¸_œ¨>} R)?É*o]?tSþ-èoü‡TCr·°˜ãà°²¬Œˆ›ð¬ÔökÖÿý_UUÕÅÔTy]ݘѣ†™7{vTïÞ?>Özžçìž“C˜=ßø¸Ï·u_ÿ¶÷«Ç&êw íÂŒmyW×QøÐݶ.-ÏÚ¦-íØ?«Š/¾ÿî»áÝœ ®-ý 88æÃÍ‘J‹Tªmîî¾Baf}ýªÖÞ)@£¾®´0ó+îñ­”%jU+'{hÊ`0[*+•Éæ::ÆÙÚ~âæÆm®¬<ÕÚ ³ˆˆˆÍJYR//°^$ö’UÞ’\[oî&R ãªBñŸ²²H+«7œˆ(ÚÚz–ƒÍ•J+Õjs·Ú«;™ß”žôîö²‹l—~ï1w2¿®¼{ÎÜí0¤2@ZýJq±ˆa¶¸»‹îH^êì&å+•KJKÍÛ9x<æ:ˆn¥,QÕW™¹qÆTH(-ͪ¯ßÅ%Pøà¬~+†ùÜÍÍ’avWWÿT[kÆæA{¤RÖþuv¡@ êÚ#¸7û£_ø|Ç`EíœÔUæm€‘ •¡­¾«©ÙU]ý¼Ýs]JÑC$ZâäDD‹¤Ò»˜”ô‘“ºR^µÜÚ.@³P`aÕõ±µŒ@(ÍÝ_zû°›`$Heh« ¶¶ÅŸ41áÀ\GÇâÀÀ›m»/˲K/æÿÐÜ¥KZzº4çGÓ¤²4÷˪‚D"‘^oD¿j_ýª#A*Cã,…B"º¢P˜2•¯(Dä¢ÏÎÆÚÚZ"²¶¶6R“æÎž­ý”eÙï~øa{RÒw?ü`ÊÑ“ˆž‹;{þüµë×7lܸrùræþ̦[¿ü2;'gάY nôËOq£F:rDš{À5`´“wÃ3꫹wù]"š8a‚¾ïE¿j_ýª#Áqeh\XXm¬¨0ÙŒ\*¢šªõÂèyçVcfÔˆD”——gšµ«^´`ÍÅÔÔƒÉÉܳçÏøùçÇ à¶½øÏÇÇçÅ©S‰èæé™¹—•uƹ×'«–渖`ÀÃûfu„~Õ^úUG‚mehÜØ¸¸äÇS¥Ò„’’µ®®Æþù¦&J()I­«swsûз¦hÑ ‹³‹¿ûö["’Éå;vî¾[h¨îtl’§‡ÇÌW^Y¿qãÛ·Göîm)®ß¸ÑÃÝ}Áܹ&˶3z´J¥Ú–”t'3éNf’•­¯¥µ›f¦ë¶DEg‰X"ŠèÙsÁܹú®ýª=ö«© ‹Åÿš?ÿßo¿ýUUÕ1™,ÁÉi µµ1öfßV*ÏÈå‰ååyJ%Ã0ÿš?_,ëøÞÉññ;vîäˆ,-‰H©Tþûí·Ó32z†‡މɏyó»ï¿OKKK|÷]áß§üܲ}ûå«W»véb¡çT çRRˆÈßߟ{*“É^_²$+++zàÀ‘Ç———ÿrèÐK–¬]³&¬[7] èÕ¤§Ÿzê̹sçSRÖ­_/jjjV¼õ–ÝC3óܸgŸí߯ßg[¶\º|Ù‚-¯.É7àÊí\{3 õ ï9"6¶u[ÉèWí´_u HehRd¯^«V¬ØðñÇyRékR£O8ìîæ¶`îÜÈ^½tË”û£ç”øxnÉÁääôŒŒ'|ÉâŠð,»fíÚÓ¿ÿž|øðÈáõߛzéÒç7zyyé^B¡8uúôg[¶ÑÓC†p wîÚ•••5aܸ—§Oç–ô‰Œ\²lÙ—_½vÍ] èÕ$†aæÏ™3sΜ´ôt"š:yrwýwøóϪ+X–Í“Hªª y[F;;»NmÙÈC¿j¿ýª@*CsúDFnÛ¼yÏÞ½iéé…EE¯ÂÇÇÇÛÓ³{XØsãÇ[Z¶u7æñ“'‰èÙ¸8nPfæÙÑ£Oÿþûñ“'ŒžófÏÖeè|eÖ,îA}}}II‰R¥"¢ýû9’ˆX–=rô(q9½""Äbñõ7är¹••Uó´wêØ$g'§ ãÆmOJ"¢¨>}Z,Ïg Ãt h¹œ¹¡_É •¡–––/LšdîVè*;'‡ˆ´žq³³³”Ôqܹoç*Ã0NŽŽ]»v:xðÑÑÜè\^^^^QADÛ“’HkãL¥R±,[RR"‹›/àëë«o“***~Ü·{¼nÆOÖ¯×÷²Ðú˜ R:™LFD666š%ÜFC­Lֺܿ¿™WëêêˆH ”•—k/ &"¡¥e‹ôm˲|ôQiYÙÒ„„/¶m“H$_~ýõ«3fè»Ð ú˜ R:™L&—Ë5(wá©Xk<5 "bYvåÛo7zm+W{3ôµïÀ />7nÜ?îàà°ä­·~Ü¿¿¿~½""Ú¾rh ú˜ ®W†…›,Wë¢Ï¬œ" 2Fub±8(0eÙ‹©©­+ —¿nÝÚöå—!ÁÁS§L!¢^={Ž3†ˆ>ذ¡¦¶¶í뇦 _É •¡CCDûú‰eY"bY–;TÖêy$Z4vÌ"Ú¼ukþßO…SªT*•J—:’Éåï½ÿ¾¥¥å›o¼!¼‰ÚÔ)S;u*–J?ß¼¹4ý L{°¡C‰6ì·ãÇ8QQQܵëôôë7n„uë;l˜‘j:dHZFÆ¡ääYsçöëÛ×ÇÇG­RÝ.(¸~ãÆ¦?vssk±€Ž}ºiS~AÁ zkO+‰ÞX¸pþÂ…GëÿØcÑM1¹ô#ýÊ8%4© ŠP(\ýŸÿ|½cÇÉS§.]¹âêê:~ìØÉññB£ÍæÍ0̼ٳ£z÷þéàÁKW®ü~ö¬¯ÏSƒÛÚÙéR@ÇŽ?úÛoO 2ä¡I’;Mýç?·'%}üé§=œõ¼e!èý ýÊdn‡ tHÜUÍŸí &n.ÆÖ}ýѯ )méWÀÁqe¾@*ðR€/Ê|Tà ¤2_ •ø© ÀHe¾@*ðfÜìȸ™šÒ–7š‚Xi l+ðÅÿé #„)€IEND®B`‚quagga-0.99.24.1/doc/defines.texi0000644000175000017500000000077312476521315013316 00000000000000@c -*- texinfo -*- @c doc/defines.texi. Generated from defines.texi.in by configure. @c Set variables @set PACKAGE_NAME Quagga @set PACKAGE_TARNAME quagga @set PACKAGE_STRING Quagga 0.99.24.1 @set AUTHORS Kunihiro Ishiguro, et al. @set COPYRIGHT_YEAR 1999-2005 @set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS} @c These may vary with installation environment. @set INSTALL_PREFIX_ETC /etc/quagga @set INSTALL_PREFIX_SBIN /usr/sbin @set INSTALL_PREFIX_STATE /var/run/quagga quagga-0.99.24.1/doc/routeserver.texi0000644000175000017500000005166112476520570014272 00000000000000@c -*-texinfo-*- @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @c @c This file is a modified version of Jose Luis Rubio's TeX sources @c of his RS-Manual document @node Configuring Quagga as a Route Server @chapter Configuring Quagga as a Route Server The purpose of a Route Server is to centralize the peerings between BGP speakers. For example if we have an exchange point scenario with four BGP speakers, each of which maintaining a BGP peering with the other three (@pxref{fig:full-mesh}), we can convert it into a centralized scenario where each of the four establishes a single BGP peering against the Route Server (@pxref{fig:route-server}). We will first describe briefly the Route Server model implemented by Quagga. We will explain the commands that have been added for configuring that model. And finally we will show a full example of Quagga configured as Route Server. @menu * Description of the Route Server model:: * Commands for configuring a Route Server:: * Example of Route Server Configuration:: @end menu @node Description of the Route Server model @section Description of the Route Server model First we are going to describe the normal processing that BGP announcements suffer inside a standard BGP speaker, as shown in @ref{fig:normal-processing}, it consists of three steps: @itemize @bullet @item When an announcement is received from some peer, the `In' filters configured for that peer are applied to the announcement. These filters can reject the announcement, accept it unmodified, or accept it with some of its attributes modified. @item The announcements that pass the `In' filters go into the Best Path Selection process, where they are compared to other announcements referred to the same destination that have been received from different peers (in case such other announcements exist). For each different destination, the announcement which is selected as the best is inserted into the BGP speaker's Loc-RIB. @item The routes which are inserted in the Loc-RIB are considered for announcement to all the peers (except the one from which the route came). This is done by passing the routes in the Loc-RIB through the `Out' filters corresponding to each peer. These filters can reject the route, accept it unmodified, or accept it with some of its attributes modified. Those routes which are accepted by the `Out' filters of a peer are announced to that peer. @end itemize @float Figure,fig:normal-processing @image{fig-normal-processing,400pt,,Normal announcement processing} @caption{Announcement processing inside a ``normal'' BGP speaker} @end float @float Figure,fig:full-mesh @image{fig_topologies_full,120pt,,Full Mesh BGP Topology} @caption{Full Mesh} @end float @float Figure,fig:route-server @image{fig_topologies_rs,120pt,,Route Server BGP Topology} @caption{Route Server and clients} @end float Of course we want that the routing tables obtained in each of the routers are the same when using the route server than when not. But as a consequence of having a single BGP peering (against the route server), the BGP speakers can no longer distinguish from/to which peer each announce comes/goes. @anchor{filter-delegation}This means that the routers connected to the route server are not able to apply by themselves the same input/output filters as in the full mesh scenario, so they have to delegate those functions to the route server. Even more, the ``best path'' selection must be also performed inside the route server on behalf of its clients. The reason is that if, after applying the filters of the announcer and the (potential) receiver, the route server decides to send to some client two or more different announcements referred to the same destination, the client will only retain the last one, considering it as an implicit withdrawal of the previous announcements for the same destination. This is the expected behavior of a BGP speaker as defined in @cite{RFC1771}, and even though there are some proposals of mechanisms that permit multiple paths for the same destination to be sent through a single BGP peering, none are currently supported by most existing BGP implementations. As a consequence a route server must maintain additional information and perform additional tasks for a RS-client that those necessary for common BGP peerings. Essentially a route server must: @anchor{Route Server tasks} @itemize @bullet @item Maintain a separated Routing Information Base (Loc-RIB) for each peer configured as RS-client, containing the routes selected as a result of the ``Best Path Selection'' process that is performed on behalf of that RS-client. @item Whenever it receives an announcement from a RS-client, it must consider it for the Loc-RIBs of the other RS-clients. @anchor{Route-server path filter process} @itemize @bullet @item This means that for each of them the route server must pass the announcement through the appropriate `Out' filter of the announcer. @item Then through the appropriate `In' filter of the potential receiver. @item Only if the announcement is accepted by both filters it will be passed to the ``Best Path Selection'' process. @item Finally, it might go into the Loc-RIB of the receiver. @end itemize @end itemize When we talk about the ``appropriate'' filter, both the announcer and the receiver of the route must be taken into account. Suppose that the route server receives an announcement from client A, and the route server is considering it for the Loc-RIB of client B. The filters that should be applied are the same that would be used in the full mesh scenario, i.e., first the `Out' filter of router A for announcements going to router B, and then the `In' filter of router B for announcements coming from router A. We call ``Export Policy'' of a RS-client to the set of `Out' filters that the client would use if there was no route server. The same applies for the ``Import Policy'' of a RS-client and the set of `In' filters of the client if there was no route server. It is also common to demand from a route server that it does not modify some BGP attributes (next-hop, as-path and MED) that are usually modified by standard BGP speakers before announcing a route. The announcement processing model implemented by Quagga is shown in @ref{fig:rs-processing}. The figure shows a mixture of RS-clients (B, C and D) with normal BGP peers (A). There are some details that worth additional comments: @itemize @bullet @item Announcements coming from a normal BGP peer are also considered for the Loc-RIBs of all the RS-clients. But logically they do not pass through any export policy. @item Those peers that are configured as RS-clients do not receive any announce from the `Main' Loc-RIB. @item Apart from import and export policies, `In' and `Out' filters can also be set for RS-clients. `In' filters might be useful when the route server has also normal BGP peers. On the other hand, `Out' filters for RS-clients are probably unnecessary, but we decided not to remove them as they do not hurt anybody (they can always be left empty). @end itemize @float Figure,fig:rs-processing @image{fig-rs-processing,450pt,,Route Server Processing Model} @caption{Announcement processing model implemented by the Route Server} @end float @node Commands for configuring a Route Server @section Commands for configuring a Route Server Now we will describe the commands that have been added to quagga in order to support the route server features. @deffn {Route-Server} {neighbor @var{peer-group} route-server-client} {} @deffnx {Route-Server} {neighbor @var{A.B.C.D} route-server-client} {} @deffnx {Route-Server} {neighbor @var{X:X::X:X} route-server-client} {} This command configures the peer given by @var{peer}, @var{A.B.C.D} or @var{X:X::X:X} as an RS-client. Actually this command is not new, it already existed in standard Quagga. It enables the transparent mode for the specified peer. This means that some BGP attributes (as-path, next-hop and MED) of the routes announced to that peer are not modified. With the route server patch, this command, apart from setting the transparent mode, creates a new Loc-RIB dedicated to the specified peer (those named `Loc-RIB for X' in @ref{fig:rs-processing}.). Starting from that moment, every announcement received by the route server will be also considered for the new Loc-RIB. @end deffn @deffn {Route-Server} {neigbor @{A.B.C.D|X.X::X.X|peer-group@} route-map WORD @{import|export@}} {} This set of commands can be used to specify the route-map that represents the Import or Export policy of a peer which is configured as a RS-client (with the previous command). @end deffn @deffn {Route-Server} {match peer @{A.B.C.D|X:X::X:X@}} {} This is a new @emph{match} statement for use in route-maps, enabling them to describe import/export policies. As we said before, an import/export policy represents a set of input/output filters of the RS-client. This statement makes possible that a single route-map represents the full set of filters that a BGP speaker would use for its different peers in a non-RS scenario. The @emph{match peer} statement has different semantics whether it is used inside an import or an export route-map. In the first case the statement matches if the address of the peer who sends the announce is the same that the address specified by @{A.B.C.D|X:X::X:X@}. For export route-maps it matches when @{A.B.C.D|X:X::X:X@} is the address of the RS-Client into whose Loc-RIB the announce is going to be inserted (how the same export policy is applied before different Loc-RIBs is shown in @ref{fig:rs-processing}.). @end deffn @deffn {Route-map Command} {call @var{WORD}} {} This command (also used inside a route-map) jumps into a different route-map, whose name is specified by @var{WORD}. When the called route-map finishes, depending on its result the original route-map continues or not. Apart from being useful for making import/export route-maps easier to write, this command can also be used inside any normal (in or out) route-map. @end deffn @node Example of Route Server Configuration @section Example of Route Server Configuration Finally we are going to show how to configure a Quagga daemon to act as a Route Server. For this purpose we are going to present a scenario without route server, and then we will show how to use the configurations of the BGP routers to generate the configuration of the route server. All the configuration files shown in this section have been taken from scenarios which were tested using the VNUML tool @uref{http://www.dit.upm.es/vnuml,VNUML}. @menu * Configuration of the BGP routers without Route Server:: * Configuration of the BGP routers with Route Server:: * Configuration of the Route Server itself:: * Further considerations about Import and Export route-maps:: @end menu @node Configuration of the BGP routers without Route Server @subsection Configuration of the BGP routers without Route Server We will suppose that our initial scenario is an exchange point with three BGP capable routers, named RA, RB and RC. Each of the BGP speakers generates some routes (with the @var{network} command), and establishes BGP peerings against the other two routers. These peerings have In and Out route-maps configured, named like ``PEER-X-IN'' or ``PEER-X-OUT''. For example the configuration file for router RA could be the following: @exampleindent 0 @example #Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::B route-map PEER-B-IN in neighbor 2001:0DB8::B route-map PEER-B-OUT out neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C soft-reconfiguration inbound neighbor 2001:0DB8::C route-map PEER-C-IN in neighbor 2001:0DB8::C route-map PEER-C-OUT out exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map PEER-C-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map PEER-C-IN permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map PEER-B-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! route-map PEER-C-OUT permit 10 match ipv6 address prefix-list PEER-A-PREFIXES ! line vty ! @end example @node Configuration of the BGP routers with Route Server @subsection Configuration of the BGP routers with Route Server To convert the initial scenario into one with route server, first we must modify the configuration of routers RA, RB and RC. Now they must not peer between them, but only with the route server. For example, RA's configuration would turn into: @example # Configuration for router 'RA' ! hostname RA password **** ! router bgp 65001 no bgp default ipv4-unicast neighbor 2001:0DB8::FFFF remote-as 65000 ! address-family ipv6 network 2001:0DB8:AAAA:1::/64 network 2001:0DB8:AAAA:2::/64 network 2001:0DB8:0000:1::/64 network 2001:0DB8:0000:2::/64 neighbor 2001:0DB8::FFFF activate neighbor 2001:0DB8::FFFF soft-reconfiguration inbound exit-address-family ! line vty ! @end example Which is logically much simpler than its initial configuration, as it now maintains only one BGP peering and all the filters (route-maps) have disappeared. @node Configuration of the Route Server itself @subsection Configuration of the Route Server itself As we said when we described the functions of a route server (@pxref{Description of the Route Server model}), it is in charge of all the route filtering. To achieve that, the In and Out filters from the RA, RB and RC configurations must be converted into Import and Export policies in the route server. This is a fragment of the route server configuration (we only show the policies for client RA): @example # Configuration for Route Server ('RS') ! hostname RS password ix ! bgp multiple-instance ! router bgp 65000 view RS no bgp default ipv4-unicast neighbor 2001:0DB8::A remote-as 65001 neighbor 2001:0DB8::B remote-as 65002 neighbor 2001:0DB8::C remote-as 65003 ! address-family ipv6 neighbor 2001:0DB8::A activate neighbor 2001:0DB8::A route-server-client neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import neighbor 2001:0DB8::A route-map RSCLIENT-A-EXPORT export neighbor 2001:0DB8::A soft-reconfiguration inbound neighbor 2001:0DB8::B activate neighbor 2001:0DB8::B route-server-client neighbor 2001:0DB8::B route-map RSCLIENT-B-IMPORT import neighbor 2001:0DB8::B route-map RSCLIENT-B-EXPORT export neighbor 2001:0DB8::B soft-reconfiguration inbound neighbor 2001:0DB8::C activate neighbor 2001:0DB8::C route-server-client neighbor 2001:0DB8::C route-map RSCLIENT-C-IMPORT import neighbor 2001:0DB8::C route-map RSCLIENT-C-EXPORT export neighbor 2001:0DB8::C soft-reconfiguration inbound exit-address-family ! ipv6 prefix-list COMMON-PREFIXES seq 5 permit 2001:0DB8:0000::/48 ge 64 le 64 ipv6 prefix-list COMMON-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-A-PREFIXES seq 5 permit 2001:0DB8:AAAA::/48 ge 64 le 64 ipv6 prefix-list PEER-A-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-B-PREFIXES seq 5 permit 2001:0DB8:BBBB::/48 ge 64 le 64 ipv6 prefix-list PEER-B-PREFIXES seq 10 deny any ! ipv6 prefix-list PEER-C-PREFIXES seq 5 permit 2001:0DB8:CCCC::/48 ge 64 le 64 ipv6 prefix-list PEER-C-PREFIXES seq 10 deny any ! route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B route-map RSCLIENT-A-IMPORT permit 20 match peer 2001:0DB8::C call A-IMPORT-FROM-C ! route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! route-map A-IMPORT-FROM-C permit 10 match ipv6 address prefix-list COMMON-PREFIXES set metric 200 route-map A-IMPORT-FROM-C permit 20 match ipv6 address prefix-list PEER-C-PREFIXES set community 65001:22222 ! route-map RSCLIENT-A-EXPORT permit 10 match peer 2001:0DB8::B match ipv6 address prefix-list PEER-A-PREFIXES route-map RSCLIENT-A-EXPORT permit 20 match peer 2001:0DB8::C match ipv6 address prefix-list PEER-A-PREFIXES ! ... ... ... @end example If you compare the initial configuration of RA with the route server configuration above, you can see how easy it is to generate the Import and Export policies for RA from the In and Out route-maps of RA's original configuration. When there was no route server, RA maintained two peerings, one with RB and another with RC. Each of this peerings had an In route-map configured. To build the Import route-map for client RA in the route server, simply add route-map entries following this scheme: @example route-map permit 10 match peer call route-map permit 20 match peer call @end example This is exactly the process that has been followed to generate the route-map RSCLIENT-A-IMPORT. The route-maps that are called inside it (A-IMPORT-FROM-B and A-IMPORT-FROM-C) are exactly the same than the In route-maps from the original configuration of RA (PEER-B-IN and PEER-C-IN), only the name is different. The same could have been done to create the Export policy for RA (route-map RSCLIENT-A-EXPORT), but in this case the original Out route-maps where so simple that we decided not to use the @var{call WORD} commands, and we integrated all in a single route-map (RSCLIENT-A-EXPORT). The Import and Export policies for RB and RC are not shown, but the process would be identical. @node Further considerations about Import and Export route-maps @subsection Further considerations about Import and Export route-maps The current version of the route server patch only allows to specify a route-map for import and export policies, while in a standard BGP speaker apart from route-maps there are other tools for performing input and output filtering (access-lists, community-lists, ...). But this does not represent any limitation, as all kinds of filters can be included in import/export route-maps. For example suppose that in the non-route-server scenario peer RA had the following filters configured for input from peer B: @example neighbor 2001:0DB8::B prefix-list LIST-1 in neighbor 2001:0DB8::B filter-list LIST-2 in neighbor 2001:0DB8::B route-map PEER-B-IN in ... ... route-map PEER-B-IN permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map PEER-B-IN permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 @end example It is posible to write a single route-map which is equivalent to the three filters (the community-list, the prefix-list and the route-map). That route-map can then be used inside the Import policy in the route server. Lets see how to do it: @example neighbor 2001:0DB8::A route-map RSCLIENT-A-IMPORT import ... ! ... route-map RSCLIENT-A-IMPORT permit 10 match peer 2001:0DB8::B call A-IMPORT-FROM-B ... ... ! route-map A-IMPORT-FROM-B permit 1 match ipv6 address prefix-list LIST-1 match as-path LIST-2 on-match goto 10 route-map A-IMPORT-FROM-B deny 2 route-map A-IMPORT-FROM-B permit 10 match ipv6 address prefix-list COMMON-PREFIXES set local-preference 100 route-map A-IMPORT-FROM-B permit 20 match ipv6 address prefix-list PEER-B-PREFIXES set community 65001:11111 ! ... ... @end example The route-map A-IMPORT-FROM-B is equivalent to the three filters (LIST-1, LIST-2 and PEER-B-IN). The first entry of route-map A-IMPORT-FROM-B (sequence number 1) matches if and only if both the prefix-list LIST-1 and the filter-list LIST-2 match. If that happens, due to the ``on-match goto 10'' statement the next route-map entry to be processed will be number 10, and as of that point route-map A-IMPORT-FROM-B is identical to PEER-B-IN. If the first entry does not match, `on-match goto 10'' will be ignored and the next processed entry will be number 2, which will deny the route. Thus, the result is the same that with the three original filters, i.e., if either LIST-1 or LIST-2 rejects the route, it does not reach the route-map PEER-B-IN. In case both LIST-1 and LIST-2 accept the route, it passes to PEER-B-IN, which can reject, accept or modify the route. quagga-0.99.24.1/doc/vtysh.texi0000644000175000017500000000455612476520570013063 00000000000000@node VTY shell @chapter VTY shell @command{vtysh} is integrated shell of Quagga software. To use vtysh please specify ---enable-vtysh to configure script. To use PAM for authentication use ---with-libpam option to configure script. vtysh only searches @value{INSTALL_PREFIX_ETC} path for vtysh.conf which is the vtysh configuration file. Vtysh does not search current directory for configuration file because the file includes user authentication settings. Currently, vtysh.conf has only two commands. @menu * VTY shell username:: * VTY shell integrated configuration:: @end menu @node VTY shell username @section VTY shell username @deffn {Command} {username @var{username} nopassword} {} With this set, user foo does not need password authentication for user vtysh. With PAM vtysh uses PAM authentication mechanism. If vtysh is compiled without PAM authentication, every user can use vtysh without authentication. vtysh requires read/write permission to the various daemons vty sockets, this can be accomplished through use of unix groups and the --enable-vty-group configure option. @end deffn @node VTY shell integrated configuration @section VTY shell integrated configuration @deffn {Command} {service integrated-vtysh-config} {} Write out integrated Quagga.conf file when 'write file' is issued. This command controls the behaviour of vtysh when it is told to write out the configuration. Per default, vtysh will instruct each daemon to write out their own config files when @command{write file} is issued. However, if @command{service integrated-vtysh-config} is set, when @command{write file} is issued, vtysh will instruct the daemons will write out a Quagga.conf with all daemons' commands integrated into it. Vtysh per default behaves as if @command{write-conf daemon} is set. Note that both may be set at same time if one wishes to have both Quagga.conf and daemon specific files written out. Further, note that the daemons are hard-coded to first look for the integrated Quagga.conf file before looking for their own file. We recommend you do not mix the use of the two types of files. Further, it is better not to use the integrated Quagga.conf file, as any syntax error in it can lead to /all/ of your daemons being unable to start up. Per daemon files are more robust as impact of errors in configuration are limited to the daemon in whose file the error is made. @end deffn quagga-0.99.24.1/doc/snmp.texi0000644000175000017500000001443412476520570012657 00000000000000@node SNMP Support @chapter SNMP Support @acronym{SNMP,Simple Network Managing Protocol} is a widely implemented feature for collecting network information from router and/or host. Quagga itself does not support SNMP agent (server daemon) functionality but is able to connect to a SNMP agent using the SMUX protocol (@cite{RFC1227}) or the AgentX protocol (@cite{RFC2741}) and make the routing protocol MIBs available through it. @menu * Getting and installing an SNMP agent:: * AgentX configuration:: * SMUX configuration:: * MIB and command reference:: * Handling SNMP Traps:: @end menu @node Getting and installing an SNMP agent @section Getting and installing an SNMP agent There are several SNMP agent which support SMUX or AgentX. We recommend to use the latest version of @code{net-snmp} which was formerly known as @code{ucd-snmp}. It is free and open software and available at @uref{http://www.net-snmp.org/} and as binary package for most Linux distributions. @code{net-snmp} has to be compiled with @code{--with-mib-modules=agentx} to be able to accept connections from Quagga using AgentX protocol or with @code{--with-mib-modules=smux} to use SMUX protocol. Nowadays, SMUX is a legacy protocol. The AgentX protocol should be preferred for any new deployment. Both protocols have the same coverage. @node AgentX configuration @section AgentX configuration To enable AgentX protocol support, Quagga must have been build with the @code{--enable-snmp} or @code{--enable-snmp=agentx} option. Both the master SNMP agent (snmpd) and each of the Quagga daemons must be configured. In @code{/etc/snmp/snmpd.conf}, @code{master agentx} directive should be added. In each of the Quagga daemons, @code{agentx} command will enable AgentX support. @example /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # enable master agent for AgentX subagents # master agentx /etc/quagga/ospfd.conf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! agentx ! @end example Upon successful connection, you should get something like this in the log of each Quagga daemons: @example 2012/05/25 11:39:08 ZEBRA: snmp[info]: NET-SNMP version 5.4.3 AgentX subagent connected @end example Then, you can use the following command to check everything works as expected: @example # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 [...] @end example The AgentX protocol can be transported over a Unix socket or using TCP or UDP. It usually defaults to a Unix socket and depends on how NetSNMP was built. If need to configure Quagga to use another transport, you can configure it through @code{/etc/snmp/quagga.conf}: @example /etc/snmp/quagga.conf: [snmpd] # Use a remote master agent agentXSocket tcp:192.168.15.12:705 @end example @node SMUX configuration @section SMUX configuration To enable SMUX protocol support, Quagga must have been build with the @code{--enable-snmp=smux} option. A separate connection has then to be established between the SNMP agent (snmpd) and each of the Quagga daemons. This connections each use different OID numbers and passwords. Be aware that this OID number is not the one that is used in queries by clients, it is solely used for the intercommunication of the daemons. In the following example the ospfd daemon will be connected to the snmpd daemon using the password "quagga_ospfd". For testing it is recommending to take exactly the below snmpd.conf as wrong access restrictions can be hard to debug. @example /etc/snmp/snmpd.conf: # # example access restrictions setup # com2sec readonly default public group MyROGroup v1 readonly view all included .1 80 access MyROGroup "" any noauth exact all none none # # the following line is relevant for Quagga # smuxpeer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd /etc/quagga/ospf: ! ... the rest of ospfd.conf has been omitted for clarity ... ! smux peer .1.3.6.1.4.1.3317.1.2.5 quagga_ospfd ! @end example After restarting snmpd and quagga, a successful connection can be verified in the syslog and by querying the SNMP daemon: @example snmpd[12300]: [smux_accept] accepted fd 12 from 127.0.0.1:36255 snmpd[12300]: accepted smux peer: \ oid GNOME-PRODUCT-ZEBRA-MIB::ospfd, quagga-0.96.5 # snmpwalk -c public -v1 localhost .1.3.6.1.2.1.14.1.1 OSPF-MIB::ospfRouterId.0 = IpAddress: 192.168.42.109 @end example Be warned that the current version (5.1.1) of the Net-SNMP daemon writes a line for every SNMP connect to the syslog which can lead to enormous log file sizes. If that is a problem you should consider to patch snmpd and comment out the troublesome @code{snmp_log()} line in the function @code{netsnmp_agent_check_packet()} in @code{agent/snmp_agent.c}. @node MIB and command reference @section MIB and command reference The following OID numbers are used for the interprocess communication of snmpd and the Quagga daemons with SMUX only. @example (OIDs below .iso.org.dod.internet.private.enterprises) zebra .1.3.6.1.4.1.3317.1.2.1 .gnome.gnomeProducts.zebra.zserv bgpd .1.3.6.1.4.1.3317.1.2.2 .gnome.gnomeProducts.zebra.bgpd ripd .1.3.6.1.4.1.3317.1.2.3 .gnome.gnomeProducts.zebra.ripd ospfd .1.3.6.1.4.1.3317.1.2.5 .gnome.gnomeProducts.zebra.ospfd ospf6d .1.3.6.1.4.1.3317.1.2.6 .gnome.gnomeProducts.zebra.ospf6d @end example Sadly, SNMP has not been implemented in all daemons yet. The following OID numbers are used for querying the SNMP daemon by a client: @example zebra .1.3.6.1.2.1.4.24 .iso.org.dot.internet.mgmt.mib-2.ip.ipForward ospfd .1.3.6.1.2.1.14 .iso.org.dot.internet.mgmt.mib-2.ospf bgpd .1.3.6.1.2.1.15 .iso.org.dot.internet.mgmt.mib-2.bgp ripd .1.3.6.1.2.1.23 .iso.org.dot.internet.mgmt.mib-2.rip2 ospf6d .1.3.6.1.3.102 .iso.org.dod.internet.experimental.ospfv3 @end example The following syntax is understood by the Quagga daemons for configuring SNMP using SMUX: @deffn {Command} {smux peer @var{oid}} {} @deffnx {Command} {no smux peer @var{oid}} {} @end deffn @deffn {Command} {smux peer @var{oid} @var{password}} {} @deffnx {Command} {no smux peer @var{oid} @var{password}} {} @end deffn Here is the syntax for using AgentX: @deffn {Command} {agentx} {} @deffnx {Command} {no agentx} {} @end deffn @include snmptrap.texi quagga-0.99.24.1/doc/routemap.texi0000644000175000017500000001461712476520570013541 00000000000000@node Route Map @chapter Route Map Route maps provide a means to both filter and/or apply actions to route, hence allowing policy to be applied to routes. @menu * Route Map Command:: * Route Map Match Command:: * Route Map Set Command:: * Route Map Call Command:: * Route Map Exit Action Command:: * Route Map Examples:: @end menu Route-maps are an ordered list of route-map entries. Each entry may specify up to four distincts sets of clauses: @table @samp @item Matching Policy This specifies the policy implied if the @samp{Matching Conditions} are met or not met, and which actions of the route-map are to be taken, if any. The two possibilities are: @itemize @minus @item @samp{permit}: If the entry matches, then carry out the @samp{Set Actions}. Then finish processing the route-map, permitting the route, unless an @samp{Exit Action} indicates otherwise. @item @samp{deny}: If the entry matches, then finish processing the route-map and deny the route (return @samp{deny}). @end itemize The @samp{Matching Policy} is specified as part of the command which defines the ordered entry in the route-map. See below. @item Matching Conditions A route-map entry may, optionally, specify one or more conditions which must be matched if the entry is to be considered further, as governed by the Match Policy. If a route-map entry does not explicitely specify any matching conditions, then it always matches. @item Set Actions A route-map entry may, optionally, specify one or more @samp{Set Actions} to set or modify attributes of the route. @item Call Action Call to another route-map, after any @samp{Set Actions} have been carried out. If the route-map called returns @samp{deny} then processing of the route-map finishes and the route is denied, regardless of the @samp{Matching Policy} or the @samp{Exit Policy}. If the called route-map returns @samp{permit}, then @samp{Matching Policy} and @samp{Exit Policy} govern further behaviour, as normal. @item Exit Policy An entry may, optionally, specify an alternative @samp{Exit Policy} to take if the entry matched, rather than the normal policy of exiting the route-map and permitting the route. The two possibilities are: @itemize @minus @item @samp{next}: Continue on with processing of the route-map entries. @item @samp{goto N}: Jump ahead to the first route-map entry whose order in the route-map is >= N. Jumping to a previous entry is not permitted. @end itemize @end table The default action of a route-map, if no entries match, is to deny. I.e. a route-map essentially has as its last entry an empty @samp{deny} entry, which matches all routes. To change this behaviour, one must specify an empty @samp{permit} entry as the last entry in the route-map. To summarise the above: @multitable {permit} {action} {No Match} @headitem @tab Match @tab No Match @item @emph{Permit} @tab action @tab cont @item @emph{Deny} @tab deny @tab cont @end multitable @table @samp @item action @itemize @minus @item Apply @emph{set} statements @item If @emph{call} is present, call given route-map. If that returns a @samp{deny}, finish processing and return @samp{deny}. @item If @samp{Exit Policy} is @emph{next}, goto next route-map entry @item If @samp{Exit Policy} is @emph{goto}, goto first entry whose order in the list is >= the given order. @item Finish processing the route-map and permit the route. @end itemize @item deny @itemize @minus @item The route is denied by the route-map (return @samp{deny}). @end itemize @item cont @itemize @minus @item goto next route-map entry @end itemize @end table @node Route Map Command @section Route Map Command @deffn {Command} {route-map @var{route-map-name} (permit|deny) @var{order}} {} Configure the @var{order}'th entry in @var{route-map-name} with @samp{Match Policy} of either @emph{permit} or @emph{deny}. @end deffn @node Route Map Match Command @section Route Map Match Command @deffn {Route-map Command} {match ip address @var{access_list}} {} Matches the specified @var{access_list} @end deffn @deffn {Route-map Command} {match ip next-hop @var{ipv4_addr}} {} Matches the specified @var{ipv4_addr}. @end deffn @deffn {Route-map Command} {match aspath @var{as_path}} {} Matches the specified @var{as_path}. @end deffn @deffn {Route-map Command} {match metric @var{metric}} {} Matches the specified @var{metric}. @end deffn @deffn {Route-map Command} {match community @var{community_list}} {} Matches the specified @var{community_list} @end deffn @node Route Map Set Command @section Route Map Set Command @deffn {Route-map Command} {set ip next-hop @var{ipv4_address}} {} Set the BGP nexthop address. @end deffn @deffn {Route-map Command} {set local-preference @var{local_pref}} {} Set the BGP local preference. @end deffn @deffn {Route-map Command} {set weight @var{weight}} {} Set the route's weight. @end deffn @deffn {Route-map Command} {set metric @var{metric}} {} Set the BGP attribute MED. @end deffn @deffn {Route-map Command} {set as-path prepend @var{as_path}} {} Set the BGP AS path to prepend. @end deffn @deffn {Route-map Command} {set community @var{community}} {} Set the BGP community attribute. @end deffn @deffn {Route-map Command} {set ipv6 next-hop global @var{ipv6_address}} {} Set the BGP-4+ global IPv6 nexthop address. @end deffn @deffn {Route-map Command} {set ipv6 next-hop local @var{ipv6_address}} {} Set the BGP-4+ link local IPv6 nexthop address. @end deffn @node Route Map Call Command @section Route Map Call Command @deffn {Route-map Command} {call @var{name}} {} Call route-map @var{name}. If it returns deny, deny the route and finish processing the route-map. @end deffn @node Route Map Exit Action Command @section Route Map Exit Action Command @deffn {Route-map Command} {on-match next} {} @deffnx {Route-map Command} {continue} {} Proceed on to the next entry in the route-map. @end deffn @deffn {Route-map Command} {on-match goto @var{N}} {} @deffnx {Route-map Command} {continue @var{N}} {} Proceed processing the route-map at the first entry whose order is >= N @end deffn @node Route Map Examples @section Route Map Examples A simple example of a route-map: @example @group route-map test permit 10 match ip address 10 set local-preference 200 @end group @end example This means that if a route matches ip access-list number 10 it's local-preference value is set to 200. See @ref{BGP Configuration Examples} for examples of more sophisticated useage of route-maps, including of the @samp{call} action. quagga-0.99.24.1/doc/ripngd.texi0000644000175000017500000000416012476520570013160 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node RIPng @chapter RIPng @command{ripngd} supports the RIPng protocol as described in RFC2080. It's an IPv6 reincarnation of the RIP protocol. @menu * Invoking ripngd:: * ripngd Configuration:: * ripngd Terminal Mode Commands:: * ripngd Filtering Commands:: @end menu @node Invoking ripngd @section Invoking ripngd There are no @code{ripngd} specific invocation options. Common options can be specified (@pxref{Common Invocation Options}). @node ripngd Configuration @section ripngd Configuration Currently ripngd supports the following commands: @deffn Command {router ripng} {} Enable RIPng. @end deffn @deffn {RIPng Command} {flush_timer @var{time}} {} Set flush timer. @end deffn @deffn {RIPng Command} {network @var{network}} {} Set RIPng enabled interface by @var{network} @end deffn @deffn {RIPng Command} {network @var{ifname}} {} Set RIPng enabled interface by @var{ifname} @end deffn @deffn {RIPng Command} {route @var{network}} {} Set RIPng static routing announcement of @var{network}. @end deffn @deffn Command {router zebra} {} This command is the default and does not appear in the configuration. With this statement, RIPng routes go to the @command{zebra} daemon. @end deffn @node ripngd Terminal Mode Commands @section ripngd Terminal Mode Commands @deffn Command {show ip ripng} {} @end deffn @deffn Command {show debugging ripng} {} @end deffn @deffn Command {debug ripng events} {} @end deffn @deffn Command {debug ripng packet} {} @end deffn @deffn Command {debug ripng zebra} {} @end deffn @node ripngd Filtering Commands @section ripngd Filtering Commands @deffn Command {distribute-list @var{access_list} (in|out) @var{ifname}} {} You can apply an access-list to the interface using the @code{distribute-list} command. @var{access_list} is an access-list name. @var{direct} is @samp{in} or @samp{out}. If @var{direct} is @samp{in}, the access-list is applied only to incoming packets. @example distribute-list local-only out sit1 @end example @end deffn quagga-0.99.24.1/doc/ripd.texi0000644000175000017500000005463412476520570012646 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node RIP @chapter RIP RIP -- Routing Information Protocol is widely deployed interior gateway protocol. RIP was developed in the 1970s at Xerox Labs as part of the XNS routing protocol. RIP is a @dfn{distance-vector} protocol and is based on the @dfn{Bellman-Ford} algorithms. As a distance-vector protocol, RIP router send updates to its neighbors periodically, thus allowing the convergence to a known topology. In each update, the distance to any given network will be broadcasted to its neighboring router. @command{ripd} supports RIP version 2 as described in RFC2453 and RIP version 1 as described in RFC1058. @menu * Starting and Stopping ripd:: * RIP Configuration:: * RIP Version Control:: * How to Announce RIP route:: * Filtering RIP Routes:: * RIP Metric Manipulation:: * RIP distance:: * RIP route-map:: * RIP Authentication:: * RIP Timers:: * Show RIP Information:: * RIP Debug Commands:: @end menu @node Starting and Stopping ripd @section Starting and Stopping ripd The default configuration file name of @command{ripd}'s is @file{ripd.conf}. When invocation @command{ripd} searches directory @value{INSTALL_PREFIX_ETC}. If @file{ripd.conf} is not there next search current directory. RIP uses UDP port 520 to send and receive RIP packets. So the user must have the capability to bind the port, generally this means that the user must have superuser privileges. RIP protocol requires interface information maintained by @command{zebra} daemon. So running @command{zebra} is mandatory to run @command{ripd}. Thus minimum sequence for running RIP is like below: @example @group # zebra -d # ripd -d @end group @end example Please note that @command{zebra} must be invoked before @command{ripd}. To stop @command{ripd}. Please use @command{kill `cat /var/run/ripd.pid`}. Certain signals have special meaningss to @command{ripd}. @table @samp @item SIGHUP Reload configuration file @file{ripd.conf}. All configurations are reseted. All routes learned so far are cleared and removed from routing table. @item SIGUSR1 Rotate @command{ripd} logfile. @item SIGINT @itemx SIGTERM @command{ripd} sweeps all installed RIP routes then terminates properly. @end table @command{ripd} invocation options. Common options that can be specified (@pxref{Common Invocation Options}). @table @samp @item -r @itemx --retain When the program terminates, retain routes added by @command{ripd}. @end table @menu * RIP netmask:: @end menu @node RIP netmask @subsection RIP netmask The netmask features of @command{ripd} support both version 1 and version 2 of RIP. Version 1 of RIP originally contained no netmask information. In RIP version 1, network classes were originally used to determine the size of the netmask. Class A networks use 8 bits of mask, Class B networks use 16 bits of masks, while Class C networks use 24 bits of mask. Today, the most widely used method of a network mask is assigned to the packet on the basis of the interface that received the packet. Version 2 of RIP supports a variable length subnet mask (VLSM). By extending the subnet mask, the mask can be divided and reused. Each subnet can be used for different purposes such as large to middle size LANs and WAN links. Quagga @command{ripd} does not support the non-sequential netmasks that are included in RIP Version 2. In a case of similar information with the same prefix and metric, the old information will be suppressed. Ripd does not currently support equal cost multipath routing. @node RIP Configuration @section RIP Configuration @deffn Command {router rip} {} The @code{router rip} command is necessary to enable RIP. To disable RIP, use the @code{no router rip} command. RIP must be enabled before carrying out any of the RIP commands. @end deffn @deffn Command {no router rip} {} Disable RIP. @end deffn @deffn {RIP Command} {network @var{network}} {} @deffnx {RIP Command} {no network @var{network}} {} Set the RIP enable interface by @var{network}. The interfaces which have addresses matching with @var{network} are enabled. This group of commands either enables or disables RIP interfaces between certain numbers of a specified network address. For example, if the network for 10.0.0.0/24 is RIP enabled, this would result in all the addresses from 10.0.0.0 to 10.0.0.255 being enabled for RIP. The @code{no network} command will disable RIP for the specified network. @end deffn @deffn {RIP Command} {network @var{ifname}} {} @deffnx {RIP Command} {no network @var{ifname}} {} Set a RIP enabled interface by @var{ifname}. Both the sending and receiving of RIP packets will be enabled on the port specified in the @code{network ifname} command. The @code{no network ifname} command will disable RIP on the specified interface. @end deffn @deffn {RIP Command} {neighbor @var{a.b.c.d}} {} @deffnx {RIP Command} {no neighbor @var{a.b.c.d}} {} Specify RIP neighbor. When a neighbor doesn't understand multicast, this command is used to specify neighbors. In some cases, not all routers will be able to understand multicasting, where packets are sent to a network or a group of addresses. In a situation where a neighbor cannot process multicast packets, it is necessary to establish a direct link between routers. The neighbor command allows the network administrator to specify a router as a RIP neighbor. The @code{no neighbor a.b.c.d} command will disable the RIP neighbor. @end deffn Below is very simple RIP configuration. Interface @code{eth0} and interface which address match to @code{10.0.0.0/8} are RIP enabled. @example @group ! router rip network 10.0.0.0/8 network eth0 ! @end group @end example Passive interface @deffn {RIP command} {passive-interface (@var{IFNAME}|default)} {} @deffnx {RIP command} {no passive-interface @var{IFNAME}} {} This command sets the specified interface to passive mode. On passive mode interface, all receiving packets are processed as normal and ripd does not send either multicast or unicast RIP packets except to RIP neighbors specified with @code{neighbor} command. The interface may be specified as @var{default} to make ripd default to passive on all interfaces. The default is to be passive on all interfaces. @end deffn RIP split-horizon @deffn {Interface command} {ip split-horizon} {} @deffnx {Interface command} {no ip split-horizon} {} Control split-horizon on the interface. Default is @code{ip split-horizon}. If you don't perform split-horizon on the interface, please specify @code{no ip split-horizon}. @end deffn @node RIP Version Control @section RIP Version Control RIP can be configured to send either Version 1 or Version 2 packets. The default is to send RIPv2 while accepting both RIPv1 and RIPv2 (and replying with packets of the appropriate version for REQUESTS / triggered updates). The version to receive and send can be specified globally, and further overriden on a per-interface basis if needs be for send and receive seperately (see below). It is important to note that RIPv1 can not be authenticated. Further, if RIPv1 is enabled then RIP will reply to REQUEST packets, sending the state of its RIP routing table to any remote routers that ask on demand. For a more detailed discussion on the security implications of RIPv1 see @ref{RIP Authentication}. @deffn {RIP Command} {version @var{version}} {} Set RIP version to accept for reads and send. @var{version} can be either `1'' or `2''. Disabling RIPv1 by specifying version 2 is STRONGLY encouraged, @xref{RIP Authentication}. This may become the default in a future release. Default: Send Version 2, and accept either version. @end deffn @deffn {RIP Command} {no version} {} Reset the global version setting back to the default. @end deffn @deffn {Interface command} {ip rip send version @var{version}} {} @var{version} can be `1', `2' or `1 2'. This interface command overrides the global rip version setting, and selects which version of RIP to send packets with, for this interface specifically. Choice of RIP Version 1, RIP Version 2, or both versions. In the latter case, where `1 2' is specified, packets will be both broadcast and multicast. Default: Send packets according to the global version (version 2) @end deffn @deffn {Interface command} {ip rip receive version @var{version}} {} @var{version} can be `1', `2' or `1 2'. This interface command overrides the global rip version setting, and selects which versions of RIP packets will be accepted on this interface. Choice of RIP Version 1, RIP Version 2, or both. Default: Accept packets according to the global setting (both 1 and 2). @end deffn @node How to Announce RIP route @section How to Announce RIP route @deffn {RIP command} {redistribute kernel} {} @deffnx {RIP command} {redistribute kernel metric <0-16>} {} @deffnx {RIP command} {redistribute kernel route-map @var{route-map}} {} @deffnx {RIP command} {no redistribute kernel} {} @code{redistribute kernel} redistributes routing information from kernel route entries into the RIP tables. @code{no redistribute kernel} disables the routes. @end deffn @deffn {RIP command} {redistribute static} {} @deffnx {RIP command} {redistribute static metric <0-16>} {} @deffnx {RIP command} {redistribute static route-map @var{route-map}} {} @deffnx {RIP command} {no redistribute static} {} @code{redistribute static} redistributes routing information from static route entries into the RIP tables. @code{no redistribute static} disables the routes. @end deffn @deffn {RIP command} {redistribute connected} {} @deffnx {RIP command} {redistribute connected metric <0-16>} {} @deffnx {RIP command} {redistribute connected route-map @var{route-map}} {} @deffnx {RIP command} {no redistribute connected} {} Redistribute connected routes into the RIP tables. @code{no redistribute connected} disables the connected routes in the RIP tables. This command redistribute connected of the interface which RIP disabled. The connected route on RIP enabled interface is announced by default. @end deffn @deffn {RIP command} {redistribute ospf} {} @deffnx {RIP command} {redistribute ospf metric <0-16>} {} @deffnx {RIP command} {redistribute ospf route-map @var{route-map}} {} @deffnx {RIP command} {no redistribute ospf} {} @code{redistribute ospf} redistributes routing information from ospf route entries into the RIP tables. @code{no redistribute ospf} disables the routes. @end deffn @deffn {RIP command} {redistribute bgp} {} @deffnx {RIP command} {redistribute bgp metric <0-16>} {} @deffnx {RIP command} {redistribute bgp route-map @var{route-map}} {} @deffnx {RIP command} {no redistribute bgp} {} @code{redistribute bgp} redistributes routing information from bgp route entries into the RIP tables. @code{no redistribute bgp} disables the routes. @end deffn If you want to specify RIP only static routes: @deffn {RIP command} {default-information originate} {} @end deffn @deffn {RIP command} {route @var{a.b.c.d/m}} {} @deffnx {RIP command} {no route @var{a.b.c.d/m}} {} This command is specific to Quagga. The @code{route} command makes a static route only inside RIP. This command should be used only by advanced users who are particularly knowledgeable about the RIP protocol. In most cases, we recommend creating a static route in Quagga and redistributing it in RIP using @code{redistribute static}. @end deffn @node Filtering RIP Routes @section Filtering RIP Routes RIP routes can be filtered by a distribute-list. @deffn Command {distribute-list @var{access_list} @var{direct} @var{ifname}} {} You can apply access lists to the interface with a @code{distribute-list} command. @var{access_list} is the access list name. @var{direct} is @samp{in} or @samp{out}. If @var{direct} is @samp{in} the access list is applied to input packets. The @code{distribute-list} command can be used to filter the RIP path. @code{distribute-list} can apply access-lists to a chosen interface. First, one should specify the access-list. Next, the name of the access-list is used in the distribute-list command. For example, in the following configuration @samp{eth0} will permit only the paths that match the route 10.0.0.0/8 @example @group ! router rip distribute-list private in eth0 ! access-list private permit 10 10.0.0.0/8 access-list private deny any ! @end group @end example @end deffn @code{distribute-list} can be applied to both incoming and outgoing data. @deffn Command {distribute-list prefix @var{prefix_list} (in|out) @var{ifname}} {} You can apply prefix lists to the interface with a @code{distribute-list} command. @var{prefix_list} is the prefix list name. Next is the direction of @samp{in} or @samp{out}. If @var{direct} is @samp{in} the access list is applied to input packets. @end deffn @node RIP Metric Manipulation @section RIP Metric Manipulation RIP metric is a value for distance for the network. Usually @command{ripd} increment the metric when the network information is received. Redistributed routes' metric is set to 1. @deffn {RIP command} {default-metric <1-16>} {} @deffnx {RIP command} {no default-metric <1-16>} {} This command modifies the default metric value for redistributed routes. The default value is 1. This command does not affect connected route even if it is redistributed by @command{redistribute connected}. To modify connected route's metric value, please use @command{redistribute connected metric} or @command{route-map}. @command{offset-list} also affects connected routes. @end deffn @deffn {RIP command} {offset-list @var{access-list} (in|out)} {} @deffnx {RIP command} {offset-list @var{access-list} (in|out) @var{ifname}} {} @end deffn @node RIP distance @section RIP distance Distance value is used in zebra daemon. Default RIP distance is 120. @deffn {RIP command} {distance <1-255>} {} @deffnx {RIP command} {no distance <1-255>} {} Set default RIP distance to specified value. @end deffn @deffn {RIP command} {distance <1-255> @var{A.B.C.D/M}} {} @deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M}} {} Set default RIP distance to specified value when the route's source IP address matches the specified prefix. @end deffn @deffn {RIP command} {distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} @deffnx {RIP command} {no distance <1-255> @var{A.B.C.D/M} @var{access-list}} {} Set default RIP distance to specified value when the route's source IP address matches the specified prefix and the specified access-list. @end deffn @node RIP route-map @section RIP route-map Usage of @command{ripd}'s route-map support. Optional argument route-map MAP_NAME can be added to each @code{redistribute} statement. @example redistribute static [route-map MAP_NAME] redistribute connected [route-map MAP_NAME] ..... @end example Cisco applies route-map _before_ routes will exported to rip route table. In current Quagga's test implementation, @command{ripd} applies route-map after routes are listed in the route table and before routes will be announced to an interface (something like output filter). I think it is not so clear, but it is draft and it may be changed at future. Route-map statement (@pxref{Route Map}) is needed to use route-map functionality. @deffn {Route Map} {match interface @var{word}} {} This command match to incoming interface. Notation of this match is different from Cisco. Cisco uses a list of interfaces - NAME1 NAME2 ... NAMEN. Ripd allows only one name (maybe will change in the future). Next - Cisco means interface which includes next-hop of routes (it is somewhat similar to "ip next-hop" statement). Ripd means interface where this route will be sent. This difference is because "next-hop" of same routes which sends to different interfaces must be different. Maybe it'd be better to made new matches - say "match interface-out NAME" or something like that. @end deffn @deffn {Route Map} {match ip address @var{word}} {} @deffnx {Route Map} {match ip address prefix-list @var{word}} {} Match if route destination is permitted by access-list. @end deffn @deffn {Route Map} {match ip next-hop @var{word}} {} @deffnx {Route Map} {match ip next-hop prefix-list @var{word}} {} Match if route next-hop (meaning next-hop listed in the rip route-table as displayed by "show ip rip") is permitted by access-list. @end deffn @deffn {Route Map} {match metric <0-4294967295>} {} This command match to the metric value of RIP updates. For other protocol compatibility metric range is shown as <0-4294967295>. But for RIP protocol only the value range <0-16> make sense. @end deffn @deffn {Route Map} {set ip next-hop A.B.C.D} {} This command set next hop value in RIPv2 protocol. This command does not affect RIPv1 because there is no next hop field in the packet. @end deffn @deffn {Route Map} {set metric <0-4294967295>} {} Set a metric for matched route when sending announcement. The metric value range is very large for compatibility with other protocols. For RIP, valid metric values are from 1 to 16. @end deffn @node RIP Authentication @section RIP Authentication RIPv2 allows packets to be authenticated via either an insecure plain text password, included with the packet, or via a more secure MD5 based @acronym{HMAC, keyed-Hashing for Message AuthentiCation}, RIPv1 can not be authenticated at all, thus when authentication is configured @code{ripd} will discard routing updates received via RIPv1 packets. However, unless RIPv1 reception is disabled entirely, @xref{RIP Version Control}, RIPv1 REQUEST packets which are received, which query the router for routing information, will still be honoured by @code{ripd}, and @code{ripd} WILL reply to such packets. This allows @code{ripd} to honour such REQUESTs (which sometimes is used by old equipment and very simple devices to bootstrap their default route), while still providing security for route updates which are received. In short: Enabling authentication prevents routes being updated by unauthenticated remote routers, but still can allow routes (I.e. the entire RIP routing table) to be queried remotely, potentially by anyone on the internet, via RIPv1. To prevent such unauthenticated querying of routes disable RIPv1, @xref{RIP Version Control}. @deffn {Interface command} {ip rip authentication mode md5} {} @deffnx {Interface command} {no ip rip authentication mode md5} {} Set the interface with RIPv2 MD5 authentication. @end deffn @deffn {Interface command} {ip rip authentication mode text} {} @deffnx {Interface command} {no ip rip authentication mode text} {} Set the interface with RIPv2 simple password authentication. @end deffn @deffn {Interface command} {ip rip authentication string @var{string}} {} @deffnx {Interface command} {no ip rip authentication string @var{string}} {} RIP version 2 has simple text authentication. This command sets authentication string. The string must be shorter than 16 characters. @end deffn @deffn {Interface command} {ip rip authentication key-chain @var{key-chain}} {} @deffnx {Interface command} {no ip rip authentication key-chain @var{key-chain}} {} Specifiy Keyed MD5 chain. @end deffn @example ! key chain test key 1 key-string test ! interface eth1 ip rip authentication mode md5 ip rip authentication key-chain test ! @end example @node RIP Timers @section RIP Timers @deffn {RIP command} {timers basic @var{update} @var{timeout} @var{garbage}} {} RIP protocol has several timers. User can configure those timers' values by @code{timers basic} command. The default settings for the timers are as follows: @itemize @bullet @item The update timer is 30 seconds. Every update timer seconds, the RIP process is awakened to send an unsolicited Response message containing the complete routing table to all neighboring RIP routers. @item The timeout timer is 180 seconds. Upon expiration of the timeout, the route is no longer valid; however, it is retained in the routing table for a short time so that neighbors can be notified that the route has been dropped. @item The garbage collect timer is 120 seconds. Upon expiration of the garbage-collection timer, the route is finally removed from the routing table. @end itemize The @code{timers basic} command allows the the default values of the timers listed above to be changed. @end deffn @deffn {RIP command} {no timers basic} {} The @code{no timers basic} command will reset the timers to the default settings listed above. @end deffn @node Show RIP Information @section Show RIP Information To display RIP routes. @deffn Command {show ip rip} {} Show RIP routes. @end deffn The command displays all RIP routes. For routes that are received through RIP, this command will display the time the packet was sent and the tag information. This command will also display this information for routes redistributed into RIP. @c Exmaple here. @deffn Command {show ip rip status} {} The command displays current RIP status. It includes RIP timer, filtering, version, RIP enabled interface and RIP peer inforation. @end deffn @example @group ripd> @b{show ip rip status} Routing Protocol is "rip" Sending updates every 30 seconds with +/-50%, next due in 35 seconds Timeout after 180 seconds, garbage collect after 120 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 Redistributing: kernel connected Default version control: send version 2, receive version 2 Interface Send Recv Routing for Networks: eth0 eth1 1.1.1.1 203.181.89.241 Routing Information Sources: Gateway BadPackets BadRoutes Distance Last Update @end group @end example @node RIP Debug Commands @section RIP Debug Commands Debug for RIP protocol. @deffn Command {debug rip events} {} Debug rip events. @end deffn @code{debug rip} will show RIP events. Sending and receiving packets, timers, and changes in interfaces are events shown with @command{ripd}. @deffn Command {debug rip packet} {} Debug rip packet. @end deffn @code{debug rip packet} will display detailed information about the RIP packets. The origin and port number of the packet as well as a packet dump is shown. @deffn Command {debug rip zebra} {} Debug rip between zebra communication. @end deffn This command will show the communication between @command{ripd} and @command{zebra}. The main information will include addition and deletion of paths to the kernel and the sending and receiving of interface information. @deffn Command {show debugging rip} {} Display @command{ripd}'s debugging option. @end deffn @code{show debugging rip} will show all information currently set for ripd debug. quagga-0.99.24.1/doc/protocol.texi0000644000175000017500000000711712476520570013543 00000000000000@node Zebra Protocol @appendix Zebra Protocol @appendixsection Overview of the Zebra Protocol Zebra Protocol is used by protocol daemons to communicate with the zebra daemon. Each protocol daemon may request and send information to and from the zebra daemon such as interface states, routing state, nexthop-validation, and so on. Protocol daemons may also install routes with zebra. The zebra daemon manages which route is installed into the forwarding table with the kernel. Zebra Protocol is a streaming protocol, with a common header. Two versions of the header are in use. Version 0 is implicitely versioned. Version 1 has an explicit version field. Version 0 can be distinguished from all other versions by examining the 3rd byte of the header, which contains a marker value for all versions bar version 0. The marker byte corresponds to the command field in version 0, and the marker value is a reserved command in version 0. We do not anticipate there will be further versions of the header for the foreseeable future, as the command field in version 1 is wide enough to allow for future extensions to done compatibly through seperate commands. Version 0 is used by all versions of GNU Zebra as of this writing, and versions of Quagga up to and including Quagga 0.98. Version 1 will be used as of Quagga 1.0. @appendixsection Zebra Protocol Definition @appendixsubsec Zebra Protocol Header (version 0) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-------------------------------+---------------+ | Length (2) | Command (1) | +-------------------------------+---------------+ @end group @end example @appendixsubsec Zebra Protocol Common Header (version 1) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-------------------------------+---------------+-------------+ | Length (2) | Marker (1) | Version (1) | +-------------------------------+---------------+-------------+ | Command (2) | +-------------------------------+ @end group @end example @appendixsubsec Zebra Protocol Header Field Definitions @table @samp @item Length Total packet length including this header. The minimum length is 3 bytes for version 0 messages and 6 bytes for version 1 messages. @item Marker Static marker with a value of 255 always. This is to allow version 0 Zserv headers (which do not include version explicitely) to be distinguished from versioned headers. Not present in version 0 messages. @item Version Version number of the Zserv message. Clients should not continue processing messages past the version field for versions they do not recognise. Not present in version 0 messages. @item Command The Zebra Protocol command. @end table @appendixsubsec Zebra Protocol Commands @multitable {ZEBRA_REDISTRIBUTE_DEFAULT_DELETE_WHATEVER} {99999} @headitem Command @tab Value @item ZEBRA_INTERFACE_ADD @tab 1 @item ZEBRA_INTERFACE_DELETE @tab 2 @item ZEBRA_INTERFACE_ADDRESS_ADD @tab 3 @item ZEBRA_INTERFACE_ADDRESS_DELETE @tab 4 @item ZEBRA_INTERFACE_UP @tab 5 @item ZEBRA_INTERFACE_DOWN @tab 6 @item ZEBRA_IPV4_ROUTE_ADD @tab 7 @item ZEBRA_IPV4_ROUTE_DELETE @tab 8 @item ZEBRA_IPV6_ROUTE_ADD @tab 9 @item ZEBRA_IPV6_ROUTE_DELETE @tab 10 @item ZEBRA_REDISTRIBUTE_ADD @tab 11 @item ZEBRA_REDISTRIBUTE_DELETE @tab 12 @item ZEBRA_REDISTRIBUTE_DEFAULT_ADD @tab 13 @item ZEBRA_REDISTRIBUTE_DEFAULT_DELETE @tab 14 @item ZEBRA_IPV4_NEXTHOP_LOOKUP @tab 15 @item ZEBRA_IPV6_NEXTHOP_LOOKUP @tab 16 @end multitable quagga-0.99.24.1/doc/overview.texi0000644000175000017500000002770512476520570013555 00000000000000@node Overview @chapter Overview @cindex Overview @uref{http://www.quagga.net,,Quagga} is a routing software package that provides TCP/IP based routing services with routing protocols support such as RIPv1, RIPv2, RIPng, OSPFv2, OSPFv3, IS-IS, BGP-4, and BGP-4+ (@pxref{Supported RFCs}). Quagga also supports special BGP Route Reflector and Route Server behavior. In addition to traditional IPv4 routing protocols, Quagga also supports IPv6 routing protocols. With SNMP daemon which supports SMUX and AgentX protocol, Quagga provides routing protocol MIBs (@pxref{SNMP Support}). Quagga uses an advanced software architecture to provide you with a high quality, multi server routing engine. Quagga has an interactive user interface for each routing protocol and supports common client commands. Due to this design, you can add new protocol daemons to Quagga easily. You can use Quagga library as your program's client user interface. Quagga is distributed under the @sc{gnu} General Public License. @menu * About Quagga:: Basic information about Quagga * System Architecture:: The Quagga system architecture * Supported Platforms:: Supported platforms and future plans * Supported RFCs:: Supported RFCs * How to get Quagga:: * Mailing List:: Mailing list information * Bug Reports:: Mail address for bug data @end menu @node About Quagga @comment node-name, next, previous, up @section About Quagga @cindex About Quagga Today, TCP/IP networks are covering all of the world. The Internet has been deployed in many countries, companies, and to the home. When you connect to the Internet your packet will pass many routers which have TCP/IP routing functionality. A system with Quagga installed acts as a dedicated router. With Quagga, your machine exchanges routing information with other routers using routing protocols. Quagga uses this information to update the kernel routing table so that the right data goes to the right place. You can dynamically change the configuration and you may view routing table information from the Quagga terminal interface. Adding to routing protocol support, Quagga can setup interface's flags, interface's address, static routes and so on. If you have a small network, or a stub network, or xDSL connection, configuring the Quagga routing software is very easy. The only thing you have to do is to set up the interfaces and put a few commands about static routes and/or default routes. If the network is rather large, or if the network structure changes frequently, you will want to take advantage of Quagga's dynamic routing protocol support for protocols such as RIP, OSPF, IS-IS or BGP. Traditionally, UNIX based router configuration is done by @command{ifconfig} and @command{route} commands. Status of routing table is displayed by @command{netstat} utility. Almost of these commands work only if the user has root privileges. Quagga has a different system administration method. There are two user modes in Quagga. One is normal mode, the other is enable mode. Normal mode user can only view system status, enable mode user can change system configuration. This UNIX account independent feature will be great help to the router administrator. Currently, Quagga supports common unicast routing protocols, that is BGP, OSPF, RIP and IS-IS. Upcoming for MPLS support, an implementation of LDP is currently being prepared for merging. Implementations of BFD and PIM-SSM (IPv4) also exist, but are not actively being worked on. The ultimate goal of the Quagga project is making a productive, quality, free TCP/IP routing software package. @node System Architecture @comment node-name, next, previous, up @section System Architecture @cindex System architecture @cindex Software architecture @cindex Software internals Traditional routing software is made as a one process program which provides all of the routing protocol functionalities. Quagga takes a different approach. It is made from a collection of several daemons that work together to build the routing table. There may be several protocol-specific routing daemons and zebra the kernel routing manager. The @command{ripd} daemon handles the RIP protocol, while @command{ospfd} is a daemon which supports OSPF version 2. @command{bgpd} supports the BGP-4 protocol. For changing the kernel routing table and for redistribution of routes between different routing protocols, there is a kernel routing table manager @command{zebra} daemon. It is easy to add a new routing protocol daemons to the entire routing system without affecting any other software. You need to run only the protocol daemon associated with routing protocols in use. Thus, user may run a specific daemon and send routing reports to a central routing console. There is no need for these daemons to be running on the same machine. You can even run several same protocol daemons on the same machine. This architecture creates new possibilities for the routing system. @example @group +----+ +----+ +-----+ +-----+ |bgpd| |ripd| |ospfd| |zebra| +----+ +----+ +-----+ +-----+ | +---------------------------|--+ | v | | UNIX Kernel routing table | | | +------------------------------+ Quagga System Architecture @end group @end example Multi-process architecture brings extensibility, modularity and maintainability. At the same time it also brings many configuration files and terminal interfaces. Each daemon has it's own configuration file and terminal interface. When you configure a static route, it must be done in @command{zebra} configuration file. When you configure BGP network it must be done in @command{bgpd} configuration file. This can be a very annoying thing. To resolve the problem, Quagga provides integrated user interface shell called @command{vtysh}. @command{vtysh} connects to each daemon with UNIX domain socket and then works as a proxy for user input. Quagga was planned to use multi-threaded mechanism when it runs with a kernel that supports multi-threads. But at the moment, the thread library which comes with @sc{gnu}/Linux or FreeBSD has some problems with running reliable services such as routing software, so we don't use threads at all. Instead we use the @command{select(2)} system call for multiplexing the events. @node Supported Platforms @comment node-name, next, previous, up @section Supported Platforms @cindex Supported platforms @cindex Quagga on other systems @cindex Compatibility with other systems @cindex Operating systems that support Quagga Currently Quagga supports @sc{gnu}/Linux and BSD. Porting Quagga to other platforms is not too difficult as platform dependent code should most be limited to the @command{zebra} daemon. Protocol daemons are mostly platform independent. Please let us know when you find out Quagga runs on a platform which is not listed below. The list of officially supported platforms are listed below. Note that Quagga may run correctly on other platforms, and may run with partial functionality on further platforms. @sp 1 @itemize @bullet @item @sc{gnu}/Linux @item FreeBSD @item NetBSD @item OpenBSD @end itemize Versions of these platforms that are older than around 2 years from the point of their original release (in case of @sc{gnu}/Linux, this is since the kernel's release on kernel.org) may need some work. Similarly, the following platforms may work with some effort: @sp 1 @itemize @bullet @item Solaris @item Mac OSX @end itemize Also note that, in particular regarding proprietary platforms, compiler and C library choice will affect Quagga. Only recent versions of the following C compilers are well-tested: @sp 1 @itemize @bullet @item @sc{gnu}'s GCC @item LLVM's clang @item Intel's ICC @end itemize @node Supported RFCs @comment node-name, next, previous, up @section Supported RFCs Below is the list of currently supported RFC's. @table @asis @item @asis{RFC1058} @cite{Routing Information Protocol. C.L. Hedrick. Jun-01-1988.} @item @asis{RF2082} @cite{RIP-2 MD5 Authentication. F. Baker, R. Atkinson. January 1997.} @item @asis{RFC2453} @cite{RIP Version 2. G. Malkin. November 1998.} @item @asis{RFC2080} @cite{RIPng for IPv6. G. Malkin, R. Minnear. January 1997.} @item @asis{RFC2328} @cite{OSPF Version 2. J. Moy. April 1998.} @item @asis{RFC2370} @cite{The OSPF Opaque LSA Option R. Coltun. July 1998.} @item @asis{RFC3101} @cite{The OSPF Not-So-Stubby Area (NSSA) Option P. Murphy. January 2003.} @item @asis{RFC2740} @cite{OSPF for IPv6. R. Coltun, D. Ferguson, J. Moy. December 1999.} @item @asis{RFC1771} @cite{A Border Gateway Protocol 4 (BGP-4). Y. Rekhter & T. Li. March 1995.} @item @asis{RFC1965} @cite{Autonomous System Confederations for BGP. P. Traina. June 1996.} @item @asis{RFC1997} @cite{BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.} @item @asis{RFC2545} @cite{Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.} @item @asis{RFC2796} @cite{BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.} @item @asis{RFC2858} @cite{Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.} @item @asis{RFC2842} @cite{Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.} @item @asis{RFC3137} @cite{OSPF Stub Router Advertisement, A. Retana, L. Nguyen, R. White, A. Zinin, D. McPherson. June 2001} @end table When SNMP support is enabled, below RFC is also supported. @table @asis @item @asis{RFC1227} @cite{SNMP MUX protocol and MIB. M.T. Rose. May-01-1991.} @item @asis{RFC1657} @cite{Definitions of Managed Objects for the Fourth Version of the Border Gateway Protocol (BGP-4) using SMIv2. S. Willis, J. Burruss, J. Chu, Editor. July 1994.} @item @asis{RFC1724} @cite{RIP Version 2 MIB Extension. G. Malkin & F. Baker. November 1994.} @item @asis{RFC1850} @cite{OSPF Version 2 Management Information Base. F. Baker, R. Coltun. November 1995.} @item @asis{RFC2741} @cite{Agent Extensibility (AgentX) Protocol. M. Daniele, B. Wijnen. January 2000.} @end table @node How to get Quagga @comment node-name, next, previous, up @section How to get Quagga The official Quagga web-site is located at: @uref{http://www.quagga.net/} and contains further information, as well as links to additional resources. @uref{http://www.quagga.net/,Quagga} is a fork of GNU Zebra, whose web-site is located at: @uref{http://www.zebra.org/}. @node Mailing List @comment node-name, next, previous, up @section Mailing List @cindex How to get in touch with Quagga @cindex Mailing Quagga @cindex Contact information @cindex Mailing lists There is a mailing list for discussions about Quagga. If you have any comments or suggestions to Quagga, please subscribe to: @uref{http://lists.quagga.net/mailman/listinfo/quagga-users}. The @uref{http://www.quagga.net/,,Quagga} site has further information on the available mailing lists, see: @uref{http://www.quagga.net/lists.php} @node Bug Reports @section Bug Reports @cindex Bug Reports @cindex Bug hunting @cindex Found a bug? @cindex Reporting bugs @cindex Reporting software errors @cindex Errors in the software If you think you have found a bug, please send a bug report to: @uref{http://bugzilla.quagga.net} When you send a bug report, please be careful about the points below. @itemize @bullet @item Please note what kind of OS you are using. If you use the IPv6 stack please note that as well. @item Please show us the results of @code{netstat -rn} and @code{ifconfig -a}. Information from zebra's VTY command @code{show ip route} will also be helpful. @item Please send your configuration file with the report. If you specify arguments to the configure script please note that too. @end itemize Bug reports are very important for us to improve the quality of Quagga. Quagga is still in the development stage, but please don't hesitate to send a bug report to @uref{http://bugzilla.quagga.net}. quagga-0.99.24.1/doc/ospfd.texi0000644000175000017500000007351112476520570013016 00000000000000@cindex OSPFv2 @node OSPFv2 @chapter OSPFv2 @acronym{OSPF,Open Shortest Path First} version 2 is a routing protocol which is described in @cite{RFC2328, OSPF Version 2}. OSPF is an @acronym{IGP,Interior Gateway Protocol}. Compared with @acronym{RIP}, @acronym{OSPF} can provide scalable network support and faster convergence times. OSPF is widely used in large networks such as @acronym{ISP,Internet Service Provider} backbone and enterprise networks. @menu * Configuring ospfd:: * OSPF router:: * OSPF area:: * OSPF interface:: * Redistribute routes to OSPF:: * Showing OSPF information:: * Debugging OSPF:: * OSPF Configuration Examples:: @end menu @node Configuring ospfd @section Configuring ospfd There are no @command{ospfd} specific options. Common options can be specified (@pxref{Common Invocation Options}) to @command{ospfd}. @command{ospfd} needs to acquire interface information from @command{zebra} in order to function. Therefore @command{zebra} must be running before invoking @command{ospfd}. Also, if @command{zebra} is restarted then @command{ospfd} must be too. Like other daemons, @command{ospfd} configuration is done in @acronym{OSPF} specific configuration file @file{ospfd.conf}. @node OSPF router @section OSPF router To start OSPF process you have to specify the OSPF router. As of this writing, @command{ospfd} does not support multiple OSPF processes. @deffn Command {router ospf} {} @deffnx Command {no router ospf} {} Enable or disable the OSPF process. @command{ospfd} does not yet support multiple OSPF processes. So you can not specify an OSPF process number. @end deffn @deffn {OSPF Command} {ospf router-id @var{a.b.c.d}} {} @deffnx {OSPF Command} {no ospf router-id} {} @anchor{ospf router-id}This sets the router-ID of the OSPF process. The router-ID may be an IP address of the router, but need not be - it can be any arbitrary 32bit number. However it MUST be unique within the entire OSPF domain to the OSPF speaker - bad things will happen if multiple OSPF speakers are configured with the same router-ID! If one is not specified then @command{ospfd} will obtain a router-ID automatically from @command{zebra}. @end deffn @deffn {OSPF Command} {ospf abr-type @var{type}} {} @deffnx {OSPF Command} {no ospf abr-type @var{type}} {} @var{type} can be cisco|ibm|shortcut|standard. The "Cisco" and "IBM" types are equivalent. The OSPF standard for ABR behaviour does not allow an ABR to consider routes through non-backbone areas when its links to the backbone are down, even when there are other ABRs in attached non-backbone areas which still can reach the backbone - this restriction exists primarily to ensure routing-loops are avoided. With the "Cisco" or "IBM" ABR type, the default in this release of Quagga, this restriction is lifted, allowing an ABR to consider summaries learnt from other ABRs through non-backbone areas, and hence route via non-backbone areas as a last resort when, and only when, backbone links are down. Note that areas with fully-adjacent virtual-links are considered to be "transit capable" and can always be used to route backbone traffic, and hence are unaffected by this setting (@pxref{OSPF virtual-link}). More information regarding the behaviour controlled by this command can be found in @cite{RFC 3509, Alternative Implementations of OSPF Area Border Routers}, and @cite{draft-ietf-ospf-shortcut-abr-02.txt}. Quote: "Though the definition of the @acronym{ABR,Area Border Router} in the OSPF specification does not require a router with multiple attached areas to have a backbone connection, it is actually necessary to provide successful routing to the inter-area and external destinations. If this requirement is not met, all traffic destined for the areas not connected to such an ABR or out of the OSPF domain, is dropped. This document describes alternative ABR behaviors implemented in Cisco and IBM routers." @end deffn @deffn {OSPF Command} {ospf rfc1583compatibility} {} @deffnx {OSPF Command} {no ospf rfc1583compatibility} {} @cite{RFC2328}, the sucessor to @cite{RFC1583}, suggests according to section G.2 (changes) in section 16.4 a change to the path preference algorithm that prevents possible routing loops that were possible in the old version of OSPFv2. More specifically it demands that inter-area paths and intra-area backbone path are now of equal preference but still both preferred to external paths. This command should NOT be set normally. @end deffn @deffn {OSPF Command} {log-adjacency-changes [detail]} {} @deffnx {OSPF Command} {no log-adjacency-changes [detail]} {} Configures ospfd to log changes in adjacency. With the optional detail argument, all changes in adjacency status are shown. Without detail, only changes to full or regressions are shown. @end deffn @deffn {OSPF Command} {passive-interface @var{interface}} {} @deffnx {OSPF Command} {no passive-interface @var{interface}} {} @anchor{OSPF passive-interface} Do not speak OSPF interface on the given interface, but do advertise the interface as a stub link in the router-@acronym{LSA,Link State Advertisement} for this router. This allows one to advertise addresses on such connected interfaces without having to originate AS-External/Type-5 LSAs (which have global flooding scope) - as would occur if connected addresses were redistributed into OSPF (@pxref{Redistribute routes to OSPF})@. This is the only way to advertise non-OSPF links into stub areas. @end deffn @deffn {OSPF Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {} @deffnx {OSPF Command} {no timers throttle spf} {} This command sets the initial @var{delay}, the @var{initial-holdtime} and the @var{maximum-holdtime} between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The @var{delay} specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the @var{initial-holdtime} configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by @var{initial-holdtime}, bounded by the @var{maximum-holdtime} configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the @var{initial-holdtime}. The current holdtime can be viewed with @ref{show ip ospf}, where it is expressed as a multiplier of the @var{initial-holdtime}. @example @group router ospf timers throttle spf 200 400 10000 @end group @end example In this example, the @var{delay} is set to 200ms, the @var{initial holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. This command supercedes the @command{timers spf} command in previous Quagga releases. @end deffn @deffn {OSPF Command} {max-metric router-lsa [on-startup|on-shutdown] <5-86400>} {} @deffnx {OSPF Command} {max-metric router-lsa administrative} {} @deffnx {OSPF Command} {no max-metric router-lsa [on-startup|on-shutdown|administrative]} {} This enables @cite{RFC3137, OSPF Stub Router Advertisement} support, where the OSPF process describes its transit links in its router-LSA as having infinite distance so that other routers will avoid calculating transit paths through the router while still being able to reach networks through the router. This support may be enabled administratively (and indefinitely) or conditionally. Conditional enabling of max-metric router-lsas can be for a period of seconds after startup and/or for a period of seconds prior to shutdown. Enabling this for a period after startup allows OSPF to converge fully first without affecting any existing routes used by other routers, while still allowing any connected stub links and/or redistributed routes to be reachable. Enabling this for a period of time in advance of shutdown allows the router to gracefully excuse itself from the OSPF domain. Enabling this feature administratively allows for administrative intervention for whatever reason, for an indefinite period of time. Note that if the configuration is written to file, this administrative form of the stub-router command will also be written to file. If @command{ospfd} is restarted later, the command will then take effect until manually deconfigured. Configured state of this feature as well as current status, such as the number of second remaining till on-startup or on-shutdown ends, can be viewed with the @ref{show ip ospf} command. @end deffn @deffn {OSPF Command} {auto-cost reference-bandwidth <1-4294967>} {} @deffnx {OSPF Command} {no auto-cost reference-bandwidth} {} @anchor{OSPF auto-cost reference-bandwidth}This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. @end deffn @deffn {OSPF Command} {network @var{a.b.c.d/m} area @var{a.b.c.d}} {} @deffnx {OSPF Command} {network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} @deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{a.b.c.d}} {} @deffnx {OSPF Command} {no network @var{a.b.c.d/m} area @var{<0-4294967295>}} {} This command specifies the OSPF enabled interface(s). If the interface has an address from range 192.168.1.0/24 then the command below enables ospf on this interface so router can provide network information to the other ospf routers via this interface. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 @end group @end example Prefix length in interface must be equal or bigger (ie. smaller network) than prefix length in network statement. For example statement above doesn't enable ospf on interface with address 192.168.1.1/23, but it does on interface with address 192.168.1.129/25. Note that the behavior when there is a peer address defined on an interface changed after release 0.99.7. Currently, if a peer prefix has been configured, then we test whether the prefix in the network command contains the destination prefix. Otherwise, we test whether the network command prefix contains the local address prefix of the interface. @end deffn @node OSPF area @section OSPF area @deffn {OSPF Command} {area @var{a.b.c.d} range @var{a.b.c.d/m}} {} @deffnx {OSPF Command} {area <0-4294967295> range @var{a.b.c.d/m}} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} range @var{a.b.c.d/m}} {} @deffnx {OSPF Command} {no area <0-4294967295> range @var{a.b.c.d/m}} {} Summarize intra area paths from specified area into one Type-3 summary-LSA announced to other areas. This command can be used only in ABR and ONLY router-LSAs (Type-1) and network-LSAs (Type-2) (ie. LSAs with scope area) can be summarized. Type-5 AS-external-LSAs can't be summarized - their scope is AS. Summarizing Type-7 AS-external-LSAs isn't supported yet by Quagga. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 @end group @end example With configuration above one Type-3 Summary-LSA with routing info 10.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router or network LSA) from this range. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX not-advertise} {} Instead of summarizing intra area paths filter them - ie. intra area paths from this range are not advertised into other areas. This command makes sense in ABR only. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} range IPV4_PREFIX substitute IPV4_PREFIX} {} Substitute summarized prefix with another prefix. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 range 10.0.0.0/8 substitute 11.0.0.0/8 @end group @end example One Type-3 summary-LSA with routing info 11.0.0.0/8 is announced into backbone area if area 0.0.0.10 contains at least one intra-area network (ie. described with router-LSA or network-LSA) from range 10.0.0.0/8. This command makes sense in ABR only. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {} @deffnx {OSPF Command} {area <0-4294967295> virtual-link @var{a.b.c.d}} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} virtual-link @var{a.b.c.d}} {} @deffnx {OSPF Command} {no area <0-4294967295> virtual-link @var{a.b.c.d}} {} @anchor{OSPF virtual-link} @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} shortcut} {} @deffnx {OSPF Command} {area <0-4294967295> shortcut} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} shortcut} {} @deffnx {OSPF Command} {no area <0-4294967295> shortcut} {} Configure the area as Shortcut capable. See @cite{RFC3509}. This requires that the 'abr-type' be set to 'shortcut'. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} stub} {} @deffnx {OSPF Command} {area <0-4294967295> stub} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} stub} {} @deffnx {OSPF Command} {no area <0-4294967295> stub} {} Configure the area to be a stub area. That is, an area where no router originates routes external to OSPF and hence an area where all external routes are via the ABR(s). Hence, ABRs for such an area do not need to pass AS-External LSAs (type-5s) or ASBR-Summary LSAs (type-4) into the area. They need only pass Network-Summary (type-3) LSAs into such an area, along with a default-route summary. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} stub no-summary} {} @deffnx {OSPF Command} {area <0-4294967295> stub no-summary} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} stub no-summary} {} @deffnx {OSPF Command} {no area <0-4294967295> stub no-summary} {} Prevents an @command{ospfd} ABR from injecting inter-area summaries into the specified stub area. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} default-cost <0-16777215>} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} default-cost <0-16777215>} {} Set the cost of default-summary LSAs announced to stubby areas. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} export-list NAME} {} @deffnx {OSPF Command} {area <0-4294967295> export-list NAME} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} export-list NAME} {} @deffnx {OSPF Command} {no area <0-4294967295> export-list NAME} {} Filter Type-3 summary-LSAs announced to other areas originated from intra- area paths from specified area. @example @group router ospf network 192.168.1.0/24 area 0.0.0.0 network 10.0.0.0/8 area 0.0.0.10 area 0.0.0.10 export-list foo ! access-list foo permit 10.10.0.0/16 access-list foo deny any @end group @end example With example above any intra-area paths from area 0.0.0.10 and from range 10.10.0.0/16 (for example 10.10.1.0/24 and 10.10.2.128/30) are announced into other areas as Type-3 summary-LSA's, but any others (for example 10.11.0.0/16 or 10.128.30.16/30) aren't. This command is only relevant if the router is an ABR for the specified area. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} import-list NAME} {} @deffnx {OSPF Command} {area <0-4294967295> import-list NAME} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} import-list NAME} {} @deffnx {OSPF Command} {no area <0-4294967295> import-list NAME} {} Same as export-list, but it applies to paths announced into specified area as Type-3 summary-LSAs. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME in} {} @deffnx {OSPF Command} {area @var{a.b.c.d} filter-list prefix NAME out} {} @deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME in} {} @deffnx {OSPF Command} {area <0-4294967295> filter-list prefix NAME out} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME in} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} filter-list prefix NAME out} {} @deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME in} {} @deffnx {OSPF Command} {no area <0-4294967295> filter-list prefix NAME out} {} Filtering Type-3 summary-LSAs to/from area using prefix lists. This command makes sense in ABR only. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} authentication} {} @deffnx {OSPF Command} {area <0-4294967295> authentication} {} @deffnx {OSPF Command} {no area @var{a.b.c.d} authentication} {} @deffnx {OSPF Command} {no area <0-4294967295> authentication} {} Specify that simple password authentication should be used for the given area. @end deffn @deffn {OSPF Command} {area @var{a.b.c.d} authentication message-digest} {} @deffnx {OSPF Command} {area <0-4294967295> authentication message-digest} {} @anchor{area authentication message-digest}Specify that OSPF packets must be authenticated with MD5 HMACs within the given area. Keying material must also be configured on a per-interface basis (@pxref{ip ospf message-digest-key}). MD5 authentication may also be configured on a per-interface basis (@pxref{ip ospf authentication message-digest}). Such per-interface settings will override any per-area authentication setting. @end deffn @node OSPF interface @section OSPF interface @deffn {Interface Command} {ip ospf authentication-key @var{AUTH_KEY}} {} @deffnx {Interface Command} {no ip ospf authentication-key} {} Set OSPF authentication key to a simple password. After setting @var{AUTH_KEY}, all OSPF packets are authenticated. @var{AUTH_KEY} has length up to 8 chars. Simple text password authentication is insecure and deprecated in favour of MD5 HMAC authentication (@pxref{ip ospf authentication message-digest}). @end deffn @deffn {Interface Command} {ip ospf authentication message-digest} {} @anchor{ip ospf authentication message-digest}Specify that MD5 HMAC authentication must be used on this interface. MD5 keying material must also be configured (@pxref{ip ospf message-digest-key}). Overrides any authentication enabled on a per-area basis (@pxref{area authentication message-digest}). Note that OSPF MD5 authentication requires that time never go backwards (correct time is NOT important, only that it never goes backwards), even across resets, if ospfd is to be able to promptly reestabish adjacencies with its neighbours after restarts/reboots. The host should have system time be set at boot from an external or non-volatile source (eg battery backed clock, NTP, etc.) or else the system clock should be periodically saved to non-volative storage and restored at boot if MD5 authentication is to be expected to work reliably. @end deffn @deffn {Interface Command} {ip ospf message-digest-key KEYID md5 KEY} {} @deffnx {Interface Command} {no ip ospf message-digest-key} {} @anchor{ip ospf message-digest-key}Set OSPF authentication key to a cryptographic password. The cryptographic algorithm is MD5. KEYID identifies secret key used to create the message digest. This ID is part of the protocol and must be consistent across routers on a link. KEY is the actual message digest key, of up to 16 chars (larger strings will be truncated), and is associated with the given KEYID. @end deffn @deffn {Interface Command} {ip ospf cost <1-65535>} {} @deffnx {Interface Command} {no ip ospf cost} {} Set link cost for the specified interface. The cost value is set to router-LSA's metric field and used for SPF calculation. @end deffn @deffn {Interface Command} {ip ospf dead-interval <1-65535>} {} @deffnx {Interface Command} {ip ospf dead-interval minimal hello-multiplier <2-20>} {} @deffnx {Interface Command} {no ip ospf dead-interval} {} @anchor{ip ospf dead-interval minimal} Set number of seconds for RouterDeadInterval timer value used for Wait Timer and Inactivity Timer. This value must be the same for all routers attached to a common network. The default value is 40 seconds. If 'minimal' is specified instead, then the dead-interval is set to 1 second and one must specify a hello-multiplier. The hello-multiplier specifies how many Hellos to send per second, from 2 (every 500ms) to 20 (every 50ms). Thus one can have 1s convergence time for OSPF. If this form is specified, then the hello-interval advertised in Hello packets is set to 0 and the hello-interval on received Hello packets is not checked, thus the hello-multiplier need NOT be the same across multiple routers on a common link. @end deffn @deffn {Interface Command} {ip ospf hello-interval <1-65535>} {} @deffnx {Interface Command} {no ip ospf hello-interval} {} Set number of seconds for HelloInterval timer value. Setting this value, Hello packet will be sent every timer value seconds on the specified interface. This value must be the same for all routers attached to a common network. The default value is 10 seconds. This command has no effect if @ref{ip ospf dead-interval minimal} is also specified for the interface. @end deffn @deffn {Interface Command} {ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)} {} @deffnx {Interface Command} {no ip ospf network} {} Set explicitly network type for specifed interface. @end deffn @deffn {Interface Command} {ip ospf priority <0-255>} {} @deffnx {Interface Command} {no ip ospf priority} {} Set RouterPriority integer value. The router with the highest priority will be more eligible to become Designated Router. Setting the value to 0, makes the router ineligible to become Designated Router. The default value is 1. @end deffn @deffn {Interface Command} {ip ospf retransmit-interval <1-65535>} {} @deffnx {Interface Command} {no ip ospf retransmit interval} {} Set number of seconds for RxmtInterval timer value. This value is used when retransmitting Database Description and Link State Request packets. The default value is 5 seconds. @end deffn @deffn {Interface Command} {ip ospf transmit-delay} {} @deffnx {Interface Command} {no ip ospf transmit-delay} {} Set number of seconds for InfTransDelay value. LSAs' age should be incremented by this value when transmitting. The default value is 1 seconds. @end deffn @node Redistribute routes to OSPF @section Redistribute routes to OSPF @deffn {OSPF Command} {redistribute (kernel|connected|static|rip|bgp)} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) @var{route-map}} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2)} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) route-map @var{word}} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214>} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric <0-16777214> route-map @var{word}} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214>} {} @deffnx {OSPF Command} {redistribute (kernel|connected|static|rip|bgp) metric-type (1|2) metric <0-16777214> route-map @var{word}} {} @deffnx {OSPF Command} {no redistribute (kernel|connected|static|rip|bgp)} {} @anchor{OSPF redistribute}Redistribute routes of the specified protocol or kind into OSPF, with the metric type and metric set if specified, filtering the routes using the given route-map if specified. Redistributed routes may also be filtered with distribute-lists, see @ref{ospf distribute-list}. Redistributed routes are distributed as into OSPF as Type-5 External LSAs into links to areas that accept external routes, Type-7 External LSAs for NSSA areas and are not redistributed at all into Stub areas, where external routes are not permitted. Note that for connected routes, one may instead use @dfn{passive-interface}, see @ref{OSPF passive-interface}. @end deffn @deffn {OSPF Command} {default-information originate} {} @deffnx {OSPF Command} {default-information originate metric <0-16777214>} {} @deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2)} {} @deffnx {OSPF Command} {default-information originate metric <0-16777214> metric-type (1|2) route-map @var{word}} {} @deffnx {OSPF Command} {default-information originate always} {} @deffnx {OSPF Command} {default-information originate always metric <0-16777214>} {} @deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2)} {} @deffnx {OSPF Command} {default-information originate always metric <0-16777214> metric-type (1|2) route-map @var{word}} {} @deffnx {OSPF Command} {no default-information originate} {} Originate an AS-External (type-5) LSA describing a default route into all external-routing capable areas, of the specified metric and metric type. If the 'always' keyword is given then the default is always advertised, even when there is no default present in the routing table. @end deffn @deffn {OSPF Command} {distribute-list NAME out (kernel|connected|static|rip|ospf} {} @deffnx {OSPF Command} {no distribute-list NAME out (kernel|connected|static|rip|ospf} {} @anchor{ospf distribute-list}Apply the access-list filter, NAME, to redistributed routes of the given type before allowing the routes to redistributed into OSPF (@pxref{OSPF redistribute}). @end deffn @deffn {OSPF Command} {default-metric <0-16777214>} {} @deffnx {OSPF Command} {no default-metric} {} @end deffn @deffn {OSPF Command} {distance <1-255>} {} @deffnx {OSPF Command} {no distance <1-255>} {} @end deffn @deffn {OSPF Command} {distance ospf (intra-area|inter-area|external) <1-255>} {} @deffnx {OSPF Command} {no distance ospf} {} @end deffn @node Showing OSPF information @section Showing OSPF information @deffn {Command} {show ip ospf} {} @anchor{show ip ospf}Show information on a variety of general OSPF and area state and configuration information. @end deffn @deffn {Command} {show ip ospf interface [INTERFACE]} {} Show state and configuration of OSPF the specified interface, or all interfaces if no interface is given. @end deffn @deffn {Command} {show ip ospf neighbor} {} @deffnx {Command} {show ip ospf neighbor INTERFACE} {} @deffnx {Command} {show ip ospf neighbor detail} {} @deffnx {Command} {show ip ospf neighbor INTERFACE detail} {} @end deffn @deffn {Command} {show ip ospf database} {} @end deffn @deffn {Command} {show ip ospf database (asbr-summary|external|network|router|summary)} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) adv-router @var{adv-router}} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) @var{link-state-id} self-originate} {} @deffnx {Command} {show ip ospf database (asbr-summary|external|network|router|summary) self-originate} {} @end deffn @deffn {Command} {show ip ospf database max-age} {} @end deffn @deffn {Command} {show ip ospf database self-originate} {} @end deffn @deffn {Command} {show ip ospf route} {} Show the OSPF routing table, as determined by the most recent SPF calculation. @end deffn @node Debugging OSPF @section Debugging OSPF @deffn {Command} {debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} @deffnx {Command} {no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]} {} @end deffn @deffn {Command} {debug ospf ism} {} @deffnx {Command} {debug ospf ism (status|events|timers)} {} @deffnx {Command} {no debug ospf ism} {} @deffnx {Command} {no debug ospf ism (status|events|timers)} {} @end deffn @deffn {Command} {debug ospf nsm} {} @deffnx {Command} {debug ospf nsm (status|events|timers)} {} @deffnx {Command} {no debug ospf nsm} {} @deffnx {Command} {no debug ospf nsm (status|events|timers)} {} @end deffn @deffn {Command} {debug ospf lsa} {} @deffnx {Command} {debug ospf lsa (generate|flooding|refresh)} {} @deffnx {Command} {no debug ospf lsa} {} @deffnx {Command} {no debug ospf lsa (generate|flooding|refresh)} {} @end deffn @deffn {Command} {debug ospf zebra} {} @deffnx {Command} {debug ospf zebra (interface|redistribute)} {} @deffnx {Command} {no debug ospf zebra} {} @deffnx {Command} {no debug ospf zebra (interface|redistribute)} {} @end deffn @deffn {Command} {show debugging ospf} {} @end deffn @node OSPF Configuration Examples @section OSPF Configuration Examples A simple example, with MD5 authentication enabled: @example @group ! interface bge0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! router ospf network 192.168.0.0/16 area 0.0.0.1 area 0.0.0.1 authentication message-digest @end group @end example An @acronym{ABR} router, with MD5 authentication and performing summarisation of networks between the areas: @example @group ! password ABCDEF log file /var/log/quagga/ospfd.log service advanced-vty ! interface eth0 ip ospf authentication message-digest ip ospf message-digest-key 1 md5 ABCDEFGHIJK ! interface ppp0 ! interface br0 ip ospf authentication message-digest ip ospf message-digest-key 2 md5 XYZ12345 ! router ospf ospf router-id 192.168.0.1 redistribute connected passive interface ppp0 network 192.168.0.0/24 area 0.0.0.0 network 10.0.0.0/16 area 0.0.0.0 network 192.168.1.0/24 area 0.0.0.1 area 0.0.0.0 authentication message-digest area 0.0.0.0 range 10.0.0.0/16 area 0.0.0.0 range 192.168.0.0/24 area 0.0.0.1 authentication message-digest area 0.0.0.1 range 10.2.0.0/16 ! @end group @end example quagga-0.99.24.1/doc/ospf6d.texi0000644000175000017500000001267412476520570013107 00000000000000@node OSPFv3 @chapter OSPFv3 @command{ospf6d} is a daemon support OSPF version 3 for IPv6 network. OSPF for IPv6 is described in RFC2740. @menu * OSPF6 router:: * OSPF6 area:: * OSPF6 interface:: * Redistribute routes to OSPF6:: * Showing OSPF6 information:: * OSPF6 Configuration Examples:: @end menu @node OSPF6 router @section OSPF6 router @deffn {Command} {router ospf6} {} @end deffn @deffn {OSPF6 Command} {router-id @var{a.b.c.d}} {} Set router's Router-ID. @end deffn @deffn {OSPF6 Command} {interface @var{ifname} area @var{area}} {} Bind interface to specified area, and start sending OSPF packets. @var{area} can be specified as 0. @end deffn @deffn {OSPF6 Command} {timers throttle spf @var{delay} @var{initial-holdtime} @var{max-holdtime}} {} @deffnx {OSPF6 Command} {no timers throttle spf} {} This command sets the initial @var{delay}, the @var{initial-holdtime} and the @var{maximum-holdtime} between when SPF is calculated and the event which triggered the calculation. The times are specified in milliseconds and must be in the range of 0 to 600000 milliseconds. The @var{delay} specifies the minimum amount of time to delay SPF calculation (hence it affects how long SPF calculation is delayed after an event which occurs outside of the holdtime of any previous SPF calculation, and also serves as a minimum holdtime). Consecutive SPF calculations will always be seperated by at least 'hold-time' milliseconds. The hold-time is adaptive and initially is set to the @var{initial-holdtime} configured with the above command. Events which occur within the holdtime of the previous SPF calculation will cause the holdtime to be increased by @var{initial-holdtime}, bounded by the @var{maximum-holdtime} configured with this command. If the adaptive hold-time elapses without any SPF-triggering event occuring then the current holdtime is reset to the @var{initial-holdtime}. @example @group router ospf6 timers throttle spf 200 400 10000 @end group @end example In this example, the @var{delay} is set to 200ms, the @var{initial holdtime} is set to 400ms and the @var{maximum holdtime} to 10s. Hence there will always be at least 200ms between an event which requires SPF calculation and the actual SPF calculation. Further consecutive SPF calculations will always be seperated by between 400ms to 10s, the hold-time increasing by 400ms each time an SPF-triggering event occurs within the hold-time of the previous SPF calculation. @end deffn @deffn {OSPF6 Command} {auto-cost reference-bandwidth @var{cost}} {} @deffnx {OSPF6 Command} {no auto-cost reference-bandwidth} {} This sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. @end deffn @node OSPF6 area @section OSPF6 area Area support for OSPFv3 is not yet implemented. @node OSPF6 interface @section OSPF6 interface @deffn {Interface Command} {ipv6 ospf6 cost COST} {} Sets interface's output cost. Default value depends on the interface bandwidth and on the auto-cost reference bandwidth. @end deffn @deffn {Interface Command} {ipv6 ospf6 hello-interval HELLOINTERVAL} {} Sets interface's Hello Interval. Default 40 @end deffn @deffn {Interface Command} {ipv6 ospf6 dead-interval DEADINTERVAL} {} Sets interface's Router Dead Interval. Default value is 40. @end deffn @deffn {Interface Command} {ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL} {} Sets interface's Rxmt Interval. Default value is 5. @end deffn @deffn {Interface Command} {ipv6 ospf6 priority PRIORITY} {} Sets interface's Router Priority. Default value is 1. @end deffn @deffn {Interface Command} {ipv6 ospf6 transmit-delay TRANSMITDELAY} {} Sets interface's Inf-Trans-Delay. Default value is 1. @end deffn @deffn {Interface Command} {ipv6 ospf6 network (broadcast|point-to-point)} {} Set explicitly network type for specifed interface. @end deffn @node Redistribute routes to OSPF6 @section Redistribute routes to OSPF6 @deffn {OSPF6 Command} {redistribute static} {} @deffnx {OSPF6 Command} {redistribute connected} {} @deffnx {OSPF6 Command} {redistribute ripng} {} @end deffn @node Showing OSPF6 information @section Showing OSPF6 information @deffn {Command} {show ipv6 ospf6 [INSTANCE_ID]} {} INSTANCE_ID is an optional OSPF instance ID. To see router ID and OSPF instance ID, simply type "show ipv6 ospf6 ". @end deffn @deffn {Command} {show ipv6 ospf6 database} {} This command shows LSA database summary. You can specify the type of LSA. @end deffn @deffn {Command} {show ipv6 ospf6 interface} {} To see OSPF interface configuration like costs. @end deffn @deffn {Command} {show ipv6 ospf6 neighbor} {} Shows state and chosen (Backup) DR of neighbor. @end deffn @deffn {Command} {show ipv6 ospf6 request-list A.B.C.D} {} Shows requestlist of neighbor. @end deffn @deffn {Command} {show ipv6 route ospf6} {} This command shows internal routing table. @end deffn @node OSPF6 Configuration Examples @section OSPF6 Configuration Examples Example of ospf6d configured on one interface and area: @example interface eth0 ipv6 ospf6 instance-id 0 ! router ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! @end example quagga-0.99.24.1/doc/main.texi0000644000175000017500000003336012476520570012625 00000000000000@node Zebra @chapter Zebra @c SYNOPSIS @command{zebra} is an IP routing manager. It provides kernel routing table updates, interface lookups, and redistribution of routes between different routing protocols. @menu * Invoking zebra:: Running the program * Interface Commands:: Commands for zebra interfaces * Static Route Commands:: Commands for adding static routes * Multicast RIB Commands:: Commands for controlling MRIB behavior * zebra Route Filtering:: Commands for zebra route filtering * zebra FIB push interface:: Interface to optional FPM component * zebra Terminal Mode Commands:: Commands for zebra's VTY @end menu @node Invoking zebra @section Invoking zebra Besides the common invocation options (@pxref{Common Invocation Options}), the @command{zebra} specific invocation options are listed below. @table @samp @item -b @itemx --batch Runs in batch mode. @command{zebra} parses configuration file and terminates immediately. @item -k @itemx --keep_kernel When zebra starts up, don't delete old self inserted routes. @item -r @itemx --retain When program terminates, retain routes added by zebra. @end table @node Interface Commands @section Interface Commands @deffn Command {interface @var{ifname}} {} @end deffn @deffn {Interface Command} {shutdown} {} @deffnx {Interface Command} {no shutdown} {} Up or down the current interface. @end deffn @deffn {Interface Command} {ip address @var{address/prefix}} {} @deffnx {Interface Command} {ipv6 address @var{address/prefix}} {} @deffnx {Interface Command} {no ip address @var{address/prefix}} {} @deffnx {Interface Command} {no ipv6 address @var{address/prefix}} {} Set the IPv4 or IPv6 address/prefix for the interface. @end deffn @deffn {Interface Command} {ip address @var{address/prefix} secondary} {} @deffnx {Interface Command} {no ip address @var{address/prefix} secondary} {} Set the secondary flag for this address. This causes ospfd to not treat the address as a distinct subnet. @end deffn @deffn {Interface Command} {description @var{description} ...} {} Set description for the interface. @end deffn @deffn {Interface Command} {multicast} {} @deffnx {Interface Command} {no multicast} {} Enable or disables multicast flag for the interface. @end deffn @deffn {Interface Command} {bandwidth <1-10000000>} {} @deffnx {Interface Command} {no bandwidth <1-10000000>} {} Set bandwidth value of the interface in kilobits/sec. This is for calculating OSPF cost. This command does not affect the actual device configuration. @end deffn @deffn {Interface Command} {link-detect} {} @deffnx {Interface Command} {no link-detect} {} Enable/disable link-detect on platforms which support this. Currently only Linux and Solaris, and only where network interface drivers support reporting link-state via the IFF_RUNNING flag. @end deffn @node Static Route Commands @section Static Route Commands Static routing is a very fundamental feature of routing technology. It defines static prefix and gateway. @deffn Command {ip route @var{network} @var{gateway}} {} @var{network} is destination prefix with format of A.B.C.D/M. @var{gateway} is gateway for the prefix. When @var{gateway} is A.B.C.D format. It is taken as a IPv4 address gateway. Otherwise it is treated as an interface name. If the interface name is @var{null0} then zebra installs a blackhole route. @example ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 ppp0 ip route 10.0.0.0/8 null0 @end example First example defines 10.0.0.0/8 static route with gateway 10.0.0.2. Second one defines the same prefix but with gateway to interface ppp0. The third install a blackhole route. @end deffn @deffn Command {ip route @var{network} @var{netmask} @var{gateway}} {} This is alternate version of above command. When @var{network} is A.B.C.D format, user must define @var{netmask} value with A.B.C.D format. @var{gateway} is same option as above command @example ip route 10.0.0.0 255.255.255.0 10.0.0.2 ip route 10.0.0.0 255.255.255.0 ppp0 ip route 10.0.0.0 255.255.255.0 null0 @end example These statements are equivalent to those in the previous example. @end deffn @deffn Command {ip route @var{network} @var{gateway} @var{distance}} {} Installs the route with the specified distance. @end deffn Multiple nexthop static route @example ip route 10.0.0.1/32 10.0.0.2 ip route 10.0.0.1/32 10.0.0.3 ip route 10.0.0.1/32 eth0 @end example If there is no route to 10.0.0.2 and 10.0.0.3, and interface eth0 is reachable, then the last route is installed into the kernel. If zebra has been compiled with multipath support, and both 10.0.0.2 and 10.0.0.3 are reachable, zebra will install a multipath route via both nexthops, if the platform supports this. @example zebra> show ip route S> 10.0.0.1/32 [1/0] via 10.0.0.2 inactive via 10.0.0.3 inactive * is directly connected, eth0 @end example @example ip route 10.0.0.0/8 10.0.0.2 ip route 10.0.0.0/8 10.0.0.3 ip route 10.0.0.0/8 null0 255 @end example This will install a multihop route via the specified next-hops if they are reachable, as well as a high-metric blackhole route, which can be useful to prevent traffic destined for a prefix to match less-specific routes (eg default) should the specified gateways not be reachable. Eg: @example zebra> show ip route 10.0.0.0/8 Routing entry for 10.0.0.0/8 Known via "static", distance 1, metric 0 10.0.0.2 inactive 10.0.0.3 inactive Routing entry for 10.0.0.0/8 Known via "static", distance 255, metric 0 directly connected, Null0 @end example @deffn Command {ipv6 route @var{network} @var{gateway}} {} @deffnx Command {ipv6 route @var{network} @var{gateway} @var{distance}} {} These behave similarly to their ipv4 counterparts. @end deffn @deffn Command {table @var{tableno}} {} Select the primary kernel routing table to be used. This only works for kernels supporting multiple routing tables (like GNU/Linux 2.2.x and later). After setting @var{tableno} with this command, static routes defined after this are added to the specified table. @end deffn @node Multicast RIB Commands @section Multicast RIB Commands The Multicast RIB provides a separate table of unicast destinations which is used for Multicast Reverse Path Forwarding decisions. It is used with a multicast source's IP address, hence contains not multicast group addresses but unicast addresses. This table is fully separate from the default unicast table. However, RPF lookup can include the unicast table. WARNING: RPF lookup results are non-responsive in this version of Quagga, i.e. multicast routing does not actively react to changes in underlying unicast topology! @deffn Command {ip multicast rpf-lookup-mode @var{mode}} {} @deffnx Command {no ip multicast rpf-lookup-mode [@var{mode}]} {} @var{mode} sets the method used to perform RPF lookups. Supported modes: @table @samp @item urib-only Performs the lookup on the Unicast RIB. The Multicast RIB is never used. @item mrib-only Performs the lookup on the Multicast RIB. The Unicast RIB is never used. @item mrib-then-urib Tries to perform the lookup on the Multicast RIB. If any route is found, that route is used. Otherwise, the Unicast RIB is tried. @item lower-distance Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the lower administrative distance is used; if they're equal, the Multicast RIB takes precedence. @item longer-prefix Performs a lookup on the Multicast RIB and Unicast RIB each. The result with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. @end table The @code{mrib-then-urib} setting is the default behavior if nothing is configured. If this is the desired behavior, it should be explicitly configured to make the configuration immune against possible changes in what the default behavior is. WARNING: Unreachable routes do not receive special treatment and do not cause fallback to a second lookup. @end deffn @deffn Command {show ip rpf @var{addr}} {} Performs a Multicast RPF lookup, as configured with @command{ip multicast rpf-lookup-mode @var{mode}}. @var{addr} specifies the multicast source address to look up. @example > show ip rpf 192.0.2.1 Routing entry for 192.0.2.0/24 using Unicast RIB Known via "kernel", distance 0, metric 0, best * 198.51.100.1, via eth0 @end example Indicates that a multicast source lookup for 192.0.2.1 would use an Unicast RIB entry for 192.0.2.0/24 with a gateway of 198.51.100.1. @end deffn @deffn Command {show ip rpf} {} Prints the entire Multicast RIB. Note that this is independent of the configured RPF lookup mode, the Multicast RIB may be printed yet not used at all. @end deffn @deffn Command {ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} @deffnx Command {no ip mroute @var{prefix} @var{nexthop} [@var{distance}]} {} Adds a static route entry to the Multicast RIB. This performs exactly as the @command{ip route} command, except that it inserts the route in the Multicast RIB instead of the Unicast RIB. @end deffn @node zebra Route Filtering @section zebra Route Filtering Zebra supports @command{prefix-list} and @command{route-map} to match routes received from other quagga components. The @command{permit}/@command{deny} facilities provided by these commands can be used to filter which routes zebra will install in the kernel. @deffn Command {ip protocol @var{protocol} route-map @var{routemap}} {} Apply a route-map filter to routes for the specified protocol. @var{protocol} can be @b{any} or one of @b{system}, @b{kernel}, @b{connected}, @b{static}, @b{rip}, @b{ripng}, @b{ospf}, @b{ospf6}, @b{isis}, @b{bgp}, @b{hsls}. @end deffn @deffn {Route Map} {set src @var{address}} Within a route-map, set the preferred source address for matching routes when installing in the kernel. @end deffn @example The following creates a prefix-list that matches all addresses, a route-map that sets the preferred source address, and applies the route-map to all @command{rip} routes. @group ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 match ip address prefix-list ANY set src 10.0.0.1 ip protocol rip route-map RM1 @end group @end example @node zebra FIB push interface @section zebra FIB push interface Zebra supports a 'FIB push' interface that allows an external component to learn the forwarding information computed by the Quagga routing suite. In Quagga, the Routing Information Base (RIB) resides inside zebra. Routing protocols communicate their best routes to zebra, and zebra computes the best route across protocols for each prefix. This latter information makes up the Forwarding Information Base (FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in the kernel to forward packets according to the routes computed by Quagga. The kernel FIB is updated in an OS-specific way. For example, the @code{netlink} interface is used on Linux, and route sockets are used on FreeBSD. The FIB push interface aims to provide a cross-platform mechanism to support scenarios where the router has a forwarding path that is distinct from the kernel, commonly a hardware-based fast path. In these cases, the FIB needs to be maintained reliably in the fast path as well. We refer to the component that programs the forwarding plane (directly or indirectly) as the Forwarding Plane Manager or FPM. The FIB push interface comprises of a TCP connection between zebra and the FPM. The connection is initiated by zebra -- that is, the FPM acts as the TCP server. The relevant zebra code kicks in when zebra is configured with the @code{--enable-fpm} flag. Zebra periodically attempts to connect to the well-known FPM port. Once the connection is up, zebra starts sending messages containing routes over the socket to the FPM. Zebra sends a complete copy of the forwarding table to the FPM, including routes that it may have picked up from the kernel. The existing interaction of zebra with the kernel remains unchanged -- that is, the kernel continues to receive FIB updates as before. The format of the messages exchanged with the FPM is defined by the file @file{fpm/fpm.h} in the quagga tree. The zebra FPM interface uses replace semantics. That is, if a 'route add' message for a prefix is followed by another 'route add' message, the information in the second message is complete by itself, and replaces the information sent in the first message. If the connection to the FPM goes down for some reason, zebra sends the FPM a complete copy of the forwarding table(s) when it reconnects. @node zebra Terminal Mode Commands @section zebra Terminal Mode Commands @deffn Command {show ip route} {} Display current routes which zebra holds in its database. @example @group Router# show ip route Codes: K - kernel route, C - connected, S - static, R - RIP, B - BGP * - FIB route. K* 0.0.0.0/0 203.181.89.241 S 0.0.0.0/0 203.181.89.1 C* 127.0.0.0/8 lo C* 203.181.89.240/28 eth0 @end group @end example @end deffn @deffn Command {show ipv6 route} {} @end deffn @deffn Command {show interface} {} @end deffn @deffn Command {show ip prefix-list [@var{name}]} {} @end deffn @deffn Command {show route-map [@var{name}]} {} @end deffn @deffn Command {show ip protocol} {} @end deffn @deffn Command {show ipforward} {} Display whether the host's IP forwarding function is enabled or not. Almost any UNIX kernel can be configured with IP forwarding disabled. If so, the box can't work as a router. @end deffn @deffn Command {show ipv6forward} {} Display whether the host's IP v6 forwarding is enabled or not. @end deffn @deffn Command {show zebra fpm stats} {} Display statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. @end deffn @deffn Command {clear zebra fpm stats} {} Reset statistics related to the zebra code that interacts with the optional Forwarding Plane Manager (FPM) component. @end deffn quagga-0.99.24.1/doc/kernel.texi0000644000175000017500000000343212476520570013156 00000000000000@node Kernel Interface @chapter Kernel Interface There are several different methods for reading kernel routing table information, updating kernel routing tables, and for looking up interfaces. @table @samp @item ioctl The @samp{ioctl} method is a very traditional way for reading or writing kernel information. @samp{ioctl} can be used for looking up interfaces and for modifying interface addresses, flags, mtu settings and other types of information. Also, @samp{ioctl} can insert and delete kernel routing table entries. It will soon be available on almost any platform which zebra supports, but it is a little bit ugly thus far, so if a better method is supported by the kernel, zebra will use that. @item sysctl @samp{sysctl} can lookup kernel information using MIB (Management Information Base) syntax. Normally, it only provides a way of getting information from the kernel. So one would usually want to change kernel information using another method such as @samp{ioctl}. @item proc filesystem @samp{proc filesystem} provides an easy way of getting kernel information. @item routing socket @item netlink On recent Linux kernels (2.0.x and 2.2.x), there is a kernel/user communication support called @code{netlink}. It makes asynchronous communication between kernel and Quagga possible, similar to a routing socket on BSD systems. Before you use this feature, be sure to select (in kernel configuration) the kernel/netlink support option 'Kernel/User network link driver' and 'Routing messages'. Today, the /dev/route special device file is obsolete. Netlink communication is done by reading/writing over netlink socket. After the kernel configuration, please reconfigure and rebuild Quagga. You can use netlink as a dynamic routing update channel between Quagga and the kernel. @end table quagga-0.99.24.1/doc/ipv6.texi0000644000175000017500000001536212476520570012567 00000000000000@node IPv6 Support @chapter IPv6 Support Quagga fully supports IPv6 routing. As described so far, Quagga supports RIPng, OSPFv3, Babel and BGP-4+. You can give IPv6 addresses to an interface and configure static IPv6 routing information. Quagga IPv6 also provides automatic address configuration via a feature called @code{address auto configuration}. To do it, the router must send router advertisement messages to the all nodes that exist on the network. @menu * Router Advertisement:: @end menu @node Router Advertisement @section Router Advertisement @deffn {Interface Command} {no ipv6 nd suppress-ra} {} Send router advertisment messages. @end deffn @deffn {Interface Command} {ipv6 nd suppress-ra} {} Don't send router advertisment messages. @end deffn @deffn {Interface Command} {ipv6 nd prefix @var{ipv6prefix} [@var{valid-lifetime}] [@var{preferred-lifetime}] [off-link] [no-autoconfig] [router-address]} {} Configuring the IPv6 prefix to include in router advertisements. Several prefix specific optional parameters and flags may follow: @itemize @bullet @item @var{valid-lifetime} - the length of time in seconds during what the prefix is valid for the purpose of on-link determination. Value @var{infinite} represents infinity (i.e. a value of all one bits (@code{0xffffffff})). Range: @code{<0-4294967295>} Default: @code{2592000} @item @var{preferred-lifetime} - the length of time in seconds during what addresses generated from the prefix remain preferred. Value @var{infinite} represents infinity. Range: @code{<0-4294967295>} Default: @code{604800} @item @var{off-link} - indicates that advertisement makes no statement about on-link or off-link properties of the prefix. Default: not set, i.e. this prefix can be used for on-link determination. @item @var{no-autoconfig} - indicates to hosts on the local link that the specified prefix cannot be used for IPv6 autoconfiguration. Default: not set, i.e. prefix can be used for autoconfiguration. @item @var{router-address} - indicates to hosts on the local link that the specified prefix contains a complete IP address by setting R flag. Default: not set, i.e. hosts do not assume a complete IP address is placed. @end itemize @end deffn @deffn {Interface Command} {ipv6 nd ra-interval <1-1800>} {} @deffnx {Interface Command} {no ipv6 nd ra-interval [<1-1800>]} {} The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in seconds. Default: @code{600} @end deffn @deffn {Interface Command} {ipv6 nd ra-interval msec <70-1800000>} {} @deffnx {Interface Command} {no ipv6 nd ra-interval [msec <70-1800000>]} {} The maximum time allowed between sending unsolicited multicast router advertisements from the interface, in milliseconds. Default: @code{600000} @end deffn @deffn {Interface Command} {ipv6 nd ra-lifetime <0-9000>} {} @deffnx {Interface Command} {no ipv6 nd ra-lifetime [<0-9000>]} {} The value to be placed in the Router Lifetime field of router advertisements sent from the interface, in seconds. Indicates the usefulness of the router as a default router on this interface. Setting the value to zero indicates that the router should not be considered a default router on this interface. Must be either zero or between value specified with @var{ipv6 nd ra-interval} (or default) and 9000 seconds. Default: @code{1800} @end deffn @deffn {Interface Command} {ipv6 nd reachable-time <1-3600000>} {} @deffnx {Interface Command} {no ipv6 nd reachable-time [<1-3600000>]} {} The value to be placed in the Reachable Time field in the Router Advertisement messages sent by the router, in milliseconds. The configured time enables the router to detect unavailable neighbors. The value zero means unspecified (by this router). Default: @code{0} @end deffn @deffn {Interface Command} {ipv6 nd managed-config-flag} {} @deffnx {Interface Command} {no ipv6 nd managed-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use managed (stateful) protocol for addresses autoconfiguration in addition to any addresses autoconfigured using stateless address autoconfiguration. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd other-config-flag} {} @deffnx {Interface Command} {no ipv6 nd other-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that they should use administered (stateful) protocol to obtain autoconfiguration information other than addresses. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd home-agent-config-flag} {} @deffnx {Interface Command} {no ipv6 nd home-agent-config-flag} {} Set/unset flag in IPv6 router advertisements which indicates to hosts that the router acts as a Home Agent and includes a Home Agent Option. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd home-agent-preference <0-65535>} {} @deffnx {Interface Command} {no ipv6 nd home-agent-preference [<0-65535>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent preference. The default value of 0 stands for the lowest preference possible. Default: 0 @end deffn @deffn {Interface Command} {ipv6 nd home-agent-lifetime <0-65520>} {} @deffnx {Interface Command} {no ipv6 nd home-agent-lifetime [<0-65520>]} {} The value to be placed in Home Agent Option, when Home Agent config flag is set, which indicates to hosts Home Agent Lifetime. The default value of 0 means to place the current Router Lifetime value. Default: 0 @end deffn @deffn {Interface Command} {ipv6 nd adv-interval-option} {} @deffnx {Interface Command} {no ipv6 nd adv-interval-option} {} Include an Advertisement Interval option which indicates to hosts the maximum time, in milliseconds, between successive unsolicited Router Advertisements. Default: not set @end deffn @deffn {Interface Command} {ipv6 nd router-preference (high|medium|low)} {} @deffnx {Interface Command} {no ipv6 nd router-preference [(high|medium|low)]} {} Set default router preference in IPv6 router advertisements per RFC4191. Default: medium @end deffn @deffn {Interface Command} {ipv6 nd mtu <1-65535>} {} @deffnx {Interface Command} {no ipv6 nd mtu [<1-65535>]} {} Include an MTU (type 5) option in each RA packet to assist the attached hosts in proper interface configuration. The announced value is not verified to be consistent with router interface MTU. Default: don't advertise any MTU option @end deffn @example @group interface eth0 no ipv6 nd suppress-ra ipv6 nd prefix 2001:0DB8:5009::/64 @end group @end example For more information see @cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)} , @cite{RFC4861 (Neighbor Discovery for IP Version 6 (IPv6))} , @cite{RFC6275 (Mobility Support in IPv6)} and @cite{RFC4191 (Default Router Preferences and More-Specific Routes)}. quagga-0.99.24.1/doc/install.texi0000644000175000017500000002332112476520570013343 00000000000000@node Installation @chapter Installation @cindex How to install Quagga @cindex Installation @cindex Installing Quagga @cindex Building the system @cindex Making Quagga There are three steps for installing the software: configuration, compilation, and installation. @menu * Configure the Software:: * Build the Software:: * Install the Software:: @end menu The easiest way to get Quagga running is to issue the following commands: @example % configure % make % make install @end example @node Configure the Software @section Configure the Software @menu * The Configure script and its options:: * Least-Privilege support:: * Linux notes:: @end menu @node The Configure script and its options @subsection The Configure script and its options @cindex Configuration options @cindex Options for configuring @cindex Build options @cindex Distribution configuration @cindex Options to @code{./configure} Quagga has an excellent configure script which automatically detects most host configurations. There are several additional configure options you can use to turn off IPv6 support, to disable the compilation of specific daemons, and to enable SNMP support. @table @option @item --disable-ipv6 Turn off IPv6 related features and daemons. Quagga configure script automatically detects IPv6 stack. But sometimes you might want to disable IPv6 support of Quagga. @item --disable-zebra Do not build zebra daemon. @item --disable-ripd Do not build ripd. @item --disable-ripngd Do not build ripngd. @item --disable-ospfd Do not build ospfd. @item --disable-ospf6d Do not build ospf6d. @item --disable-bgpd Do not build bgpd. @item --disable-bgp-announce Make @command{bgpd} which does not make bgp announcements at all. This feature is good for using @command{bgpd} as a BGP announcement listener. @item --enable-netlink Force to enable @sc{gnu}/Linux netlink interface. Quagga configure script detects netlink interface by checking a header file. When the header file does not match to the current running kernel, configure script will not turn on netlink support. @item --enable-snmp Enable SNMP support. By default, SNMP support is disabled. @item --disable-opaque-lsa Disable support for Opaque LSAs (RFC2370) in ospfd. @item --disable-ospfapi Disable support for OSPF-API, an API to interface directly with ospfd. OSPF-API is enabled if --enable-opaque-lsa is set. @item --disable-ospfclient Disable building of the example OSPF-API client. @item --disable-ospf-te Disable support for OSPF Traffic Engineering Extension (internet-draft) this requires support for Opaque LSAs. @item --enable-multipath=@var{ARG} Enable support for Equal Cost Multipath. @var{ARG} is the maximum number of ECMP paths to allow, set to 0 to allow unlimited number of paths. @item --disable-rtadv Disable support IPV6 router advertisement in zebra. @item --enable-gcc-rdynamic Pass the @command{-rdynamic} option to the linker driver. This is in most cases neccessary for getting usable backtraces. This option defaults to on if the compiler is detected as gcc, but giving an explicit enable/disable is suggested. @item --enable-backtrace Controls backtrace support for the crash handlers. This is autodetected by default. Using the switch will enforce the requested behaviour, failing with an error if support is requested but not available. On BSD systems, this needs libexecinfo, while on glibc support for this is part of libc itself. @end table You may specify any combination of the above options to the configure script. By default, the executables are placed in @file{/usr/local/sbin} and the configuration files in @file{/usr/local/etc}. The @file{/usr/local/} installation prefix and other directories may be changed using the following options to the configuration script. @table @option @item --prefix=@var{prefix} Install architecture-independent files in @var{prefix} [/usr/local]. @item --sysconfdir=@var{dir} Look for configuration files in @var{dir} [@var{prefix}/etc]. Note that sample configuration files will be installed here. @item --localstatedir=@var{dir} Configure zebra to use @var{dir} for local state files, such as pid files and unix sockets. @end table @example % ./configure --disable-ipv6 @end example This command will configure zebra and the routing daemons. @node Least-Privilege support @subsection Least-Privilege support @cindex Quagga Least-Privileges @cindex Quagga Privileges Additionally, you may configure zebra to drop its elevated privileges shortly after startup and switch to another user. The configure script will automatically try to configure this support. There are three configure options to control the behaviour of Quagga daemons. @table @option @item --enable-user=@var{user} Switch to user @var{ARG} shortly after startup, and run as user @var{ARG} in normal operation. @item --enable-group=@var{group} Switch real and effective group to @var{group} shortly after startup. @item --enable-vty-group=@var{group} Create Unix Vty sockets (for use with vtysh) with group owndership set to @var{group}. This allows one to create a seperate group which is restricted to accessing only the Vty sockets, hence allowing one to delegate this group to individual users, or to run vtysh setgid to this group. @end table The default user and group which will be configured is 'quagga' if no user or group is specified. Note that this user or group requires write access to the local state directory (see --localstatedir) and requires at least read access, and write access if you wish to allow daemons to write out their configuration, to the configuration directory (see --sysconfdir). On systems which have the 'libcap' capabilities manipulation library (currently only linux), the quagga system will retain only minimal capabilities required, further it will only raise these capabilities for brief periods. On systems without libcap, quagga will run as the user specified and only raise its uid back to uid 0 for brief periods. @node Linux notes @subsection Linux Notes @cindex Configuring Quagga @cindex Building on Linux boxes @cindex Linux configurations There are several options available only to @sc{gnu}/Linux systems: @footnote{@sc{gnu}/Linux has very flexible kernel configuration features}. If you use @sc{gnu}/Linux, make sure that the current kernel configuration is what you want. Quagga will run with any kernel configuration but some recommendations do exist. @table @var @item CONFIG_NETLINK Kernel/User netlink socket. This is a brand new feature which enables an advanced interface between the Linux kernel and zebra (@pxref{Kernel Interface}). @item CONFIG_RTNETLINK Routing messages. This makes it possible to receive netlink routing messages. If you specify this option, @command{zebra} can detect routing information updates directly from the kernel (@pxref{Kernel Interface}). @item CONFIG_IP_MULTICAST IP: multicasting. This option should be specified when you use @command{ripd} (@pxref{RIP}) or @command{ospfd} (@pxref{OSPFv2}) because these protocols use multicast. @end table IPv6 support has been added in @sc{gnu}/Linux kernel version 2.2. If you try to use the Quagga IPv6 feature on a @sc{gnu}/Linux kernel, please make sure the following libraries have been installed. Please note that these libraries will not be needed when you uses @sc{gnu} C library 2.1 or upper. @table @code @item inet6-apps The @code{inet6-apps} package includes basic IPv6 related libraries such as @code{inet_ntop} and @code{inet_pton}. Some basic IPv6 programs such as @command{ping}, @command{ftp}, and @command{inetd} are also included. The @code{inet-apps} can be found at @uref{ftp://ftp.inner.net/pub/ipv6/}. @item net-tools The @code{net-tools} package provides an IPv6 enabled interface and routing utility. It contains @command{ifconfig}, @command{route}, @command{netstat}, and other tools. @code{net-tools} may be found at @uref{http://www.tazenda.demon.co.uk/phil/net-tools/}. @end table @c A - end of footnote @node Build the Software @section Build the Software After configuring the software, you will need to compile it for your system. Simply issue the command @command{make} in the root of the source directory and the software will be compiled. If you have *any* problems at this stage, be certain to send a bug report @xref{Bug Reports}. @example % ./configure . . . ./configure output . . . % make @end example @c A - End of node, Building the Software @node Install the Software @comment node-name, next, previous, up @section Install the Software Installing the software to your system consists of copying the compiled programs and supporting files to a standard location. After the installation process has completed, these files have been copied from your work directory to @file{/usr/local/bin}, and @file{/usr/local/etc}. To install the Quagga suite, issue the following command at your shell prompt: @command{make install}. @example % % make install % @end example Quagga daemons have their own terminal interface or VTY. After installation, you have to setup each beast's port number to connect to them. Please add the following entries to @file{/etc/services}. @example zebrasrv 2600/tcp # zebra service zebra 2601/tcp # zebra vty ripd 2602/tcp # RIPd vty ripngd 2603/tcp # RIPngd vty ospfd 2604/tcp # OSPFd vty bgpd 2605/tcp # BGPd vty ospf6d 2606/tcp # OSPF6d vty ospfapi 2607/tcp # ospfapi isisd 2608/tcp # ISISd vty pimd 2611/tcp # PIMd vty @end example If you use a FreeBSD newer than 2.2.8, the above entries are already added to @file{/etc/services} so there is no need to add it. If you specify a port number when starting the daemon, these entries may not be needed. You may need to make changes to the config files in @file{@value{INSTALL_PREFIX_ETC}/*.conf}. @xref{Config Commands}. quagga-0.99.24.1/doc/filter.texi0000644000175000017500000001431212476520570013162 00000000000000@node Filtering @comment node-name, next, previous, up @chapter Filtering Quagga provides many very flexible filtering features. Filtering is used for both input and output of the routing information. Once filtering is defined, it can be applied in any direction. @menu * IP Access List:: * IP Prefix List:: @end menu @node IP Access List @comment node-name, next, previous, up @section IP Access List @deffn {Command} {access-list @var{name} permit @var{ipv4-network}} {} @deffnx {Command} {access-list @var{name} deny @var{ipv4-network}} {} @end deffn Basic filtering is done by @code{access-list} as shown in the following example. @example access-list filter deny 10.0.0.0/9 access-list filter permit 10.0.0.0/8 @end example @node IP Prefix List @comment node-name, next, previous, up @section IP Prefix List @command{ip prefix-list} provides the most powerful prefix based filtering mechanism. In addition to @command{access-list} functionality, @command{ip prefix-list} has prefix length range specification and sequential number specification. You can add or delete prefix based filters to arbitrary points of prefix-list using sequential number specification. If no ip prefix-list is specified, it acts as permit. If @command{ip prefix-list} is defined, and no match is found, default deny is applied. @c @deffn {Command} {ip prefix-list @var{name} [seq @var{number}] permit|deny [le @var{prefixlen}] [ge @var{prefixlen}]} {} @deffn {Command} {ip prefix-list @var{name} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} @deffnx {Command} {ip prefix-list @var{name} seq @var{number} (permit|deny) @var{prefix} [le @var{len}] [ge @var{len}]} {} You can create @command{ip prefix-list} using above commands. @table @asis @item @asis{seq} seq @var{number} can be set either automatically or manually. In the case that sequential numbers are set manually, the user may pick any number less than 4294967295. In the case that sequential number are set automatically, the sequential number will increase by a unit of five (5) per list. If a list with no specified sequential number is created after a list with a specified sequential number, the list will automatically pick the next multiple of five (5) as the list number. For example, if a list with number 2 already exists and a new list with no specified number is created, the next list will be numbered 5. If lists 2 and 7 already exist and a new list with no specified number is created, the new list will be numbered 10. @item @asis{le} @command{le} command specifies prefix length. The prefix list will be applied if the prefix length is less than or equal to the le prefix length. @item @asis{ge} @command{ge} command specifies prefix length. The prefix list will be applied if the prefix length is greater than or equal to the ge prefix length. @end table @end deffn Less than or equal to prefix numbers and greater than or equal to prefix numbers can be used together. The order of the le and ge commands does not matter. If a prefix list with a different sequential number but with the exact same rules as a previous list is created, an error will result. However, in the case that the sequential number and the rules are exactly similar, no error will result. If a list with the same sequential number as a previous list is created, the new list will overwrite the old list. Matching of IP Prefix is performed from the smaller sequential number to the larger. The matching will stop once any rule has been applied. In the case of no le or ge command, the prefix length must match exactly the length specified in the prefix list. @deffn {Command} {no ip prefix-list @var{name}} {} @end deffn @menu * ip prefix-list description:: * ip prefix-list sequential number control:: * Showing ip prefix-list:: * Clear counter of ip prefix-list:: @end menu @node ip prefix-list description @subsection ip prefix-list description @deffn {Command} {ip prefix-list @var{name} description @var{desc}} {} Descriptions may be added to prefix lists. This command adds a description to the prefix list. @end deffn @deffn {Command} {no ip prefix-list @var{name} description [@var{desc}]} {} Deletes the description from a prefix list. It is possible to use the command without the full description. @end deffn @node ip prefix-list sequential number control @subsection ip prefix-list sequential number control @deffn {Command} {ip prefix-list sequence-number} {} With this command, the IP prefix list sequential number is displayed. This is the default behavior. @end deffn @deffn {Command} {no ip prefix-list sequence-number} {} With this command, the IP prefix list sequential number is not displayed. @end deffn @node Showing ip prefix-list @subsection Showing ip prefix-list @deffn {Command} {show ip prefix-list} {} Display all IP prefix lists. @end deffn @deffn {Command} {show ip prefix-list @var{name}} {} Show IP prefix list can be used with a prefix list name. @end deffn @deffn {Command} {show ip prefix-list @var{name} seq @var{num}} {} Show IP prefix list can be used with a prefix list name and sequential number. @end deffn @deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m}} {} If the command longer is used, all prefix lists with prefix lengths equal to or longer than the specified length will be displayed. If the command first match is used, the first prefix length match will be displayed. @end deffn @deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} longer} {} @end deffn @deffn {Command} {show ip prefix-list @var{name} @var{a.b.c.d/m} first-match} {} @end deffn @deffn {Command} {show ip prefix-list summary} {} @end deffn @deffn {Command} {show ip prefix-list summary @var{name}} {} @end deffn @deffn {Command} {show ip prefix-list detail} {} @end deffn @deffn {Command} {show ip prefix-list detail @var{name}} {} @end deffn @node Clear counter of ip prefix-list @subsection Clear counter of ip prefix-list @deffn {Command} {clear ip prefix-list} {} Clears the counters of all IP prefix lists. Clear IP Prefix List can be used with a specified name and prefix. @end deffn @deffn {Command} {clear ip prefix-list @var{name}} {} @end deffn @deffn {Command} {clear ip prefix-list @var{name} @var{a.b.c.d/m}} {} @end deffn quagga-0.99.24.1/doc/bgpd.texi0000644000175000017500000015150312476520570012615 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node BGP @chapter BGP @acronym{BGP} stands for a Border Gateway Protocol. The lastest BGP version is 4. It is referred as BGP-4. BGP-4 is one of the Exterior Gateway Protocols and de-fact standard of Inter Domain routing protocol. BGP-4 is described in @cite{RFC1771, A Border Gateway Protocol 4 (BGP-4)}. Many extensions have been added to @cite{RFC1771}. @cite{RFC2858, Multiprotocol Extensions for BGP-4} provides multiprotocol support to BGP-4. @menu * Starting BGP:: * BGP router:: * BGP network:: * BGP Peer:: * BGP Peer Group:: * BGP Address Family:: * Autonomous System:: * BGP Communities Attribute:: * BGP Extended Communities Attribute:: * Displaying BGP routes:: * Capability Negotiation:: * Route Reflector:: * Route Server:: * How to set up a 6-Bone connection:: * Dump BGP packets and table:: * BGP Configuration Examples:: @end menu @node Starting BGP @section Starting BGP Default configuration file of @command{bgpd} is @file{bgpd.conf}. @command{bgpd} searches the current directory first then @value{INSTALL_PREFIX_ETC}/bgpd.conf. All of bgpd's command must be configured in @file{bgpd.conf}. @command{bgpd} specific invocation options are described below. Common options may also be specified (@pxref{Common Invocation Options}). @table @samp @item -p @var{PORT} @itemx --bgp_port=@var{PORT} Set the bgp protocol's port number. @item -r @itemx --retain When program terminates, retain BGP routes added by zebra. @end table @node BGP router @section BGP router First of all you must configure BGP router with @command{router bgp} command. To configure BGP router, you need AS number. AS number is an identification of autonomous system. BGP protocol uses the AS number for detecting whether the BGP connection is internal one or external one. @deffn Command {router bgp @var{asn}} {} Enable a BGP protocol process with the specified @var{asn}. After this statement you can input any @code{BGP Commands}. You can not create different BGP process under different @var{asn} without specifying @code{multiple-instance} (@pxref{Multiple instance}). @end deffn @deffn Command {no router bgp @var{asn}} {} Destroy a BGP protocol process with the specified @var{asn}. @end deffn @deffn {BGP} {bgp router-id @var{A.B.C.D}} {} This command specifies the router-ID. If @command{bgpd} connects to @command{zebra} it gets interface and address information. In that case default router ID value is selected as the largest IP Address of the interfaces. When @code{router zebra} is not enabled @command{bgpd} can't get interface information so @code{router-id} is set to 0.0.0.0. So please set router-id by hand. @end deffn @menu * BGP distance:: * BGP decision process:: * BGP route flap dampening:: @end menu @node BGP distance @subsection BGP distance @deffn {BGP} {distance bgp <1-255> <1-255> <1-255>} {} This command change distance value of BGP. Each argument is distance value for external routes, internal routes and local routes. @end deffn @deffn {BGP} {distance <1-255> @var{A.B.C.D/M}} {} @deffnx {BGP} {distance <1-255> @var{A.B.C.D/M} @var{word}} {} This command set distance value to @end deffn @node BGP decision process @subsection BGP decision process @table @asis @item 1. Weight check @item 2. Local preference check. @item 3. Local route check. @item 4. AS path length check. @item 5. Origin check. @item 6. MED check. @end table @deffn {BGP} {bgp bestpath as-path confed} {} This command specifies that the length of confederation path sets and sequences should should be taken into account during the BGP best path decision process. @end deffn @deffn {BGP} {bgp bestpath as-path multipath-relax} {} This command specifies that BGP decision process should consider paths of equal AS_PATH length candidates for multipath computation. Without the knob, the entire AS_PATH must match for multipath computation. @end deffn @node BGP route flap dampening @subsection BGP route flap dampening @deffn {BGP} {bgp dampening @var{<1-45>} @var{<1-20000>} @var{<1-20000>} @var{<1-255>}} {} This command enables BGP route-flap dampening and specifies dampening parameters. @table @asis @item @asis{half-life} Half-life time for the penalty @item @asis{reuse-threshold} Value to start reusing a route @item @asis{suppress-threshold} Value to start suppressing a route @item @asis{max-suppress} Maximum duration to suppress a stable route @end table The route-flap damping algorithm is compatible with @cite{RFC2439}. The use of this command is not recommended nowadays, see @uref{http://www.ripe.net/ripe/docs/ripe-378,,RIPE-378}. @end deffn @node BGP network @section BGP network @menu * BGP route:: * Route Aggregation:: * Redistribute to BGP:: @end menu @node BGP route @subsection BGP route @deffn {BGP} {network @var{A.B.C.D/M}} {} This command adds the announcement network. @example @group router bgp 1 network 10.0.0.0/8 @end group @end example This configuration example says that network 10.0.0.0/8 will be announced to all neighbors. Some vendors' routers don't advertise routes if they aren't present in their IGP routing tables; @code{bgpd} doesn't care about IGP routes when announcing its routes. @end deffn @deffn {BGP} {no network @var{A.B.C.D/M}} {} @end deffn @node Route Aggregation @subsection Route Aggregation @deffn {BGP} {aggregate-address @var{A.B.C.D/M}} {} This command specifies an aggregate address. @end deffn @deffn {BGP} {aggregate-address @var{A.B.C.D/M} as-set} {} This command specifies an aggregate address. Resulting routes inlucde AS set. @end deffn @deffn {BGP} {aggregate-address @var{A.B.C.D/M} summary-only} {} This command specifies an aggregate address. Aggreated routes will not be announce. @end deffn @deffn {BGP} {no aggregate-address @var{A.B.C.D/M}} {} @end deffn @node Redistribute to BGP @subsection Redistribute to BGP @deffn {BGP} {redistribute kernel} {} Redistribute kernel route to BGP process. @end deffn @deffn {BGP} {redistribute static} {} Redistribute static route to BGP process. @end deffn @deffn {BGP} {redistribute connected} {} Redistribute connected route to BGP process. @end deffn @deffn {BGP} {redistribute rip} {} Redistribute RIP route to BGP process. @end deffn @deffn {BGP} {redistribute ospf} {} Redistribute OSPF route to BGP process. @end deffn @node BGP Peer @section BGP Peer @menu * Defining Peer:: * BGP Peer commands:: * Peer filtering:: @end menu @node Defining Peer @subsection Defining Peer @deffn {BGP} {neighbor @var{peer} remote-as @var{asn}} {} Creates a new neighbor whose remote-as is @var{asn}. @var{peer} can be an IPv4 address or an IPv6 address. @example @group router bgp 1 neighbor 10.0.0.1 remote-as 2 @end group @end example In this case my router, in AS-1, is trying to peer with AS-2 at 10.0.0.1. This command must be the first command used when configuring a neighbor. If the remote-as is not specified, @command{bgpd} will complain like this: @example can't find neighbor 10.0.0.1 @end example @end deffn @node BGP Peer commands @subsection BGP Peer commands In a @code{router bgp} clause there are neighbor specific configurations required. @deffn {BGP} {neighbor @var{peer} shutdown} {} @deffnx {BGP} {no neighbor @var{peer} shutdown} {} Shutdown the peer. We can delete the neighbor's configuration by @code{no neighbor @var{peer} remote-as @var{as-number}} but all configuration of the neighbor will be deleted. When you want to preserve the configuration, but want to drop the BGP peer, use this syntax. @end deffn @deffn {BGP} {neighbor @var{peer} ebgp-multihop} {} @deffnx {BGP} {no neighbor @var{peer} ebgp-multihop} {} @end deffn @deffn {BGP} {neighbor @var{peer} description ...} {} @deffnx {BGP} {no neighbor @var{peer} description ...} {} Set description of the peer. @end deffn @deffn {BGP} {neighbor @var{peer} version @var{version}} {} Set up the neighbor's BGP version. @var{version} can be @var{4}, @var{4+} or @var{4-}. BGP version @var{4} is the default value used for BGP peering. BGP version @var{4+} means that the neighbor supports Multiprotocol Extensions for BGP-4. BGP version @var{4-} is similar but the neighbor speaks the old Internet-Draft revision 00's Multiprotocol Extensions for BGP-4. Some routing software is still using this version. @end deffn @deffn {BGP} {neighbor @var{peer} interface @var{ifname}} {} @deffnx {BGP} {no neighbor @var{peer} interface @var{ifname}} {} When you connect to a BGP peer over an IPv6 link-local address, you have to specify the @var{ifname} of the interface used for the connection. To specify IPv4 session addresses, see the @code{neighbor @var{peer} update-source} command below. This command is deprecated and may be removed in a future release. Its use should be avoided. @end deffn @deffn {BGP} {neighbor @var{peer} next-hop-self [all]} {} @deffnx {BGP} {no neighbor @var{peer} next-hop-self [all]} {} This command specifies an announced route's nexthop as being equivalent to the address of the bgp router if it is learned via eBGP. If the optional keyword @code{all} is specified the modifiation is done also for routes learned via iBGP. @end deffn @deffn {BGP} {neighbor @var{peer} update-source @var{}} {} @deffnx {BGP} {no neighbor @var{peer} update-source} {} Specify the IPv4 source address to use for the @acronym{BGP} session to this neighbour, may be specified as either an IPv4 address directly or as an interface name (in which case the @command{zebra} daemon MUST be running in order for @command{bgpd} to be able to retrieve interface state). @example @group router bgp 64555 neighbor foo update-source 192.168.0.1 neighbor bar update-source lo0 @end group @end example @end deffn @deffn {BGP} {neighbor @var{peer} default-originate} {} @deffnx {BGP} {no neighbor @var{peer} default-originate} {} @command{bgpd}'s default is to not announce the default route (0.0.0.0/0) even it is in routing table. When you want to announce default routes to the peer, use this command. @end deffn @deffn {BGP} {neighbor @var{peer} port @var{port}} {} @deffnx {BGP} {neighbor @var{peer} port @var{port}} {} @end deffn @deffn {BGP} {neighbor @var{peer} send-community} {} @deffnx {BGP} {neighbor @var{peer} send-community} {} @end deffn @deffn {BGP} {neighbor @var{peer} weight @var{weight}} {} @deffnx {BGP} {no neighbor @var{peer} weight @var{weight}} {} This command specifies a default @var{weight} value for the neighbor's routes. @end deffn @deffn {BGP} {neighbor @var{peer} maximum-prefix @var{number}} {} @deffnx {BGP} {no neighbor @var{peer} maximum-prefix @var{number}} {} @end deffn @deffn {BGP} {neighbor @var{peer} local-as @var{as-number}} {} @deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend} {} @deffnx {BGP} {neighbor @var{peer} local-as @var{as-number} no-prepend replace-as} {} @deffnx {BGP} {no neighbor @var{peer} local-as} {} Specify an alternate AS for this BGP process when interacting with the specified peer. With no modifiers, the specified local-as is prepended to the received AS_PATH when receiving routing updates from the peer, and prepended to the outgoing AS_PATH (after the process local AS) when transmitting local routes to the peer. If the no-prepend attribute is specified, then the supplied local-as is not prepended to the received AS_PATH. If the replace-as attribute is specified, then only the supplied local-as is prepended to the AS_PATH when transmitting local-route updates to this peer. Note that replace-as can only be specified if no-prepend is. This command is only allowed for eBGP peers. @end deffn @deffn {BGP} {neighbor @var{peer} ttl-security hops @var{number}} {} @deffnx {BGP} {no neighbor @var{peer} ttl-security hops @var{number}} {} This command enforces Generalized TTL Security Mechanism (GTSM), as specified in RFC 5082. With this command, only neighbors that are the specified number of hops away will be allowed to become neighbors. This command is mututally exclusive with @command{ebgp-multihop}. @end deffn @node Peer filtering @subsection Peer filtering @deffn {BGP} {neighbor @var{peer} distribute-list @var{name} [in|out]} {} This command specifies a distribute-list for the peer. @var{direct} is @samp{in} or @samp{out}. @end deffn @deffn {BGP command} {neighbor @var{peer} prefix-list @var{name} [in|out]} {} @end deffn @deffn {BGP command} {neighbor @var{peer} filter-list @var{name} [in|out]} {} @end deffn @deffn {BGP} {neighbor @var{peer} route-map @var{name} [in|out]} {} Apply a route-map on the neighbor. @var{direct} must be @code{in} or @code{out}. @end deffn @c ----------------------------------------------------------------------- @node BGP Peer Group @section BGP Peer Group @deffn {BGP} {neighbor @var{word} peer-group} {} This command defines a new peer group. @end deffn @deffn {BGP} {neighbor @var{peer} peer-group @var{word}} {} This command bind specific peer to peer group @var{word}. @end deffn @node BGP Address Family @section BGP Address Family @c ----------------------------------------------------------------------- @node Autonomous System @section Autonomous System The @acronym{AS,Autonomous System} number is one of the essential element of BGP. BGP is a distance vector routing protocol, and the AS-Path framework provides distance vector metric and loop detection to BGP. @cite{RFC1930, Guidelines for creation, selection, and registration of an Autonomous System (AS)} provides some background on the concepts of an AS. The AS number is a two octet value, ranging in value from 1 to 65535. The AS numbers 64512 through 65535 are defined as private AS numbers. Private AS numbers must not to be advertised in the global Internet. @menu * AS Path Regular Expression:: * Display BGP Routes by AS Path:: * AS Path Access List:: * Using AS Path in Route Map:: * Private AS Numbers:: @end menu @node AS Path Regular Expression @subsection AS Path Regular Expression AS path regular expression can be used for displaying BGP routes and AS path access list. AS path regular expression is based on @code{POSIX 1003.2} regular expressions. Following description is just a subset of @code{POSIX} regular expression. User can use full @code{POSIX} regular expression. Adding to that special character '_' is added for AS path regular expression. @table @code @item . Matches any single character. @item * Matches 0 or more occurrences of pattern. @item + Matches 1 or more occurrences of pattern. @item ? Match 0 or 1 occurrences of pattern. @item ^ Matches the beginning of the line. @item $ Matches the end of the line. @item _ Character @code{_} has special meanings in AS path regular expression. It matches to space and comma , and AS set delimiter @{ and @} and AS confederation delimiter @code{(} and @code{)}. And it also matches to the beginning of the line and the end of the line. So @code{_} can be used for AS value boundaries match. @code{show ip bgp regexp _7675_} matches to all of BGP routes which as AS number include @var{7675}. @end table @node Display BGP Routes by AS Path @subsection Display BGP Routes by AS Path To show BGP routes which has specific AS path information @code{show ip bgp} command can be used. @deffn Command {show ip bgp regexp @var{line}} {} This commands display BGP routes that matches AS path regular expression @var{line}. @end deffn @node AS Path Access List @subsection AS Path Access List AS path access list is user defined AS path. @deffn {Command} {ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} This command defines a new AS path access list. @end deffn @deffn {Command} {no ip as-path access-list @var{word}} {} @deffnx {Command} {no ip as-path access-list @var{word} @{permit|deny@} @var{line}} {} @end deffn @node Using AS Path in Route Map @subsection Using AS Path in Route Map @deffn {Route Map} {match as-path @var{word}} {} @end deffn @deffn {Route Map} {set as-path prepend @var{as-path}} {} Prepend the given string of AS numbers to the AS_PATH. @end deffn @deffn {Route Map} {set as-path prepend last-as @var{num}} {} Prepend the existing last AS number (the leftmost ASN) to the AS_PATH. @end deffn @node Private AS Numbers @subsection Private AS Numbers @c ----------------------------------------------------------------------- @node BGP Communities Attribute @section BGP Communities Attribute BGP communities attribute is widely used for implementing policy routing. Network operators can manipulate BGP communities attribute based on their network policy. BGP communities attribute is defined in @cite{RFC1997, BGP Communities Attribute} and @cite{RFC1998, An Application of the BGP Community Attribute in Multi-home Routing}. It is an optional transitive attribute, therefore local policy can travel through different autonomous system. Communities attribute is a set of communities values. Each communities value is 4 octet long. The following format is used to define communities value. @table @code @item AS:VAL This format represents 4 octet communities value. @code{AS} is high order 2 octet in digit format. @code{VAL} is low order 2 octet in digit format. This format is useful to define AS oriented policy value. For example, @code{7675:80} can be used when AS 7675 wants to pass local policy value 80 to neighboring peer. @item internet @code{internet} represents well-known communities value 0. @item no-export @code{no-export} represents well-known communities value @code{NO_EXPORT}@* @r{(0xFFFFFF01)}. All routes carry this value must not be advertised to outside a BGP confederation boundary. If neighboring BGP peer is part of BGP confederation, the peer is considered as inside a BGP confederation boundary, so the route will be announced to the peer. @item no-advertise @code{no-advertise} represents well-known communities value @code{NO_ADVERTISE}@*@r{(0xFFFFFF02)}. All routes carry this value must not be advertise to other BGP peers. @item local-AS @code{local-AS} represents well-known communities value @code{NO_EXPORT_SUBCONFED} @r{(0xFFFFFF03)}. All routes carry this value must not be advertised to external BGP peers. Even if the neighboring router is part of confederation, it is considered as external BGP peer, so the route will not be announced to the peer. @end table When BGP communities attribute is received, duplicated communities value in the communities attribute is ignored and each communities values are sorted in numerical order. @menu * BGP Community Lists:: * Numbered BGP Community Lists:: * BGP Community in Route Map:: * Display BGP Routes by Community:: * Using BGP Communities Attribute:: @end menu @node BGP Community Lists @subsection BGP Community Lists BGP community list is a user defined BGP communites attribute list. BGP community list can be used for matching or manipulating BGP communities attribute in updates. There are two types of community list. One is standard community list and another is expanded community list. Standard community list defines communities attribute. Expanded community list defines communities attribute string with regular expression. Standard community list is compiled into binary format when user define it. Standard community list will be directly compared to BGP communities attribute in BGP updates. Therefore the comparison is faster than expanded community list. @deffn Command {ip community-list standard @var{name} @{permit|deny@} @var{community}} {} This command defines a new standard community list. @var{community} is communities value. The @var{community} is compiled into community structure. We can define multiple community list under same name. In that case match will happen user defined order. Once the community list matches to communities attribute in BGP updates it return permit or deny by the community list definition. When there is no matched entry, deny will be returned. When @var{community} is empty it matches to any routes. @end deffn @deffn Command {ip community-list expanded @var{name} @{permit|deny@} @var{line}} {} This command defines a new expanded community list. @var{line} is a string expression of communities attribute. @var{line} can include regular expression to match communities attribute in BGP updates. @end deffn @deffn Command {no ip community-list @var{name}} {} @deffnx Command {no ip community-list standard @var{name}} {} @deffnx Command {no ip community-list expanded @var{name}} {} These commands delete community lists specified by @var{name}. All of community lists shares a single name space. So community lists can be removed simpley specifying community lists name. @end deffn @deffn {Command} {show ip community-list} {} @deffnx {Command} {show ip community-list @var{name}} {} This command display current community list information. When @var{name} is specified the specified community list's information is shown. @example # show ip community-list Named Community standard list CLIST permit 7675:80 7675:100 no-export deny internet Named Community expanded list EXPAND permit : # show ip community-list CLIST Named Community standard list CLIST permit 7675:80 7675:100 no-export deny internet @end example @end deffn @node Numbered BGP Community Lists @subsection Numbered BGP Community Lists When number is used for BGP community list name, the number has special meanings. Community list number in the range from 1 and 99 is standard community list. Community list number in the range from 100 to 199 is expanded community list. These community lists are called as numbered community lists. On the other hand normal community lists is called as named community lists. @deffn Command {ip community-list <1-99> @{permit|deny@} @var{community}} {} This command defines a new community list. <1-99> is standard community list number. Community list name within this range defines standard community list. When @var{community} is empty it matches to any routes. @end deffn @deffn Command {ip community-list <100-199> @{permit|deny@} @var{community}} {} This command defines a new community list. <100-199> is expanded community list number. Community list name within this range defines expanded community list. @end deffn @deffn Command {ip community-list @var{name} @{permit|deny@} @var{community}} {} When community list type is not specifed, the community list type is automatically detected. If @var{community} can be compiled into communities attribute, the community list is defined as a standard community list. Otherwise it is defined as an expanded community list. This feature is left for backward compability. Use of this feature is not recommended. @end deffn @node BGP Community in Route Map @subsection BGP Community in Route Map In Route Map (@pxref{Route Map}), we can match or set BGP communities attribute. Using this feature network operator can implement their network policy based on BGP communities attribute. Following commands can be used in Route Map. @deffn {Route Map} {match community @var{word}} {} @deffnx {Route Map} {match community @var{word} exact-match} {} This command perform match to BGP updates using community list @var{word}. When the one of BGP communities value match to the one of communities value in community list, it is match. When @code{exact-match} keyword is spcified, match happen only when BGP updates have completely same communities value specified in the community list. @end deffn @deffn {Route Map} {set community none} {} @deffnx {Route Map} {set community @var{community}} {} @deffnx {Route Map} {set community @var{community} additive} {} This command manipulate communities value in BGP updates. When @code{none} is specified as communities value, it removes entire communities attribute from BGP updates. When @var{community} is not @code{none}, specified communities value is set to BGP updates. If BGP updates already has BGP communities value, the existing BGP communities value is replaced with specified @var{community} value. When @code{additive} keyword is specified, @var{community} is appended to the existing communities value. @end deffn @deffn {Route Map} {set comm-list @var{word} delete} {} This command remove communities value from BGP communities attribute. The @var{word} is community list name. When BGP route's communities value matches to the community list @var{word}, the communities value is removed. When all of communities value is removed eventually, the BGP update's communities attribute is completely removed. @end deffn @node Display BGP Routes by Community @subsection Display BGP Routes by Community To show BGP routes which has specific BGP communities attribute, @code{show ip bgp} command can be used. The @var{community} value and community list can be used for @code{show ip bgp} command. @deffn Command {show ip bgp community} {} @deffnx Command {show ip bgp community @var{community}} {} @deffnx Command {show ip bgp community @var{community} exact-match} {} @code{show ip bgp community} displays BGP routes which has communities attribute. When @var{community} is specified, BGP routes that matches @var{community} value is displayed. For this command, @code{internet} keyword can't be used for @var{community} value. When @code{exact-match} is specified, it display only routes that have an exact match. @end deffn @deffn Command {show ip bgp community-list @var{word}} {} @deffnx Command {show ip bgp community-list @var{word} exact-match} {} This commands display BGP routes that matches community list @var{word}. When @code{exact-match} is specified, display only routes that have an exact match. @end deffn @node Using BGP Communities Attribute @subsection Using BGP Communities Attribute Following configuration is the most typical usage of BGP communities attribute. AS 7675 provides upstream Internet connection to AS 100. When following configuration exists in AS 7675, AS 100 networks operator can set local preference in AS 7675 network by setting BGP communities attribute to the updates. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list 70 permit 7675:70 ip community-list 70 deny ip community-list 80 permit 7675:80 ip community-list 80 deny ip community-list 90 permit 7675:90 ip community-list 90 deny ! route-map RMAP permit 10 match community 70 set local-preference 70 ! route-map RMAP permit 20 match community 80 set local-preference 80 ! route-map RMAP permit 30 match community 90 set local-preference 90 @end example Following configuration announce 10.0.0.0/8 from AS 100 to AS 7675. The route has communities value 7675:80 so when above configuration exists in AS 7675, announced route's local preference will be set to value 80. @example router bgp 100 network 10.0.0.0/8 neighbor 192.168.0.2 remote-as 7675 neighbor 192.168.0.2 route-map RMAP out ! ip prefix-list PLIST permit 10.0.0.0/8 ! route-map RMAP permit 10 match ip address prefix-list PLIST set community 7675:80 @end example Following configuration is an example of BGP route filtering using communities attribute. This configuration only permit BGP routes which has BGP communities value 0:80 or 0:90. Network operator can put special internal communities value at BGP border router, then limit the BGP routes announcement into the internal network. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list 1 permit 0:80 0:90 ! route-map RMAP permit in match community 1 @end example Following exmaple filter BGP routes which has communities value 1:1. When there is no match community-list returns deny. To avoid filtering all of routes, we need to define permit any at last. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard FILTER deny 1:1 ip community-list standard FILTER permit ! route-map RMAP permit 10 match community FILTER @end example Communities value keyword @code{internet} has special meanings in standard community lists. In below example @code{internet} act as match any. It matches all of BGP routes even if the route does not have communities attribute at all. So community list @code{INTERNET} is same as above example's @code{FILTER}. @example ip community-list standard INTERNET deny 1:1 ip community-list standard INTERNET permit internet @end example Following configuration is an example of communities value deletion. With this configuration communities value 100:1 and 100:2 is removed from BGP updates. For communities value deletion, only @code{permit} community-list is used. @code{deny} community-list is ignored. @example router bgp 7675 neighbor 192.168.0.1 remote-as 100 neighbor 192.168.0.1 route-map RMAP in ! ip community-list standard DEL permit 100:1 100:2 ! route-map RMAP permit 10 set comm-list DEL delete @end example @c ----------------------------------------------------------------------- @node BGP Extended Communities Attribute @section BGP Extended Communities Attribute BGP extended communities attribute is introduced with MPLS VPN/BGP technology. MPLS VPN/BGP expands capability of network infrastructure to provide VPN functionality. At the same time it requires a new framework for policy routing. With BGP Extended Communities Attribute we can use Route Target or Site of Origin for implementing network policy for MPLS VPN/BGP. BGP Extended Communities Attribute is similar to BGP Communities Attribute. It is an optional transitive attribute. BGP Extended Communities Attribute can carry multiple Extended Community value. Each Extended Community value is eight octet length. BGP Extended Communities Attribute provides an extended range compared with BGP Communities Attribute. Adding to that there is a type field in each value to provides community space structure. There are two format to define Extended Community value. One is AS based format the other is IP address based format. @table @code @item AS:VAL This is a format to define AS based Extended Community value. @code{AS} part is 2 octets Global Administrator subfield in Extended Community value. @code{VAL} part is 4 octets Local Administrator subfield. @code{7675:100} represents AS 7675 policy value 100. @item IP-Address:VAL This is a format to define IP address based Extended Community value. @code{IP-Address} part is 4 octets Global Administrator subfield. @code{VAL} part is 2 octets Local Administrator subfield. @code{10.0.0.1:100} represents @end table @menu * BGP Extended Community Lists:: * BGP Extended Communities in Route Map:: @end menu @node BGP Extended Community Lists @subsection BGP Extended Community Lists Expanded Community Lists is a user defined BGP Expanded Community Lists. @deffn Command {ip extcommunity-list standard @var{name} @{permit|deny@} @var{extcommunity}} {} This command defines a new standard extcommunity-list. @var{extcommunity} is extended communities value. The @var{extcommunity} is compiled into extended community structure. We can define multiple extcommunity-list under same name. In that case match will happen user defined order. Once the extcommunity-list matches to extended communities attribute in BGP updates it return permit or deny based upon the extcommunity-list definition. When there is no matched entry, deny will be returned. When @var{extcommunity} is empty it matches to any routes. @end deffn @deffn Command {ip extcommunity-list expanded @var{name} @{permit|deny@} @var{line}} {} This command defines a new expanded extcommunity-list. @var{line} is a string expression of extended communities attribute. @var{line} can include regular expression to match extended communities attribute in BGP updates. @end deffn @deffn Command {no ip extcommunity-list @var{name}} {} @deffnx Command {no ip extcommunity-list standard @var{name}} {} @deffnx Command {no ip extcommunity-list expanded @var{name}} {} These commands delete extended community lists specified by @var{name}. All of extended community lists shares a single name space. So extended community lists can be removed simpley specifying the name. @end deffn @deffn {Command} {show ip extcommunity-list} {} @deffnx {Command} {show ip extcommunity-list @var{name}} {} This command display current extcommunity-list information. When @var{name} is specified the community list's information is shown. @example # show ip extcommunity-list @end example @end deffn @node BGP Extended Communities in Route Map @subsection BGP Extended Communities in Route Map @deffn {Route Map} {match extcommunity @var{word}} {} @end deffn @deffn {Route Map} {set extcommunity rt @var{extcommunity}} {} This command set Route Target value. @end deffn @deffn {Route Map} {set extcommunity soo @var{extcommunity}} {} This command set Site of Origin value. @end deffn @c ----------------------------------------------------------------------- @node Displaying BGP routes @section Displaying BGP Routes @menu * Show IP BGP:: * More Show IP BGP:: @end menu @node Show IP BGP @subsection Show IP BGP @deffn {Command} {show ip bgp} {} @deffnx {Command} {show ip bgp @var{A.B.C.D}} {} @deffnx {Command} {show ip bgp @var{X:X::X:X}} {} This command displays BGP routes. When no route is specified it display all of IPv4 BGP routes. @end deffn @example BGP table version is 0, local router ID is 10.1.1.1 Status codes: s suppressed, d damped, h history, * valid, > best, i - internal Origin codes: i - IGP, e - EGP, ? - incomplete Network Next Hop Metric LocPrf Weight Path *> 1.1.1.1/32 0.0.0.0 0 32768 i Total number of prefixes 1 @end example @node More Show IP BGP @subsection More Show IP BGP @deffn {Command} {show ip bgp regexp @var{line}} {} This command display BGP routes using AS path regular expression (@pxref{Display BGP Routes by AS Path}). @end deffn @deffn Command {show ip bgp community @var{community}} {} @deffnx Command {show ip bgp community @var{community} exact-match} {} This command display BGP routes using @var{community} (@pxref{Display BGP Routes by Community}). @end deffn @deffn Command {show ip bgp community-list @var{word}} {} @deffnx Command {show ip bgp community-list @var{word} exact-match} {} This command display BGP routes using community list (@pxref{Display BGP Routes by Community}). @end deffn @deffn {Command} {show ip bgp summary} {} @end deffn @deffn {Command} {show ip bgp neighbor [@var{peer}]} {} @end deffn @deffn {Command} {clear ip bgp @var{peer}} {} Clear peers which have addresses of X.X.X.X @end deffn @deffn {Command} {clear ip bgp @var{peer} soft in} {} Clear peer using soft reconfiguration. @end deffn @deffn {Command} {show ip bgp dampened-paths} {} Display paths suppressed due to dampening @end deffn @deffn {Command} {show ip bgp flap-statistics} {} Display flap statistics of routes @end deffn @deffn {Command} {show debug} {} @end deffn @deffn {Command} {debug event} {} @end deffn @deffn {Command} {debug update} {} @end deffn @deffn {Command} {debug keepalive} {} @end deffn @deffn {Command} {no debug event} {} @end deffn @deffn {Command} {no debug update} {} @end deffn @deffn {Command} {no debug keepalive} {} @end deffn @node Capability Negotiation @section Capability Negotiation When adding IPv6 routing information exchange feature to BGP. There were some proposals. @acronym{IETF,Internet Engineering Task Force} @acronym{IDR, Inter Domain Routing} @acronym{WG, Working group} adopted a proposal called Multiprotocol Extension for BGP. The specification is described in @cite{RFC2283}. The protocol does not define new protocols. It defines new attributes to existing BGP. When it is used exchanging IPv6 routing information it is called BGP-4+. When it is used for exchanging multicast routing information it is called MBGP. @command{bgpd} supports Multiprotocol Extension for BGP. So if remote peer supports the protocol, @command{bgpd} can exchange IPv6 and/or multicast routing information. Traditional BGP did not have the feature to detect remote peer's capabilities, e.g. whether it can handle prefix types other than IPv4 unicast routes. This was a big problem using Multiprotocol Extension for BGP to operational network. @cite{RFC2842, Capabilities Advertisement with BGP-4} adopted a feature called Capability Negotiation. @command{bgpd} use this Capability Negotiation to detect the remote peer's capabilities. If the peer is only configured as IPv4 unicast neighbor, @command{bgpd} does not send these Capability Negotiation packets (at least not unless other optional BGP features require capability negotation). By default, Quagga will bring up peering with minimal common capability for the both sides. For example, local router has unicast and multicast capabilitie and remote router has unicast capability. In this case, the local router will establish the connection with unicast only capability. When there are no common capabilities, Quagga sends Unsupported Capability error and then resets the connection. If you want to completely match capabilities with remote peer. Please use @command{strict-capability-match} command. @deffn {BGP} {neighbor @var{peer} strict-capability-match} {} @deffnx {BGP} {no neighbor @var{peer} strict-capability-match} {} Strictly compares remote capabilities and local capabilities. If capabilities are different, send Unsupported Capability error then reset connection. @end deffn You may want to disable sending Capability Negotiation OPEN message optional parameter to the peer when remote peer does not implement Capability Negotiation. Please use @command{dont-capability-negotiate} command to disable the feature. @deffn {BGP} {neighbor @var{peer} dont-capability-negotiate} {} @deffnx {BGP} {no neighbor @var{peer} dont-capability-negotiate} {} Suppress sending Capability Negotiation as OPEN message optional parameter to the peer. This command only affects the peer is configured other than IPv4 unicast configuration. @end deffn When remote peer does not have capability negotiation feature, remote peer will not send any capabilities at all. In that case, bgp configures the peer with configured capabilities. You may prefer locally configured capabilities more than the negotiated capabilities even though remote peer sends capabilities. If the peer is configured by @command{override-capability}, @command{bgpd} ignores received capabilities then override negotiated capabilities with configured values. @deffn {BGP} {neighbor @var{peer} override-capability} {} @deffnx {BGP} {no neighbor @var{peer} override-capability} {} Override the result of Capability Negotiation with local configuration. Ignore remote peer's capability value. @end deffn @node Route Reflector @section Route Reflector @deffn {BGP} {bgp cluster-id @var{a.b.c.d}} {} @end deffn @deffn {BGP} {neighbor @var{peer} route-reflector-client} {} @deffnx {BGP} {no neighbor @var{peer} route-reflector-client} {} @end deffn @node Route Server @section Route Server At an Internet Exchange point, many ISPs are connected to each other by external BGP peering. Normally these external BGP connection are done by @samp{full mesh} method. As with internal BGP full mesh formation, this method has a scaling problem. This scaling problem is well known. Route Server is a method to resolve the problem. Each ISP's BGP router only peers to Route Server. Route Server serves as BGP information exchange to other BGP routers. By applying this method, numbers of BGP connections is reduced from O(n*(n-1)/2) to O(n). Unlike normal BGP router, Route Server must have several routing tables for managing different routing policies for each BGP speaker. We call the routing tables as different @code{view}s. @command{bgpd} can work as normal BGP router or Route Server or both at the same time. @menu * Multiple instance:: * BGP instance and view:: * Routing policy:: * Viewing the view:: @end menu @node Multiple instance @subsection Multiple instance To enable multiple view function of @code{bgpd}, you must turn on multiple instance feature beforehand. @deffn {Command} {bgp multiple-instance} {} Enable BGP multiple instance feature. After this feature is enabled, you can make multiple BGP instances or multiple BGP views. @end deffn @deffn {Command} {no bgp multiple-instance} {} Disable BGP multiple instance feature. You can not disable this feature when BGP multiple instances or views exist. @end deffn When you want to make configuration more Cisco like one, @deffn {Command} {bgp config-type cisco} {} Cisco compatible BGP configuration output. @end deffn When bgp config-type cisco is specified, ``no synchronization'' is displayed. ``no auto-summary'' is displayed. ``network'' and ``aggregate-address'' argument is displayed as ``A.B.C.D M.M.M.M'' Quagga: network 10.0.0.0/8 Cisco: network 10.0.0.0 Quagga: aggregate-address 192.168.0.0/24 Cisco: aggregate-address 192.168.0.0 255.255.255.0 Community attribute handling is also different. If there is no configuration is specified community attribute and extended community attribute are sent to neighbor. When user manually disable the feature community attribute is not sent to the neighbor. In case of @command{bgp config-type cisco} is specified, community attribute is not sent to the neighbor by default. To send community attribute user has to specify @command{neighbor A.B.C.D send-community} command. @example ! router bgp 1 neighbor 10.0.0.1 remote-as 1 no neighbor 10.0.0.1 send-community ! router bgp 1 neighbor 10.0.0.1 remote-as 1 neighbor 10.0.0.1 send-community ! @end example @deffn {Command} {bgp config-type zebra} {} Quagga style BGP configuration. This is default. @end deffn @node BGP instance and view @subsection BGP instance and view BGP instance is a normal BGP process. The result of route selection goes to the kernel routing table. You can setup different AS at the same time when BGP multiple instance feature is enabled. @deffn {Command} {router bgp @var{as-number}} {} Make a new BGP instance. You can use arbitrary word for the @var{name}. @end deffn @example @group bgp multiple-instance ! router bgp 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.2 remote-as 3 ! router bgp 2 neighbor 10.0.0.3 remote-as 4 neighbor 10.0.0.4 remote-as 5 @end group @end example BGP view is almost same as normal BGP process. The result of route selection does not go to the kernel routing table. BGP view is only for exchanging BGP routing information. @deffn {Command} {router bgp @var{as-number} view @var{name}} {} Make a new BGP view. You can use arbitrary word for the @var{name}. This view's route selection result does not go to the kernel routing table. @end deffn With this command, you can setup Route Server like below. @example @group bgp multiple-instance ! router bgp 1 view 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.2 remote-as 3 ! router bgp 2 view 2 neighbor 10.0.0.3 remote-as 4 neighbor 10.0.0.4 remote-as 5 @end group @end example @node Routing policy @subsection Routing policy You can set different routing policy for a peer. For example, you can set different filter for a peer. @example @group bgp multiple-instance ! router bgp 1 view 1 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.1 distribute-list 1 in ! router bgp 1 view 2 neighbor 10.0.0.1 remote-as 2 neighbor 10.0.0.1 distribute-list 2 in @end group @end example This means BGP update from a peer 10.0.0.1 goes to both BGP view 1 and view 2. When the update is inserted into view 1, distribute-list 1 is applied. On the other hand, when the update is inserted into view 2, distribute-list 2 is applied. @node Viewing the view @subsection Viewing the view To display routing table of BGP view, you must specify view name. @deffn {Command} {show ip bgp view @var{name}} {} Display routing table of BGP view @var{name}. @end deffn @node How to set up a 6-Bone connection @section How to set up a 6-Bone connection @example @group zebra configuration =================== ! ! Actually there is no need to configure zebra ! bgpd configuration ================== ! ! This means that routes go through zebra and into the kernel. ! router zebra ! ! MP-BGP configuration ! router bgp 7675 bgp router-id 10.0.0.1 neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 remote-as @var{as-number} ! address-family ipv6 network 3ffe:506::/32 neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 activate neighbor 3ffe:1cfa:0:2:2a0:c9ff:fe9e:f56 route-map set-nexthop out neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 remote-as @var{as-number} neighbor 3ffe:1cfa:0:2:2c0:4fff:fe68:a231 route-map set-nexthop out exit-address-family ! ipv6 access-list all permit any ! ! Set output nexthop address. ! route-map set-nexthop permit 10 match ipv6 address all set ipv6 nexthop global 3ffe:1cfa:0:2:2c0:4fff:fe68:a225 set ipv6 nexthop local fe80::2c0:4fff:fe68:a225 ! ! logfile FILENAME is obsolete. Please use log file FILENAME log file bgpd.log ! @end group @end example @node Dump BGP packets and table @section Dump BGP packets and table @deffn Command {dump bgp all @var{path}} {} @deffnx Command {dump bgp all @var{path} @var{interval}} {} Dump all BGP packet and events to @var{path} file. @end deffn @deffn Command {dump bgp updates @var{path}} {} @deffnx Command {dump bgp updates @var{path} @var{interval}} {} Dump BGP updates to @var{path} file. @end deffn @deffn Command {dump bgp routes @var{path}} {} @deffnx Command {dump bgp routes @var{path}} {} Dump whole BGP routing table to @var{path}. This is heavy process. @end deffn @node BGP Configuration Examples @section BGP Configuration Examples Example of a session to an upstream, advertising only one prefix to it. @example router bgp 64512 bgp router-id 10.236.87.1 network 10.236.87.0/24 neighbor upstream peer-group neighbor upstream remote-as 64515 neighbor upstream capability dynamic neighbor upstream prefix-list pl-allowed-adv out neighbor 10.1.1.1 peer-group upstream neighbor 10.1.1.1 description ACME ISP ! ip prefix-list pl-allowed-adv seq 5 permit 82.195.133.0/25 ip prefix-list pl-allowed-adv seq 10 deny any @end example A more complex example. With upstream, peer and customer sessions. Advertising global prefixes and NO_EXPORT prefixes and providing actions for customer routes based on community values. Extensive use of route-maps and the 'call' feature to support selective advertising of prefixes. This example is intended as guidance only, it has NOT been tested and almost certainly containts silly mistakes, if not serious flaws. @example router bgp 64512 bgp router-id 10.236.87.1 network 10.123.456.0/24 network 10.123.456.128/25 route-map rm-no-export neighbor upstream capability dynamic neighbor upstream route-map rm-upstream-out out neighbor cust capability dynamic neighbor cust route-map rm-cust-in in neighbor cust route-map rm-cust-out out neighbor cust send-community both neighbor peer capability dynamic neighbor peer route-map rm-peer-in in neighbor peer route-map rm-peer-out out neighbor peer send-community both neighbor 10.1.1.1 remote-as 64515 neighbor 10.1.1.1 peer-group upstream neighbor 10.2.1.1 remote-as 64516 neighbor 10.2.1.1 peer-group upstream neighbor 10.3.1.1 remote-as 64517 neighbor 10.3.1.1 peer-group cust-default neighbor 10.3.1.1 description customer1 neighbor 10.3.1.1 prefix-list pl-cust1-network in neighbor 10.4.1.1 remote-as 64518 neighbor 10.4.1.1 peer-group cust neighbor 10.4.1.1 prefix-list pl-cust2-network in neighbor 10.4.1.1 description customer2 neighbor 10.5.1.1 remote-as 64519 neighbor 10.5.1.1 peer-group peer neighbor 10.5.1.1 prefix-list pl-peer1-network in neighbor 10.5.1.1 description peer AS 1 neighbor 10.6.1.1 remote-as 64520 neighbor 10.6.1.1 peer-group peer neighbor 10.6.1.1 prefix-list pl-peer2-network in neighbor 10.6.1.1 description peer AS 2 ! ip prefix-list pl-default permit 0.0.0.0/0 ! ip prefix-list pl-upstream-peers permit 10.1.1.1/32 ip prefix-list pl-upstream-peers permit 10.2.1.1/32 ! ip prefix-list pl-cust1-network permit 10.3.1.0/24 ip prefix-list pl-cust1-network permit 10.3.2.0/24 ! ip prefix-list pl-cust2-network permit 10.4.1.0/24 ! ip prefix-list pl-peer1-network permit 10.5.1.0/24 ip prefix-list pl-peer1-network permit 10.5.2.0/24 ip prefix-list pl-peer1-network permit 192.168.0.0/24 ! ip prefix-list pl-peer2-network permit 10.6.1.0/24 ip prefix-list pl-peer2-network permit 10.6.2.0/24 ip prefix-list pl-peer2-network permit 192.168.1.0/24 ip prefix-list pl-peer2-network permit 192.168.2.0/24 ip prefix-list pl-peer2-network permit 172.16.1/24 ! ip as-path access-list asp-own-as permit ^$ ip as-path access-list asp-own-as permit _64512_ ! ! ################################################################# ! Match communities we provide actions for, on routes receives from ! customers. Communities values of :X, with X, have actions: ! ! 100 - blackhole the prefix ! 200 - set no_export ! 300 - advertise only to other customers ! 400 - advertise only to upstreams ! 500 - set no_export when advertising to upstreams ! 2X00 - set local_preference to X00 ! ! blackhole the prefix of the route ip community-list standard cm-blackhole permit 64512:100 ! ! set no-export community before advertising ip community-list standard cm-set-no-export permit 64512:200 ! ! advertise only to other customers ip community-list standard cm-cust-only permit 64512:300 ! ! advertise only to upstreams ip community-list standard cm-upstream-only permit 64512:400 ! ! advertise to upstreams with no-export ip community-list standard cm-upstream-noexport permit 64512:500 ! ! set local-pref to least significant 3 digits of the community ip community-list standard cm-prefmod-100 permit 64512:2100 ip community-list standard cm-prefmod-200 permit 64512:2200 ip community-list standard cm-prefmod-300 permit 64512:2300 ip community-list standard cm-prefmod-400 permit 64512:2400 ip community-list expanded cme-prefmod-range permit 64512:2... ! ! Informational communities ! ! 3000 - learned from upstream ! 3100 - learned from customer ! 3200 - learned from peer ! ip community-list standard cm-learnt-upstream permit 64512:3000 ip community-list standard cm-learnt-cust permit 64512:3100 ip community-list standard cm-learnt-peer permit 64512:3200 ! ! ################################################################### ! Utility route-maps ! ! These utility route-maps generally should not used to permit/deny ! routes, i.e. they do not have meaning as filters, and hence probably ! should be used with 'on-match next'. These all finish with an empty ! permit entry so as not interfere with processing in the caller. ! route-map rm-no-export permit 10 set community additive no-export route-map rm-no-export permit 20 ! route-map rm-blackhole permit 10 description blackhole, up-pref and ensure it cant escape this AS set ip next-hop 127.0.0.1 set local-preference 10 set community additive no-export route-map rm-blackhole permit 20 ! ! Set local-pref as requested route-map rm-prefmod permit 10 match community cm-prefmod-100 set local-preference 100 route-map rm-prefmod permit 20 match community cm-prefmod-200 set local-preference 200 route-map rm-prefmod permit 30 match community cm-prefmod-300 set local-preference 300 route-map rm-prefmod permit 40 match community cm-prefmod-400 set local-preference 400 route-map rm-prefmod permit 50 ! ! Community actions to take on receipt of route. route-map rm-community-in permit 10 description check for blackholing, no point continuing if it matches. match community cm-blackhole call rm-blackhole route-map rm-community-in permit 20 match community cm-set-no-export call rm-no-export on-match next route-map rm-community-in permit 30 match community cme-prefmod-range call rm-prefmod route-map rm-community-in permit 40 ! ! ##################################################################### ! Community actions to take when advertising a route. ! These are filtering route-maps, ! ! Deny customer routes to upstream with cust-only set. route-map rm-community-filt-to-upstream deny 10 match community cm-learnt-cust match community cm-cust-only route-map rm-community-filt-to-upstream permit 20 ! ! Deny customer routes to other customers with upstream-only set. route-map rm-community-filt-to-cust deny 10 match community cm-learnt-cust match community cm-upstream-only route-map rm-community-filt-to-cust permit 20 ! ! ################################################################### ! The top-level route-maps applied to sessions. Further entries could ! be added obviously.. ! ! Customers route-map rm-cust-in permit 10 call rm-community-in on-match next route-map rm-cust-in permit 20 set community additive 64512:3100 route-map rm-cust-in permit 30 ! route-map rm-cust-out permit 10 call rm-community-filt-to-cust on-match next route-map rm-cust-out permit 20 ! ! Upstream transit ASes route-map rm-upstream-out permit 10 description filter customer prefixes which are marked cust-only call rm-community-filt-to-upstream on-match next route-map rm-upstream-out permit 20 description only customer routes are provided to upstreams/peers match community cm-learnt-cust ! ! Peer ASes ! outbound policy is same as for upstream route-map rm-peer-out permit 10 call rm-upstream-out ! route-map rm-peer-in permit 10 set community additive 64512:3200 @end example quagga-0.99.24.1/doc/basic.texi0000644000175000017500000003756112476520570012771 00000000000000@node Basic commands @chapter Basic commands There are five routing daemons in use, and there is one manager daemon. These daemons may be located on separate machines from the manager daemon. Each of these daemons will listen on a particular port for incoming VTY connections. The routing daemons are: @itemize @bullet @item @command{ripd}, @command{ripngd}, @command{ospfd}, @command{ospf6d}, @command{bgpd} @item @command{zebra} @end itemize The following sections discuss commands common to all the routing daemons. @menu * Config Commands:: Commands used in config files * Terminal Mode Commands:: Common commands used in a VTY * Common Invocation Options:: Starting the daemons * Virtual Terminal Interfaces:: Interacting with the daemons @end menu @node Config Commands @section Config Commands @cindex Configuration files for running the software @c A -not configuration files for installing the software @cindex Files for running configurations @cindex Modifying the herd's behavior @cindex Getting the herd running @menu * Basic Config Commands:: Some of the generic config commands * Sample Config File:: An example config file @end menu In a config file, you can write the debugging options, a vty's password, routing daemon configurations, a log file name, and so forth. This information forms the initial command set for a routing beast as it is starting. Config files are generally found in: @itemize @w{} @item @file{@value{INSTALL_PREFIX_ETC}/*.conf} @end itemize Each of the daemons has its own config file. For example, zebra's default config file name is: @itemize @w{} @item @file{@value{INSTALL_PREFIX_ETC}/zebra.conf} @end itemize The daemon name plus @file{.conf} is the default config file name. You can specify a config file using the @kbd{-f} or @kbd{--config-file} options when starting the daemon. @node Basic Config Commands @subsection Basic Config Commands @deffn Command {hostname @var{hostname}} {} Set hostname of the router. @end deffn @deffn Command {password @var{password}} {} Set password for vty interface. If there is no password, a vty won't accept connections. @end deffn @deffn Command {enable password @var{password}} {} Set enable password. @end deffn @deffn Command {log trap @var{level}} {} @deffnx Command {no log trap} {} These commands are deprecated and are present only for historical compatibility. The log trap command sets the current logging level for all enabled logging destinations, and it sets the default for all future logging commands that do not specify a level. The normal default logging level is debugging. The @code{no} form of the command resets the default level for future logging commands to debugging, but it does not change the logging level of existing logging destinations. @end deffn @deffn Command {log stdout} {} @deffnx Command {log stdout @var{level}} {} @deffnx Command {no log stdout} {} Enable logging output to stdout. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to stdout. The @code{level} argument must have one of these values: emergencies, alerts, critical, errors, warnings, notifications, informational, or debugging. Note that the existing code logs its most important messages with severity @code{errors}. @end deffn @deffn Command {log file @var{filename}} {} @deffnx Command {log file @var{filename} @var{level}} {} @deffnx Command {no log file} {} If you want to log into a file, please specify @code{filename} as in this example: @example log file /var/log/quagga/bgpd.log informational @end example If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to a file. Note: if you do not configure any file logging, and a daemon crashes due to a signal or an assertion failure, it will attempt to save the crash information in a file named /var/tmp/quagga..crashlog. For security reasons, this will not happen if the file exists already, so it is important to delete the file after reporting the crash information. @end deffn @deffn Command {log syslog} {} @deffnx Command {log syslog @var{level}} {} @deffnx Command {no log syslog} {} Enable logging output to syslog. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to syslog. @end deffn @deffn Command {log monitor} {} @deffnx Command {log monitor @var{level}} {} @deffnx Command {no log monitor} {} Enable logging output to vty terminals that have enabled logging using the @code{terminal monitor} command. By default, monitor logging is enabled at the debugging level, but this command (or the deprecated @code{log trap} command) can be used to change the monitor logging level. If the optional second argument specifying the logging level is not present, the default logging level (typically debugging, but can be changed using the deprecated @code{log trap} command) will be used. The @code{no} form of the command disables logging to terminal monitors. @end deffn @deffn Command {log facility @var{facility}} {} @deffnx Command {no log facility} {} This command changes the facility used in syslog messages. The default facility is @code{daemon}. The @code{no} form of the command resets the facility to the default @code{daemon} facility. @end deffn @deffn Command {log record-priority} {} @deffnx Command {no log record-priority} {} To include the severity in all messages logged to a file, to stdout, or to a terminal monitor (i.e. anything except syslog), use the @code{log record-priority} global configuration command. To disable this option, use the @code{no} form of the command. By default, the severity level is not included in logged messages. Note: some versions of syslogd (including Solaris) can be configured to include the facility and level in the messages emitted. @end deffn @deffn Command {log timestamp precision @var{<0-6>}} {} @deffnx Command {no log timestamp precision} {} This command sets the precision of log message timestamps to the given number of digits after the decimal point. Currently, the value must be in the range 0 to 6 (i.e. the maximum precision is microseconds). To restore the default behavior (1-second accuracy), use the @code{no} form of the command, or set the precision explicitly to 0. @example @group log timestamp precision 3 @end group @end example In this example, the precision is set to provide timestamps with millisecond accuracy. @end deffn @deffn Command {service password-encryption} {} Encrypt password. @end deffn @deffn Command {service advanced-vty} {} Enable advanced mode VTY. @end deffn @deffn Command {service terminal-length @var{<0-512>}} {} Set system wide line configuration. This configuration command applies to all VTY interfaces. @end deffn @deffn Command {line vty} {} Enter vty configuration mode. @end deffn @deffn Command {banner motd default} {} Set default motd string. @end deffn @deffn Command {no banner motd} {} No motd banner string will be printed. @end deffn @deffn {Line Command} {exec-timeout @var{minute}} {} @deffnx {Line Command} {exec-timeout @var{minute} @var{second}} {} Set VTY connection timeout value. When only one argument is specified it is used for timeout value in minutes. Optional second argument is used for timeout value in seconds. Default timeout value is 10 minutes. When timeout value is zero, it means no timeout. @end deffn @deffn {Line Command} {no exec-timeout} {} Do not perform timeout at all. This command is as same as @command{exec-timeout 0 0}. @end deffn @deffn {Line Command} {access-class @var{access-list}} {} Restrict vty connections with an access list. @end deffn @node Sample Config File @subsection Sample Config File Below is a sample configuration file for the zebra daemon. @example @group ! ! Zebra configuration file ! hostname Router password zebra enable password zebra ! log stdout ! ! @end group @end example '!' and '#' are comment characters. If the first character of the word is one of the comment characters then from the rest of the line forward will be ignored as a comment. @example password zebra!password @end example If a comment character is not the first character of the word, it's a normal character. So in the above example '!' will not be regarded as a comment and the password is set to 'zebra!password'. @node Terminal Mode Commands @section Terminal Mode Commands @deffn Command {write terminal} {} Displays the current configuration to the vty interface. @end deffn @deffn Command {write file} {} Write current configuration to configuration file. @end deffn @deffn Command {configure terminal} {} Change to configuration mode. This command is the first step to configuration. @end deffn @deffn Command {terminal length @var{<0-512>}} {} Set terminal display length to @var{<0-512>}. If length is 0, no display control is performed. @end deffn @deffn Command {who} {} Show a list of currently connected vty sessions. @end deffn @deffn Command {list} {} List all available commands. @end deffn @deffn Command {show version} {} Show the current version of @value{PACKAGE_NAME} and its build host information. @end deffn @deffn Command {show logging} {} Shows the current configuration of the logging system. This includes the status of all logging destinations. @end deffn @deffn Command {logmsg @var{level} @var{message}} {} Send a message to all logging destinations that are enabled for messages of the given severity. @end deffn @node Common Invocation Options @section Common Invocation Options @c COMMON_OPTIONS @c OPTIONS section of the man page These options apply to all @value{PACKAGE_NAME} daemons. @table @samp @item -d @itemx --daemon Runs in daemon mode. @item -f @var{file} @itemx --config_file=@var{file} Set configuration file name. @item -h @itemx --help Display this help and exit. @item -i @var{file} @itemx --pid_file=@var{file} Upon startup the process identifier of the daemon is written to a file, typically in @file{/var/run}. This file can be used by the init system to implement commands such as @command{@dots{}/init.d/zebra status}, @command{@dots{}/init.d/zebra restart} or @command{@dots{}/init.d/zebra stop}. The file name is an run-time option rather than a configure-time option so that multiple routing daemons can be run simultaneously. This is useful when using @value{PACKAGE_NAME} to implement a routing looking glass. One machine can be used to collect differing routing views from differing points in the network. @item -A @var{address} @itemx --vty_addr=@var{address} Set the VTY local address to bind to. If set, the VTY socket will only be bound to this address. @item -P @var{port} @itemx --vty_port=@var{port} Set the VTY TCP port number. If set to 0 then the TCP VTY sockets will not be opened. @item -u @var{user} @itemx --vty_addr=@var{user} Set the user and group to run as. @item -v @itemx --version Print program version. @end table @node Virtual Terminal Interfaces @section Virtual Terminal Interfaces VTY -- Virtual Terminal [aka TeletYpe] Interface is a command line interface (CLI) for user interaction with the routing daemon. @menu * VTY Overview:: Basics about VTYs * VTY Modes:: View, Enable, and Other VTY modes * VTY CLI Commands:: Commands for movement, edition, and management @end menu @node VTY Overview @subsection VTY Overview VTY stands for Virtual TeletYpe interface. It means you can connect to the daemon via the telnet protocol. To enable a VTY interface, you have to setup a VTY password. If there is no VTY password, one cannot connect to the VTY interface at all. @example @group % telnet localhost 2601 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Hello, this is @value{PACKAGE_NAME} (version @value{VERSION}) @value{COPYRIGHT_STR} User Access Verification Password: XXXXX Router> ? enable Turn on privileged commands exit Exit current mode and down to previous mode help Description of the interactive help system list Print command list show Show running system information who Display who is on a vty Router> enable Password: XXXXX Router# configure terminal Router(config)# interface eth0 Router(config-if)# ip address 10.0.0.1/8 Router(config-if)# ^Z Router# @end group @end example '?' is very useful for looking up commands. @node VTY Modes @subsection VTY Modes There are three basic VTY modes: @menu * VTY View Mode:: Mode for read-only interaction * VTY Enable Mode:: Mode for read-write interaction * VTY Other Modes:: Special modes (tftp, etc) @end menu There are commands that may be restricted to specific VTY modes. @node VTY View Mode @subsubsection VTY View Mode @c to be written (gpoul) This mode is for read-only access to the CLI. One may exit the mode by leaving the system, or by entering @code{enable} mode. @node VTY Enable Mode @subsubsection VTY Enable Mode @c to be written (gpoul) This mode is for read-write access to the CLI. One may exit the mode by leaving the system, or by escaping to view mode. @node VTY Other Modes @subsubsection VTY Other Modes @c to be written (gpoul) This page is for describing other modes. @node VTY CLI Commands @subsection VTY CLI Commands Commands that you may use at the command-line are described in the following three subsubsections. @menu * CLI Movement Commands:: Commands for moving the cursor about * CLI Editing Commands:: Commands for changing text * CLI Advanced Commands:: Other commands, session management and so on @end menu @node CLI Movement Commands @subsubsection CLI Movement Commands These commands are used for moving the CLI cursor. The @key{C} character means press the Control Key. @table @kbd @item C-f @itemx @key{RIGHT} @kindex C-f @kindex @key{RIGHT} Move forward one character. @item C-b @itemx @key{LEFT} @kindex C-b @kindex @key{LEFT} Move backward one character. @item M-f @kindex M-f Move forward one word. @item M-b @kindex M-b Move backward one word. @item C-a @kindex C-a Move to the beginning of the line. @item C-e @kindex C-e Move to the end of the line. @end table @node CLI Editing Commands @subsubsection CLI Editing Commands These commands are used for editing text on a line. The @key{C} character means press the Control Key. @table @kbd @item C-h @itemx @key{DEL} @kindex C-h @kindex @key{DEL} Delete the character before point. @item C-d @kindex C-d Delete the character after point. @item M-d @kindex M-d Forward kill word. @item C-w @kindex C-w Backward kill word. @item C-k @kindex C-k Kill to the end of the line. @item C-u @kindex C-u Kill line from the beginning, erasing input. @item C-t @kindex C-t Transpose character. @end table @node CLI Advanced Commands @subsubsection CLI Advanced Commands There are several additional CLI commands for command line completions, insta-help, and VTY session management. @table @kbd @item C-c @kindex C-c Interrupt current input and moves to the next line. @item C-z @kindex C-z End current configuration session and move to top node. @item C-n @itemx @key{DOWN} @kindex C-n @kindex @key{DOWN} Move down to next line in the history buffer. @item C-p @itemx @key{UP} @kindex C-p @kindex @key{UP} Move up to previous line in the history buffer. @item TAB @kindex @key{TAB} Use command line completion by typing @key{TAB}. @item ? @kindex @key{?} You can use command line help by typing @code{help} at the beginning of the line. Typing @kbd{?} at any point in the line will show possible completions. @end table quagga-0.99.24.1/doc/babeld.texi0000644000175000017500000001070412476520570013107 00000000000000@c -*-texinfo-*- @c This is part of the Quagga Manual. @c @value{COPYRIGHT_STR} @c See file quagga.texi for copying conditions. @node Babel @chapter Babel Babel is an interior gateway protocol that is suitable both for wired networks and for wireless mesh networks. Babel has been described as ``RIP on speed'' --- it is based on the same principles as RIP, but includes a number of refinements that make it react much faster to topology changes without ever counting to infinity, and allow it to perform reliable link quality estimation on wireless links. Babel is a double-stack routing protocol, meaning that a single Babel instance is able to perform routing for both IPv4 and IPv6. Quagga implements Babel as described in RFC6126. @menu * Configuring babeld:: * Babel configuration:: * Babel redistribution:: * Show Babel information:: * Babel debugging commands:: @end menu @node Configuring babeld, Babel configuration, Babel, Babel @section Configuring babeld The @command{babeld} daemon can be invoked with any of the common options (@pxref{Common Invocation Options}). The @command{zebra} daemon must be running before @command{babeld} is invoked. Also, if @command{zebra} is restarted then @command{babeld} must be too. Configuration of @command{babeld} is done in its configuration file @file{babeld.conf}. @node Babel configuration, Babel redistribution, Configuring babeld, Babel @section Babel configuration @deffn Command {router babel} {} @deffnx Command {no router babel} {} Enable or disable Babel routing. @end deffn @deffn {Babel Command} {network @var{ifname}} {} @deffnx {Babel Command} {no network @var{ifname}} {} Enable or disable Babel on the given interface. @end deffn @deffn {Interface Command} {babel wired} {} @deffnx {Interface Command} {babel wireless} {} Specifies whether this interface is wireless, which disables a number of optimisations that are only correct on wired interfaces. Specifying @code{wireless} (the default) is always correct, but may cause slower convergence and extra routing traffic. @end deffn @deffn {Interface Command} {babel split-horizon} @deffnx {Interface Command} {no babel split-horizon} Specifies whether to perform split-horizon on the interface. Specifying @code{no babel split-horizon} (the default) is always correct, while @code{babel split-horizon} is an optimisation that should only be used on symmetric and transitive (wired) networks. @end deffn @deffn {Interface Command} {babel hello-interval <20-655340>} Specifies the time in milliseconds between two scheduled hellos. On wired links, Babel notices a link failure within two hello intervals; on wireless links, the link quality value is reestimated at every hello interval. The default is 4000@dmn{ms}. @end deffn @deffn {Interface Command} {babel update-interval <20-655340>} Specifies the time in milliseconds between two scheduled updates. Since Babel makes extensive use of triggered updates, this can be set to fairly high values on links with little packet loss. The default is 20000@dmn{ms}. @end deffn @deffn {Babel Command} {babel resend-delay <20-655340>} Specifies the time in milliseconds after which an ``important'' request or update will be resent. The default is 2000@dmn{ms}. You probably don't want to tweak this value. @end deffn @node Babel redistribution, Show Babel information, Babel configuration, Babel @section Babel redistribution @deffn {Babel command} {redistribute @var{kind}} @deffnx {Babel command} {no redistribute @var{kind}} Specify which kind of routes should be redistributed into Babel. @end deffn @node Show Babel information, Babel debugging commands, Babel redistribution, Babel @section Show Babel information @deffn {Command} {show babel database} {} @deffnx {Command} {show babel interface} {} @deffnx {Command} {show babel neighbour} {} @deffnx {Command} {show babel parameters} {} These commands dump various parts of @command{babeld}'s internal state. They are mostly useful for troubleshooting. @end deffn @node Babel debugging commands, , Show Babel information, Babel @section Babel debugging commands @deffn {Babel Command} {debug babel @var{kind}} {} @deffnx {Babel Command} {no debug babel @var{kind}} {} Enable or disable debugging messages of a given kind. @var{kind} can be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout}, @samp{interface}, @samp{route} or @samp{all}. Note that if you have compiled with the NO_DEBUG flag, then these commands aren't available. @end deffn quagga-0.99.24.1/doc/appendix.texi0000644000175000017500000002556112476520570013515 00000000000000@node Packet Binary Dump Format @appendix Packet Binary Dump Format Quagga can dump routing protocol packet into file with a binary format (@pxref{Dump BGP packets and table}). It seems to be better that we share the MRT's header format for backward compatibility with MRT's dump logs. We should also define the binary format excluding the header, because we must support both IP v4 and v6 addresses as socket addresses and / or routing entries. In the last meeting, we discussed to have a version field in the header. But Masaki told us that we can define new `type' value rather than having a `version' field, and it seems to be better because we don't need to change header format. Here is the common header format. This is same as that of MRT. @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Type | Subtype | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example Where State is the value defined in RFC1771. If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_STATE_CHANGE, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Old State | New State | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example Where BGP Message Packet is the whole contents of the BGP4 message including header portion. If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_MESSAGE, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source AS number | Destination AS number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Interface Index | Address Family | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination IP address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Message Packet | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, and Address Family == IP (version 4) @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example If `type' is PROTOCOL_BGP4MP, `subtype' is BGP4MP_ENTRY, and Address Family == IP version 6 @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | Status | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time Last Change | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Family | SAFI | Next-Hop-Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Next Hop Address (Cont'd) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Prefix Length | Address Prefix [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Address Prefix (cont'd) [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Attribute Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | BGP Attribute [variable length] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example BGP4 Attribute must not contain MP_UNREACH_NLRI. If BGP Attribute has MP_REACH_NLRI field, it must has zero length NLRI, e.g., MP_REACH_NLRI has only Address Family, SAFI and next-hop values. If `type' is PROTOCOL_BGP4MP and `subtype' is BGP4MP_SNAPSHOT, @example @group 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | View # | File Name [variable] | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @end group @end example The file specified in "File Name" contains all routing entries, which are in the format of ``subtype == BGP4MP_ENTRY''. @example @group Constants: /* type value */ #define MSG_PROTOCOL_BGP4MP 16 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 @end group @end example quagga-0.99.24.1/doc/defines.texi.in0000644000175000017500000000074012476520570013717 00000000000000@c -*- texinfo -*- @c @configure_input@ @c Set variables @set PACKAGE_NAME @PACKAGE_NAME@ @set PACKAGE_TARNAME @PACKAGE_TARNAME@ @set PACKAGE_STRING @PACKAGE_STRING@ @set AUTHORS Kunihiro Ishiguro, et al. @set COPYRIGHT_YEAR 1999-2005 @set COPYRIGHT_STR Copyright @copyright{} @value{COPYRIGHT_YEAR} @value{AUTHORS} @c These may vary with installation environment. @set INSTALL_PREFIX_ETC /etc/quagga @set INSTALL_PREFIX_SBIN /usr/sbin @set INSTALL_PREFIX_STATE /var/run/quagga quagga-0.99.24.1/doc/Makefile.am0000644000175000017500000000603712476520570013043 00000000000000## Process this file with automake to produce Makefile.in. # Dia, the version i have at least, doesn't do very good EPS output # (some of the text is scaled strangely). So this will work, but # it is probably better to use something like gimp to convert the # dia exported PNG files to EPS manually. # # Here we use 'convert' from the well known 'ImageMagick' package # to do conversion from png to eps/pdf for figures. # PDF form is required for quagga.pdf, using PDFTex at least. # # TeX implementation, which we depend on already anyway. # # dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf SUFFIXES = .png .eps .dia .pdf DIATOPNG = dia -t png -e DIATOEPS = dia -t eps -e PNGTOEPS = convert -antialias -contrast -despeckle PNGTOPDF = $(PNGTOEPS) EPSTOPDF = epstopdf # The figure sources figures_names_parts = -normal-processing -rs-processing \ _topologies_full _topologies_rs figures_sources = $(figures_names_parts:%=fig%.dia) figures_png = $(figures_names_parts:%=fig%.png) figures_pdf = $(figures_names_parts:%=fig%.pdf) figures_eps = $(figures_names_parts:%=fig%.eps) figures_txt = $(figures_names_parts:%=fig%.txt) # rather twisted logic because we have to build PDFs of the EPS figures for # PDFTex and yet build one PDF, quagga.pdf, from texi source. Which means we # cant rely on a single automatic rule for *.pdf, eg the one automatically # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. # Built from defines.texi.in BUILT_SOURCES = defines.texi info_TEXINFOS = quagga.texi # Have to manually specify the quagga.pdf rule in order to allow # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< || true quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ snmptrap.texi $(figures_txt) .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< man_MANS = if PIMD man_MANS += pimd.8 endif if BGPD man_MANS += bgpd.8 endif if ISISD man_MANS += isisd.8 endif if OSPF6D man_MANS += ospf6d.8 endif if OSPFCLIENT man_MANS += ospfclient.8 endif if OSPFD man_MANS += ospfd.8 endif if RIPD man_MANS += ripd.8 endif if RIPNGD man_MANS += ripngd.8 endif if VTYSH man_MANS += vtysh.1 endif if WATCHQUAGGA man_MANS += watchquagga.8 endif if ZEBRA man_MANS += zebra.8 endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ quagga-0.99.24.1/doc/Makefile.in0000644000175000017500000010015012476521250013037 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ @PIMD_TRUE@am__append_1 = pimd.8 @BGPD_TRUE@am__append_2 = bgpd.8 @ISISD_TRUE@am__append_3 = isisd.8 @OSPF6D_TRUE@am__append_4 = ospf6d.8 @OSPFCLIENT_TRUE@am__append_5 = ospfclient.8 @OSPFD_TRUE@am__append_6 = ospfd.8 @RIPD_TRUE@am__append_7 = ripd.8 @RIPNGD_TRUE@am__append_8 = ripngd.8 @VTYSH_TRUE@am__append_9 = vtysh.1 @WATCHQUAGGA_TRUE@am__append_10 = watchquagga.8 @ZEBRA_TRUE@am__append_11 = zebra.8 subdir = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/defines.texi.in $(quagga_TEXINFOS) mdate-sh \ $(srcdir)/version.texi $(srcdir)/stamp-vti texinfo.tex ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = defines.texi CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = AM_V_DVIPS = $(am__v_DVIPS_@AM_V@) am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@) am__v_DVIPS_0 = @echo " DVIPS " $@; am__v_DVIPS_1 = AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@) am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@) am__v_MAKEINFO_0 = @echo " MAKEINFO" $@; am__v_MAKEINFO_1 = AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@) am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@) am__v_INFOHTML_0 = @echo " INFOHTML" $@; am__v_INFOHTML_1 = AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@) am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@) am__v_TEXI2DVI_0 = @echo " TEXI2DVI" $@; am__v_TEXI2DVI_1 = AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@) am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@) am__v_TEXI2PDF_0 = @echo " TEXI2PDF" $@; am__v_TEXI2PDF_1 = AM_V_texinfo = $(am__v_texinfo_@AM_V@) am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@) am__v_texinfo_0 = -q am__v_texinfo_1 = AM_V_texidevnull = $(am__v_texidevnull_@AM_V@) am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@) am__v_texidevnull_0 = > /dev/null am__v_texidevnull_1 = INFO_DEPS = $(srcdir)/quagga.info am__TEXINFO_TEX_DIR = $(srcdir) DVIS = quagga.dvi PDFS = quagga.pdf PSS = quagga.ps HTMLS = quagga.html TEXINFOS = quagga.texi TEXI2DVI = texi2dvi TEXI2PDF = $(TEXI2DVI) --pdf --batch MAKEINFOHTML = $(MAKEINFO) --html AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS) DVIPS = dvips am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__installdirs = "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(man8dir)" am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # Dia, the version i have at least, doesn't do very good EPS output # (some of the text is scaled strangely). So this will work, but # it is probably better to use something like gimp to convert the # dia exported PNG files to EPS manually. # # Here we use 'convert' from the well known 'ImageMagick' package # to do conversion from png to eps/pdf for figures. # PDF form is required for quagga.pdf, using PDFTex at least. # # TeX implementation, which we depend on already anyway. # # dia -> (dia) -> png -> (convert) -> eps -> (epstopdf) -> pdf SUFFIXES = .png .eps .dia .pdf DIATOPNG = dia -t png -e DIATOEPS = dia -t eps -e PNGTOEPS = convert -antialias -contrast -despeckle PNGTOPDF = $(PNGTOEPS) EPSTOPDF = epstopdf # The figure sources figures_names_parts = -normal-processing -rs-processing \ _topologies_full _topologies_rs figures_sources = $(figures_names_parts:%=fig%.dia) figures_png = $(figures_names_parts:%=fig%.png) figures_pdf = $(figures_names_parts:%=fig%.pdf) figures_eps = $(figures_names_parts:%=fig%.eps) figures_txt = $(figures_names_parts:%=fig%.txt) # rather twisted logic because we have to build PDFs of the EPS figures for # PDFTex and yet build one PDF, quagga.pdf, from texi source. Which means we # cant rely on a single automatic rule for *.pdf, eg the one automatically # provided by automake. If you are an automake wizard, please feel free to # compact it somehow. # Built from defines.texi.in BUILT_SOURCES = defines.texi info_TEXINFOS = quagga.texi quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \ install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \ overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \ snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \ snmptrap.texi $(figures_txt) man_MANS = $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_10) $(am__append_11) EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ $(figures_sources) $(figures_png) $(figures_txt) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .png .eps .dia .pdf .dvi .html .info .ps .texi $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): defines.texi: $(top_builddir)/config.status $(srcdir)/defines.texi.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs .texi.info: $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \ am__cwd=`pwd` && $(am__cd) $(srcdir) && \ rm -rf $$backupdir && mkdir $$backupdir && \ if ($(MAKEINFO) --version) >/dev/null 2>&1; then \ for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \ if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \ done; \ else :; fi && \ cd "$$am__cwd"; \ if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $@ $<; \ then \ rc=0; \ $(am__cd) $(srcdir); \ else \ rc=$$?; \ $(am__cd) $(srcdir) && \ $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \ fi; \ rm -rf $$backupdir; exit $$rc .texi.dvi: $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \ $< .texi.pdf: $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \ $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \ $< .texi.html: $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp) $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \ -o $(@:.html=.htp) $<; \ then \ rm -rf $@ && mv $(@:.html=.htp) $@; \ else \ rm -rf $(@:.html=.htp); exit 1; \ fi $(srcdir)/quagga.info: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) quagga.dvi: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) quagga.html: quagga.texi $(srcdir)/version.texi $(quagga_TEXINFOS) $(srcdir)/version.texi: $(srcdir)/stamp-vti $(srcdir)/stamp-vti: quagga.texi $(top_srcdir)/configure @(dir=.; test -f ./quagga.texi || dir=$(srcdir); \ set `$(SHELL) $(srcdir)/mdate-sh $$dir/quagga.texi`; \ echo "@set UPDATED $$1 $$2 $$3"; \ echo "@set UPDATED-MONTH $$2 $$3"; \ echo "@set EDITION $(VERSION)"; \ echo "@set VERSION $(VERSION)") > vti.tmp @cmp -s vti.tmp $(srcdir)/version.texi \ || (echo "Updating $(srcdir)/version.texi"; \ cp vti.tmp $(srcdir)/version.texi) -@rm -f vti.tmp @cp $(srcdir)/version.texi $@ mostlyclean-vti: -rm -f vti.tmp maintainer-clean-vti: -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi .dvi.ps: $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \ $(DVIPS) $(AM_V_texinfo) -o $@ $< uninstall-dvi-am: @$(NORMAL_UNINSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \ rm -f "$(DESTDIR)$(dvidir)/$$f"; \ done uninstall-html-am: @$(NORMAL_UNINSTALL) @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \ rm -rf "$(DESTDIR)$(htmldir)/$$f"; \ done uninstall-info-am: @$(PRE_UNINSTALL) @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \ if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \ then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \ done; \ else :; fi @$(NORMAL_UNINSTALL) @list='$(INFO_DEPS)'; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \ (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \ echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \ rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \ else :; fi); \ done uninstall-pdf-am: @$(NORMAL_UNINSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \ rm -f "$(DESTDIR)$(pdfdir)/$$f"; \ done uninstall-ps-am: @$(NORMAL_UNINSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \ rm -f "$(DESTDIR)$(psdir)/$$f"; \ done dist-info: $(INFO_DEPS) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; \ for base in $$list; do \ case $$base in \ $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$base; then d=.; else d=$(srcdir); fi; \ base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \ for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \ if test -f $$file; then \ relfile=`expr "$$file" : "$$d/\(.*\)"`; \ test -f "$(distdir)/$$relfile" || \ cp -p $$file "$(distdir)/$$relfile"; \ else :; fi; \ done; \ done mostlyclean-aminfo: -rm -rf quagga.t2d quagga.t2p clean-aminfo: -test -z "quagga.dvi quagga.pdf quagga.ps quagga.html" \ || rm -rf quagga.dvi quagga.pdf quagga.ps quagga.html maintainer-clean-aminfo: @list='$(INFO_DEPS)'; for i in $$list; do \ i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \ echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \ rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \ done install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-info check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(INFO_DEPS) $(MANS) installdirs: for dir in "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: $(DVIS) html: html-am html-am: $(HTMLS) info: info-am info-am: $(INFO_DEPS) install-data-am: install-info-am install-man install-dvi: install-dvi-am install-dvi-am: $(DVIS) @$(NORMAL_INSTALL) @list='$(DVIS)'; test -n "$(dvidir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \ $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \ done install-exec-am: install-html: install-html-am install-html-am: $(HTMLS) @$(NORMAL_INSTALL) @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \ $(am__strip_dir) \ d2=$$d$$p; \ if test -d "$$d2"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \ $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \ echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \ $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \ else \ list2="$$list2 $$d2"; \ fi; \ done; \ test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \ done; } install-info: install-info-am install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \ $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \ fi; \ for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ esac; \ if test -f $$file; then d=.; else d=$(srcdir); fi; \ file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \ for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \ $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \ if test -f $$ifile; then \ echo "$$ifile"; \ else : ; fi; \ done; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done @$(POST_INSTALL) @if $(am__can_run_installinfo); then \ list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \ for file in $$list; do \ relfile=`echo "$$file" | sed 's|^.*/||'`; \ echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\ done; \ else : ; fi install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: $(PDFS) @$(NORMAL_INSTALL) @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done install-ps: install-ps-am install-ps-am: $(PSS) @$(NORMAL_INSTALL) @list='$(PSS)'; test -n "$(psdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \ mostlyclean-libtool mostlyclean-vti pdf: pdf-am pdf-am: $(PDFS) ps: ps-am ps-am: $(PSS) uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \ uninstall-man uninstall-pdf-am uninstall-ps-am uninstall-man: uninstall-man1 uninstall-man8 .MAKE: all check install install-am install-strip .PHONY: all all-am check check-am clean clean-aminfo clean-generic \ clean-libtool cscopelist-am ctags-am dist-info distclean \ distclean-generic distclean-libtool distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man1 install-man8 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-aminfo \ maintainer-clean-generic maintainer-clean-vti mostlyclean \ mostlyclean-aminfo mostlyclean-generic mostlyclean-libtool \ mostlyclean-vti pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dvi-am uninstall-html-am \ uninstall-info-am uninstall-man uninstall-man1 uninstall-man8 \ uninstall-pdf-am uninstall-ps-am # Have to manually specify the quagga.pdf rule in order to allow # us to have a generic automatic .pdf rule to build the figure sources # because it cant just work from the png's directly it seems - contrary # to the documentation... quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS) $(TEXI2PDF) -o "$@" $< || true .png.eps: $(PNGTOEPS) $< "$@" .png.pdf: $(PNGTOPDF) $< "$@" .dia.png: $(DIATOPNG) "$@" $< draft-zebra-00.txt: draft-zebra-00.ms groff -T ascii -ms $< > $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/doc/mpls/0000755000175000017500000000000012476521356012037 500000000000000quagga-0.99.24.1/doc/mpls/ospfd.conf0000644000175000017500000000305412476520570013740 00000000000000! ! Zebra configuration saved from vty ! 2001/03/16 22:07:53 ! hostname HOSTNAME password PASSWORD log file /var/log/ospfd.log ! debug ospf ism debug ospf nsm debug ospf lsa debug ospf zebra debug ospf event debug ospf packet all detail ! ! interface fxp0 ip ospf hello-interval 60 ip ospf dead-interval 240 mpls-te link metric 999 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xab ! interface de1 ip ospf hello-interval 60 ip ospf dead-interval 240 mpls-te link metric 111 mpls-te link max-bw 1.25e+06 mpls-te link max-rsv-bw 1.25e+06 mpls-te link unrsv-bw 0 1.25e+06 mpls-te link unrsv-bw 1 1.25e+06 mpls-te link unrsv-bw 2 1.25e+06 mpls-te link unrsv-bw 3 1.25e+06 mpls-te link unrsv-bw 4 1.25e+06 mpls-te link unrsv-bw 5 1.25e+06 mpls-te link unrsv-bw 6 1.25e+06 mpls-te link unrsv-bw 7 1.25e+06 mpls-te link rsc-clsclr 0xcd ! interface de0 mpls-te link metric 0 mpls-te link rsc-clsclr 0x0 ! interface lp0 ip ospf network point-to-point ! interface tun0 ip ospf network point-to-point ! interface sl0 ip ospf network point-to-point ! interface ppp0 ip ospf network point-to-point ! interface lo0 ! router ospf compatible rfc1583 network 192.168.0.0/16 area 1 ospf opaque-lsa mpls-te mpls-te router-address 1.2.3.4 ! line vty ! quagga-0.99.24.1/doc/mpls/opaque_lsa.txt0000644000175000017500000005505012476520570014653 000000000000001. List of "opaque-type dependent" callback functions per LSA-type. (N = 9,10,11) | | struct | list struct struct +-> +-------+ listnode listnode | head |-----> +------+ +------ | tail | | next |--------------------> | next | count | /--| prev |<---------------------| prev +-------+ | data |----+ | |///////| +------+ | +-------+ | | struct | ospf_opaque_tabent | +----------------------+ <--+ | opaque_type | +----------------------+ | (Callback functions) | +----------------------+ 2. Self-originated Opaque-LSAs per LSA-type. 2.1 Type-11 (AS-external) Opaque-LSAs struct ospf +---> +-------------------+ | |///////////////////| | +-------------------+ | | opaque | | +-------------------+ | |///////////////////| | +-------------------+ | | opaque_lsa_self |---+ | +-------------------+ | | |///////////////////| | | +-------------------+ | | | ......|.............................|....................................... : | | Almost common for type-9,10,11 LSA : : | +-----------------------+ : : | | : : | | struct : : | | list struct struct : : | +-> +-------+ listnode listnode : : | | head |-----> +------+ +------ : : | | tail | | next |--------------------> | next : : | | count | /--| prev |<---------------------| prev : : | +-------+ | data |---+ | : : | |///////| +------+ | : : | +-------+ | : : | | : : | struct | : : | opaque_info_per_type | : : | +-------------------+ <--------+ : : | | opaque_type | <------------+ : : | +-------------------+ | : : | | status | | : : | +-------------------+ | : : | | t_opaque_lsa_self | | : : | +-------------------+ | : : +-----| owner | | struct : : +-------------------+ | ospf_opaque_tabent : : | functab |-------------------> +---------------- : : +-------------------+ | | opaque_type : : | id_list |---+ | |(Callback Funcs) : : +-------------------+ | | | : : | | : : +-----------------------+ | : : | | : : | struct | : : | list struct | struct : : +-> +-------+ listnode | listnode : : | head |-----> +------+ | +------ : : | tail | | next |--------------------> | next : : | count | /--| prev |<---------------------| prev : : +-------+ | data |---+ | | : : |///////| +------+ | | : : +-------+ | | : : | | : : struct | | : : opaque_info_per_id | | : : +-------------------+ <--------+ | : : | opaque_id | | : : +-------------------+ | : : | t_opaque_lsa_self | | : : +-------------------+ | : : | opqctl_type |--------------+ : : +-------------------+ : : | lsa |---+ : : +-------------------+ | : : | : : struct | : : ospf_lsa | : : +-------------+ <-------+ : : |/////////////| struct : : +-------------+ lsa_header : : | data |--------------> +-------- : : +-------------+ | : : |/////////////| : : +-------------+ : : +--------| area | : : | +-------------+ : : --- |/////////////| : : +-------------+ : : +-----| oi | : : | +-------------+ : : --- : :..........................................................................: 2.2 Type-10 (area-local) Opaque-LSAs struct ospf +---------+ <-----------+ |/////////| | +---------+ | | struct | ospf_area | +--+---> +-----------------+ | | | | top |-----+ | | +-----------------+ | | |/////////////////| struct | | +-----------------+ ospf_lsa | | | router_lsa_self |-----------> +--------- | | +-----------------+ | | | | opaque_lsa_self |-----+ | | | +-----------------+ | | | |/////////////////| | | | +-----------------+ | | | | ...|..|.............................|....................................... : | | | Almost common for type-9,10,11 LSA : : | | +-----------------------+ : : | | | : : | | | struct : : | | | list struct struct : : | | +-> +-------+ listnode listnode : : | | | head |-----> +------+ +------ : : | | | tail | | next |--------------------> | next : : | | | count | /--| prev |<---------------------| prev : : | | +-------+ | data |---+ | : : | | |///////| +------+ | : : | | +-------+ | : : | | | : : | | struct | : : | | opaque_info_per_type | : : | | +-------------------+ <--------+ : : | | | opaque_type | <------------+ : : | | +-------------------+ | : : | | | status | | : : | | +-------------------+ | : : | | | t_opaque_lsa_self | | : : | | +-------------------+ | : : | +-----| owner | | struct : : | +-------------------+ | ospf_opaque_tabent : : | | functab |-------------------> +---------------- : : | +-------------------+ | | opaque_type : : | | id_list |---+ | |(Callback Funcs) : : | +-------------------+ | | | : : | | | : : | +-----------------------+ | : : | | | : : | | struct | : : | | list struct | struct : : | +-> +-------+ listnode | listnode : : | | head |-----> +------+ | +------ : : | | tail | | next |--------------------> | next : : | | count | /--| prev |<---------------------| prev : : | +-------+ | data |---+ | | : : | |///////| +------+ | | : : | +-------+ | | : : | | | : : | struct | | : : | opaque_info_per_id | | : : | +-------------------+ <--------+ | : : | | opaque_id | | : : | +-------------------+ | : : | | t_opaque_lsa_self | | : : | +-------------------+ | : : | | opqctl_type |--------------+ : : | +-------------------+ : : | | lsa |---+ : : | +-------------------+ | : : | | : : | struct | : : | ospf_lsa | : : | +-------------+ <-------+ : : | |/////////////| struct : : | +-------------+ lsa_header : : | | data |--------------> +-------- : : | +-------------+ | : : | |/////////////| : : | +-------------+ : : +--------| area | : : +-------------+ : : |/////////////| : : +-------------+ : : +-----| oi | : : | +-------------+ : : --- : :..........................................................................: 2.3 Type-9 (link-local) Opaque-LSAs struct ospf_area +------> +---------+ <---------+ | |/////////| | | +---------+ | | | | struct | | ospf_interface | | +-+-> +-----------------+ | | | | |/////////////////| | | | | +-----------------+ | | | | | area |---+ | | | +-----------------+ | | | |/////////////////| struct | | | +-----------------+ ospf_lsa | | | |network_lsa_self |-----------> +--------- | | | +-----------------+ | | | | | opaque_lsa_self |-----+ | | | | +-----------------+ | | | | |/////////////////| | | | | +-----------------+ | | | | | ...|..|.|...........................|....................................... : | | | | Almost common for type-9,10,11 LSA : : | | | +-----------------------+ : : | | | | : : | | | | struct : : | | | | list struct struct : : | | | +-> +-------+ listnode listnode : : | | | | head |-----> +------+ +------ : : | | | | tail | | next |--------------------> | next : : | | | | count | /--| prev |<---------------------| prev : : | | | +-------+ | data |---+ | : : | | | |///////| +------+ | : : | | | +-------+ | : : | | | | : : | | | struct | : : | | | opaque_info_per_type | : : | | | +-------------------+ <--------+ : : | | | | opaque_type | <------------+ : : | | | +-------------------+ | : : | | | | status | | : : | | | +-------------------+ | : : | | | | t_opaque_lsa_self | | : : | | | +-------------------+ | : : | | +---| owner | | struct : : | | +-------------------+ | ospf_opaque_tabent : : | | | functab |-------------------> +---------------- : : | | +-------------------+ | | opaque_type : : | | | id_list |---+ | |(Callback Funcs) : : | | +-------------------+ | | | : : | | | | : : | | +-----------------------+ | : : | | | | : : | | | struct | : : | | | list struct | struct : : | | +-> +-------+ listnode | listnode : : | | | head |-----> +------+ | +------ : : | | | tail | | next |--------------------> | next : : | | | count | /--| prev |<---------------------| prev : : | | +-------+ | data |---+ | | : : | | |///////| +------+ | | : : | | +-------+ | | : : | | | | : : | | struct | | : : | | opaque_info_per_id | | : : | | +-------------------+ <--------+ | : : | | | opaque_id | | : : | | +-------------------+ | : : | | | t_opaque_lsa_self | | : : | | +-------------------+ | : : | | | opqctl_type |--------------+ : : | | +-------------------+ : : | | | lsa |---+ : : | | +-------------------+ | : : | | | : : | | struct | : : | | ospf_lsa | : : | | +-------------+ <-------+ : : | | |/////////////| struct : : | | +-------------+ lsa_header : : | | | data |--------------> +-------- : : | | +-------------+ | : : | | |/////////////| : : | | +-------------+ : : +--|-----| area | : : | +-------------+ : : | |/////////////| : : | +-------------+ : : +-----| oi | : : +-------------+ : :..........................................................................: 3. Internal structures for MPLS-TE parameter management. struct ospf_mpls_te +-------------+ | status | +-------------+ | iflist |---+ +-------------+ | |(Router-TLV) | | +-------------+ | | +---------------------+ | | struct | list struct struct +---> +-------+ listnode listnode | head |-----> +------+ +------ | tail | | next |--------------------> | next | count | /--| prev |<---------------------| prev +-------+ | data |---+ | |///////| +------+ | +-------+ | | +--------------------------------+ | | struct | ospf_mpls_te_linkparms +-> +----------------+ | instance | struct +----------------+ interface | ifp |--------------------> +----------+ +----------------+ +----> |//////////| | area |----+ | +----------+ +----------------+ | | | info |-----+ | flags | | | +----------+ | +----------------+ | | |//////////| | | (Link-TLV) | | | +----------+ | +----------------+ | | | | (Link-SubTLVs) | | | struct | +----------------+ | | ospf_if_info | | | +----------+ <---+ | | |//////////| struct | | +----------+ ospf_area | | | oifs |-----+ +-> +--------------+ <----+ | +----------+ | | |//////////////| | | | +--------------+ | struct | | | route_table | | struct | +-----------+ <--+ | ospf_interface | | route_top | - - - - -. | +--------------+ <----+ | +-----------+ . | |//////////////| | | . | +--------------+ | | struct . | | ifp |------|----------+ route_node . | +--------------+ | +-----------+ < - - - - | |//////////////| | |///////////| | +--------------+ | +-----------+ +---| area | +-----------------| info | +--------------+ +-----------+ |//////////////| |///////////| +--------------+ +-----------+ quagga-0.99.24.1/doc/mpls/cli_summary.txt0000644000175000017500000000525512476520570015050 00000000000000Summary of CLI commands, expanded for Opaque-LSA/MPLS-TE. --------------------------------------------------------- router> show ip ospf database (asbr-summary|external|max-age|network|router|self-originate|summary|opaque-link|opaque-area|opaque-external) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) (self-originate|) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D (self-originate|) show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) A.B.C.D adv-router A.B.C.D show ip ospf database (asbr-summary|external|network|router|summary|opaque-link|opaque-area|opaque-external) adv-router A.B.C.D --> Add database items: opaque-link, opaque-area, opaque-external show mpls-te interface [INTERFACE] --> Show current MPLS-TE link-TLV parameters. If [INTERFACE] is omitted, all interfaces will be displayed. show mpls-te router --> Show current MPLS-TE Router-TLV parameters. router> enable router# router# configure terminal router(config)# interface [INTERFACE] router(config-if)# mpls-te link max-bw BANDWIDTH --> Set MPLS-TE link-TLV parameter: Maximum Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) mpls-te link max-rsv-bw BANDWIDTH --> Set MPLS-TE link-TLV parameter: Maximum Reservable Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) mpls-te link metric <0-4294967295> --> Set MPLS-TE link-TLV parameter: MPLS-TE metric. mpls-te link rsc-clsclr BITPATTERN --> Set MPLS-TE link-TLV parameter: Resource Class/Color. In 32-bit hexadecimal format, with leading "0x" (0x0 - 0xffffffff) mpls-te link unrsv-bw <0-7> BANDWIDTH --> Set MPLS-TE link-TLV parameter: Unreserved Bandwidth (Bytes/sec). In integer or floating point format (1000, or 1.0e3) router(config-if)# exit router(config)# router ospf router(config-router)# mpls-te --> Enable MPLS-TE functionality. Note that master-switch "ospf opaque-lsa" must also be specified. mpls-te on --> Alias of "mpls-te" command. mpls-te router-address A.B.C.D --> Set MPLS-TE Router-TLV parameter: Router Address. no mpls-te --> Disable MPLS-TE functionality. no ospf opaque-lsa --> Disable Opaque-LSAs capability. This node behaves Opaque-incapable node. ospf opaque-lsa --> Enable Opaque-LSAs capability. This is the master-switch to make this node Opaque-capable. router# exit quagga-0.99.24.1/doc/mpls/ChangeLog.opaque.txt0000644000175000017500000002000012476520570015625 00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.12.03 1. Bug fixes 1.1 Though a new member "oi" has added to "struct ospf_lsa" to control flooding scope of type-9 Opaque-LSAs, the value was always NULL because no one set it. 1.2 In the function "show_ip_ospf_database_summary()" and "show_lsa_ detail_adv_router()", VTY output for type-11 Opaque-LSAs did not work properly. 1.3 URL for the opaque-type assignment reference has changed. 1.4 In the file "ospf_mpls_te.c", printf formats have changed to avoid compiler warning messages; "%lu" -> "%u", "%lx" -> "%x". Note that this hack depends on OS, compiler and their versions. 1.5 One of attached documentation "opaque_lsa.txt" has changed to reflect the latest coding. 2. Feature enhancements 2.1 Knowing that it is an ugly hack, an "officially unallocated" opaque-type value 0 has newly introduced as a "wildcard", which matches to all opaque-type. This value must not be flooded to the network, of course. 2.2 The Opaque-core module makes use of newly introduced hooks to dispatch every LSDB change (LSA installation and deletion) to preregistered opaque users. Therefore, by providing appropriate callback functions as new parameters of "ospf_register_opaque_functab()", an opaque user can refer to every LSA instance to be installed into, or to be deleted from, the LSDB. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.10.31 1. Bug fixes 1.1 Since each LSA has their own lifetime, they will remain in a routing domain (being stored in LSDB of each router), until their age naturally reach to MaxAge or explicitly being flushed by the originated router. Therefore, if a router restarted with a short downtime, it is possible that previously flooded self-originated LSAs might received if the NSM status is not less than Exchange. There were some problems in the way of handling self-originated Opaque-LSAs if they are contained in a received LSUpd message, but not installed to the local LSDB yet. Regardless of some conditions to start originating Opaque-LSAs (there should be at least one opaque-capable full-state neighbor), the function "ospf_flood()" will be called to flood and install this brand-new looking LSA. As the result, when the NSM of an opaque-capable neighbor gets full, internal state inconsistency happens; a user of Opaque-LSA such as MPLS-TE can refer to self-originated LSAs in the local LSDB, but cannot modify their contents... Above problems have fixed with a policy "flush it from the whole routing domain and keep silent until the flushing completed". By using this sweeping technique, we can be free from confusion caused by self-originated LSAs received via network. 1.2 The function "ospf_opaque_type_name()" contained massive ifdefs corresponding to each "opaque-type". These unnecessary ifdefs are removed completely. 1.3 In the function "ospf_delete_opaque_functab()", there was an improper loop control that causes illegal memory access. Original coding was "next = nextnode (node)". 1.4 The function "ospf_mpls_te_ism_change()" could not handle the case when the ISM changes from Waiting to DR/BDR/Other. So, there was a case that even if one of an ISM become operational and MPLS-TE module has started, the corresponding Opaque-LSA cannot be originated. 1.5 The function "ospf_opaque_lsa_reoriginate_schedule()" did not allow to be called multiple times, simply because handling module for the given "lsa-type & opaque-type" already exists. But this assumption seems to be wrong. Change the policy to allow this function to be called multiple times and let the caller to decide what should do when the corresponding callback function "(* functab->lsa_originator)()" is called. 2. Feature enhancements 2.1 The global bitmap "opaque" has introduced instead of former flag "OpaqueCapable", to store complex conditions to handle Opaque-LSAs. 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic -06.txt", no significant changes with 05 version, though. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.08.03 1. Bug fixes 1.1 Even if the ospfd started with opaque capability enabled, when the ospfd receives an unknown opaque-type (unregistered by the function "ospf_register_opaque_functab()" beforehand), the LSA was discarded. As the result, only the opaque-LSAs that have commonly registered by opaque-capable ospf routers can be flooded in a routing domain. This behavior has fixed so that arbitrary opaque-type LSAs can be flooded among opaque-capable ospf routers. If the ospfd has opaque-LSA capability but disabled at runtime, received opaque-LSAs can be accepted and registered to LSDB as is, but not be flooded to the network; those opaque LSAs will remain in LSDB until explicitly flushed by incoming LSUpd messages with MaxAge, or their age naturally reaches to MaxAge. 1.2 The function "ospf_register_opaque_functab()" did not check if the entry corresponding to the given "lsa-type, opaque-type" combination already exists or not. This problem has fixed not to allow multiple registration. 1.3 Since type-11 (AS external) LSAs will be flooded beyond areas, there is little relationship between "struct lsa" and "struct area". More specifically, the pointer address "lsa->area" can be NULL if the lsa-type is 11, thus an illegal memory access will happen. This problem has fixed. 1.4 When self-originated opaque-LSAs are received via network and if the corresponding opaque-type functions are not available (they have already deleted) at that time, those LSAs were dropped due to "unknown opaque-type" error. After the problem 1.1 has fixed, those "self-originated" LSAs were registered to LSDB and then flooded to the network, even if the processing functions did not exist... After all, this problem has fixed so that those LSAs should explicitly be flushed from the routing domain immediately, if the processing functions cannot find at that time. 1.5 Some typo have fixed. --- EXAMPLE --- static int opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent) ^^^^^ --- EXAMPLE --- 2. Feature enhancements 2.1 According to the description of rfc2328 in section 10.8, any change in the router's optional capabilities should trigger the option re-negotiation procedures with neighbors. --- EXCERPT --- If for some reason the router's optional capabilities change, the Database Exchange procedure should be restarted by reverting to neighbor state ExStart. --- EXCERPT --- For the opaque-capability changes, this feature has implemented. More specifically, if "ospf opaque-lsa" or "no ospf opaque-lsa" VTY command is given at runtime, all self-originated LSAs will be flushed immediately and then all neighbor status will be forced to ExStart by generating SeqNumberMismatch events. 2.1 When we change opaque-capability dynamically (ON -> OFF -> ON), there was no trigger at "OFF->ON" timing to reactivate opaque LSA handling modules (such as MPLS-TE) that have once forcibly stopped at "ON->OFF" timing. Now this dynamic reactivation feature has added. 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic -05.txt", no significant changes with 04 version, though. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.03.28 Initial release of Opaque-LSA/MPLS-TE extensions for the zebra/ospfd. quagga-0.99.24.1/ospfclient/0000755000175000017500000000000012476521356012465 500000000000000quagga-0.99.24.1/ospfclient/ospfclient.c0000644000175000017500000002272612476520570014725 00000000000000/* This file is part of Quagga. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * Simple program to demonstrate how OSPF API can be used. This * application retrieves the LSDB from the OSPF daemon and then * originates, updates and finally deletes an application-specific * opaque LSA. You can use this application as a template when writing * your own application. */ /* The following includes are needed in all OSPF API client applications. */ #include #include "prefix.h" /* needed by ospf_asbr.h */ #include "privs.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_opaque.h" #include "ospfd/ospf_api.h" #include "ospf_apiclient.h" /* privileges struct. * set cap_num_* and uid/gid to nothing to use NULL privs * as ospfapiclient links in libospf.a which uses privs. */ struct zebra_privs_t ospfd_privs = { .user = NULL, .group = NULL, .cap_num_p = 0, .cap_num_i = 0 }; /* The following includes are specific to this application. For example it uses threads from libzebra, however your application is free to use any thread library (like pthreads). */ #include "ospfd/ospf_dump.h" /* for ospf_lsa_header_dump */ #include "thread.h" #include "log.h" /* Local portnumber for async channel. Note that OSPF API library will also allocate a sync channel at ASYNCPORT+1. */ #define ASYNCPORT 4000 /* Master thread */ struct thread_master *master; /* Global variables */ struct ospf_apiclient *oclient; char **args; /* Our opaque LSAs have the following format. */ struct my_opaque_lsa { struct lsa_header hdr; /* include common LSA header */ u_char data[4]; /* our own data format then follows here */ }; /* --------------------------------------------------------- * Threads for asynchronous messages and LSA update/delete * --------------------------------------------------------- */ static int lsa_delete (struct thread *t) { struct ospf_apiclient *oclient; struct in_addr area_id; int rc; oclient = THREAD_ARG (t); inet_aton (args[6], &area_id); printf ("Deleting LSA... "); rc = ospf_apiclient_lsa_delete (oclient, area_id, atoi (args[2]), /* lsa type */ atoi (args[3]), /* opaque type */ atoi (args[4])); /* opaque ID */ printf ("done, return code is = %d\n", rc); return rc; } static int lsa_inject (struct thread *t) { struct ospf_apiclient *cl; struct in_addr ifaddr; struct in_addr area_id; u_char lsa_type; u_char opaque_type; u_int32_t opaque_id; void *opaquedata; int opaquelen; static u_int32_t counter = 1; /* Incremented each time invoked */ int rc; cl = THREAD_ARG (t); inet_aton (args[5], &ifaddr); inet_aton (args[6], &area_id); lsa_type = atoi (args[2]); opaque_type = atoi (args[3]); opaque_id = atoi (args[4]); opaquedata = &counter; opaquelen = sizeof (u_int32_t); printf ("Originating/updating LSA with counter=%d... ", counter); rc = ospf_apiclient_lsa_originate(cl, ifaddr, area_id, lsa_type, opaque_type, opaque_id, opaquedata, opaquelen); printf ("done, return code is %d\n", rc); counter++; return 0; } /* This thread handles asynchronous messages coming in from the OSPF API server */ static int lsa_read (struct thread *thread) { struct ospf_apiclient *oclient; int fd; int ret; printf ("lsa_read called\n"); oclient = THREAD_ARG (thread); fd = THREAD_FD (thread); /* Handle asynchronous message */ ret = ospf_apiclient_handle_async (oclient); if (ret < 0) { printf ("Connection closed, exiting..."); exit(0); } /* Reschedule read thread */ thread_add_read (master, lsa_read, oclient, fd); return 0; } /* --------------------------------------------------------- * Callback functions for asynchronous events * --------------------------------------------------------- */ static void lsa_update_callback (struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *lsa) { printf ("lsa_update_callback: "); printf ("ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area: %s\n", inet_ntoa (area_id)); printf ("is_self_origin: %u\n", is_self_originated); /* It is important to note that lsa_header does indeed include the header and the LSA payload. To access the payload, first check the LSA type and then typecast lsa into the corresponding type, e.g.: if (lsa->type == OSPF_ROUTER_LSA) { struct router_lsa *rl = (struct router_lsa) lsa; ... u_int16_t links = rl->links; ... } */ ospf_lsa_header_dump (lsa); } static void lsa_delete_callback (struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *lsa) { printf ("lsa_delete_callback: "); printf ("ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area: %s\n", inet_ntoa (area_id)); printf ("is_self_origin: %u\n", is_self_originated); ospf_lsa_header_dump (lsa); } static void ready_callback (u_char lsa_type, u_char opaque_type, struct in_addr addr) { printf ("ready_callback: lsa_type: %d opaque_type: %d addr=%s\n", lsa_type, opaque_type, inet_ntoa (addr)); /* Schedule opaque LSA originate in 5 secs */ thread_add_timer (master, lsa_inject, oclient, 5); /* Schedule opaque LSA update with new value */ thread_add_timer (master, lsa_inject, oclient, 10); /* Schedule delete */ thread_add_timer (master, lsa_delete, oclient, 30); } static void new_if_callback (struct in_addr ifaddr, struct in_addr area_id) { printf ("new_if_callback: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area_id: %s\n", inet_ntoa (area_id)); } static void del_if_callback (struct in_addr ifaddr) { printf ("new_if_callback: ifaddr: %s\n ", inet_ntoa (ifaddr)); } static void ism_change_callback (struct in_addr ifaddr, struct in_addr area_id, u_char state) { printf ("ism_change: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("area_id: %s\n", inet_ntoa (area_id)); printf ("state: %d [%s]\n", state, LOOKUP (ospf_ism_state_msg, state)); } static void nsm_change_callback (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char state) { printf ("nsm_change: ifaddr: %s ", inet_ntoa (ifaddr)); printf ("nbraddr: %s\n", inet_ntoa (nbraddr)); printf ("router_id: %s\n", inet_ntoa (router_id)); printf ("state: %d [%s]\n", state, LOOKUP (ospf_nsm_state_msg, state)); } /* --------------------------------------------------------- * Main program * --------------------------------------------------------- */ static int usage() { printf("Usage: ospfclient \n"); printf("where ospfd : router where API-enabled OSPF daemon is running\n"); printf(" lsatype : either 9, 10, or 11 depending on flooding scope\n"); printf(" opaquetype: 0-255 (e.g., experimental applications use > 128)\n"); printf(" opaqueid : arbitrary application instance (24 bits)\n"); printf(" ifaddr : interface IP address (for type 9) otherwise ignored\n"); printf(" areaid : area in IP address format (for type 10) otherwise ignored\n"); exit(1); } int main (int argc, char *argv[]) { struct thread thread; args = argv; /* ospfclient should be started with the following arguments: * * (1) host (2) lsa_type (3) opaque_type (4) opaque_id (5) if_addr * (6) area_id * * host: name or IP of host where ospfd is running * lsa_type: 9, 10, or 11 * opaque_type: 0-255 (e.g., experimental applications use > 128) * opaque_id: arbitrary application instance (24 bits) * if_addr: interface IP address (for type 9) otherwise ignored * area_id: area in IP address format (for type 10) otherwise ignored */ if (argc != 7) { usage(); } /* Initialization */ zprivs_init (&ospfd_privs); master = thread_master_create (); /* Open connection to OSPF daemon */ oclient = ospf_apiclient_connect (args[1], ASYNCPORT); if (!oclient) { printf ("Connecting to OSPF daemon on %s failed!\n", args[1]); exit (1); } /* Register callback functions. */ ospf_apiclient_register_callback (oclient, ready_callback, new_if_callback, del_if_callback, ism_change_callback, nsm_change_callback, lsa_update_callback, lsa_delete_callback); /* Register LSA type and opaque type. */ ospf_apiclient_register_opaque_type (oclient, atoi (args[2]), atoi (args[3])); /* Synchronize database with OSPF daemon. */ ospf_apiclient_sync_lsdb (oclient); /* Schedule thread that handles asynchronous messages */ thread_add_read (master, lsa_read, oclient, oclient->fd_async); /* Now connection is established, run loop */ while (1) { thread_fetch (master, &thread); thread_call (&thread); } /* Never reached */ return 0; } quagga-0.99.24.1/ospfclient/ospf_apiclient.c0000644000175000017500000004613012476520570015551 00000000000000/* * Client side of OSPF API. * Copyright (C) 2001, 2002, 2003 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "getopt.h" #include "thread.h" #include "prefix.h" #include "linklist.h" #include "if.h" #include "vector.h" #include "vty.h" #include "command.h" #include "filter.h" #include "stream.h" #include "log.h" #include "memory.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_opaque.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_api.h" #include "ospf_apiclient.h" /* Backlog for listen */ #define BACKLOG 5 /* ----------------------------------------------------------- * Forward declarations * ----------------------------------------------------------- */ void ospf_apiclient_handle_reply (struct ospf_apiclient *oclient, struct msg *msg); void ospf_apiclient_handle_update_notify (struct ospf_apiclient *oclient, struct msg *msg); void ospf_apiclient_handle_delete_notify (struct ospf_apiclient *oclient, struct msg *msg); /* ----------------------------------------------------------- * Initialization * ----------------------------------------------------------- */ static unsigned short ospf_apiclient_getport (void) { struct servent *sp = getservbyname ("ospfapi", "tcp"); return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT; } /* ----------------------------------------------------------- * Followings are functions for connection management * ----------------------------------------------------------- */ struct ospf_apiclient * ospf_apiclient_connect (char *host, int syncport) { struct sockaddr_in myaddr_sync; struct sockaddr_in myaddr_async; struct sockaddr_in peeraddr; struct hostent *hp; struct ospf_apiclient *new; int size = 0; unsigned int peeraddrlen; int async_server_sock; int fd1, fd2; int ret; int on = 1; /* There are two connections between the client and the server. First the client opens a connection for synchronous requests/replies to the server. The server will accept this connection and as a reaction open a reverse connection channel for asynchronous messages. */ async_server_sock = socket (AF_INET, SOCK_STREAM, 0); if (async_server_sock < 0) { fprintf (stderr, "ospf_apiclient_connect: creating async socket failed\n"); return NULL; } /* Prepare socket for asynchronous messages */ /* Initialize async address structure */ memset (&myaddr_async, 0, sizeof (struct sockaddr_in)); myaddr_async.sin_family = AF_INET; myaddr_async.sin_addr.s_addr = htonl (INADDR_ANY); myaddr_async.sin_port = htons (syncport+1); size = sizeof (struct sockaddr_in); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_async.sin_len = size; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* This is a server socket, reuse addr and port */ ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n"); close (async_server_sock); return NULL; } #ifdef SO_REUSEPORT ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n"); close (async_server_sock); return NULL; } #endif /* SO_REUSEPORT */ /* Bind socket to address structure */ ret = bind (async_server_sock, (struct sockaddr *) &myaddr_async, size); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: bind async socket failed\n"); close (async_server_sock); return NULL; } /* Wait for reverse channel connection establishment from server */ ret = listen (async_server_sock, BACKLOG); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno)); close (async_server_sock); return NULL; } /* Make connection for synchronous requests and connect to server */ /* Resolve address of server */ hp = gethostbyname (host); if (!hp) { fprintf (stderr, "ospf_apiclient_connect: no such host %s\n", host); close (async_server_sock); return NULL; } fd1 = socket (AF_INET, SOCK_STREAM, 0); if (fd1 < 0) { fprintf (stderr, "ospf_apiclient_connect: creating sync socket failed\n"); return NULL; } /* Reuse addr and port */ ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n"); close (fd1); return NULL; } #ifdef SO_REUSEPORT ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof (on)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n"); close (fd1); return NULL; } #endif /* SO_REUSEPORT */ /* Bind sync socket to address structure. This is needed since we want the sync port number on a fixed port number. The reverse async channel will be at this port+1 */ memset (&myaddr_sync, 0, sizeof (struct sockaddr_in)); myaddr_sync.sin_family = AF_INET; myaddr_sync.sin_port = htons (syncport); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_sync.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ ret = bind (fd1, (struct sockaddr *) &myaddr_sync, size); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: bind sync socket failed\n"); close (fd1); return NULL; } /* Prepare address structure for connect */ memcpy (&myaddr_sync.sin_addr, hp->h_addr, hp->h_length); myaddr_sync.sin_family = AF_INET; myaddr_sync.sin_port = htons(ospf_apiclient_getport ()); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN myaddr_sync.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Now establish synchronous channel with OSPF daemon */ ret = connect (fd1, (struct sockaddr *) &myaddr_sync, sizeof (struct sockaddr_in)); if (ret < 0) { fprintf (stderr, "ospf_apiclient_connect: sync connect failed\n"); close (async_server_sock); close (fd1); return NULL; } /* Accept reverse connection */ peeraddrlen = sizeof (struct sockaddr_in); memset (&peeraddr, 0, peeraddrlen); fd2 = accept (async_server_sock, (struct sockaddr *) &peeraddr, &peeraddrlen); if (fd2 < 0) { fprintf (stderr, "ospf_apiclient_connect: accept async failed\n"); close (async_server_sock); close (fd1); return NULL; } /* Server socket is not needed anymore since we are not accepting more connections */ close (async_server_sock); /* Create new client-side instance */ new = XCALLOC (MTYPE_OSPF_APICLIENT, sizeof (struct ospf_apiclient)); /* Initialize socket descriptors for sync and async channels */ new->fd_sync = fd1; new->fd_async = fd2; return new; } int ospf_apiclient_close (struct ospf_apiclient *oclient) { if (oclient->fd_sync >= 0) { close (oclient->fd_sync); } if (oclient->fd_async >= 0) { close (oclient->fd_async); } /* Free client structure */ XFREE (MTYPE_OSPF_APICLIENT, oclient); return 0; } /* ----------------------------------------------------------- * Followings are functions to send a request to OSPFd * ----------------------------------------------------------- */ /* Send synchronous request, wait for reply */ static int ospf_apiclient_send_request (struct ospf_apiclient *oclient, struct msg *msg) { u_int32_t reqseq; struct msg_reply *msgreply; int rc; /* NB: Given "msg" is freed inside this function. */ /* Remember the sequence number of the request */ reqseq = ntohl (msg->hdr.msgseq); /* Write message to OSPFd */ rc = msg_write (oclient->fd_sync, msg); msg_free (msg); if (rc < 0) { return -1; } /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */ msg = msg_read (oclient->fd_sync); if (!msg) return -1; assert (msg->hdr.msgtype == MSG_REPLY); assert (ntohl (msg->hdr.msgseq) == reqseq); msgreply = (struct msg_reply *) STREAM_DATA (msg->s); rc = msgreply->errcode; msg_free (msg); return rc; } /* ----------------------------------------------------------- * Helper functions * ----------------------------------------------------------- */ static u_int32_t ospf_apiclient_get_seqnr (void) { static u_int32_t seqnr = MIN_SEQ; u_int32_t tmp; tmp = seqnr; /* Increment sequence number */ if (seqnr < MAX_SEQ) { seqnr++; } else { seqnr = MIN_SEQ; } return tmp; } /* ----------------------------------------------------------- * API to access OSPF daemon by client applications. * ----------------------------------------------------------- */ /* * Synchronous request to register opaque type. */ int ospf_apiclient_register_opaque_type (struct ospf_apiclient *cl, u_char ltype, u_char otype) { struct msg *msg; int rc; /* just put 1 as a sequence number. */ msg = new_msg_register_opaque_type (ospf_apiclient_get_seqnr (), ltype, otype); if (!msg) { fprintf (stderr, "new_msg_register_opaque_type failed\n"); return -1; } rc = ospf_apiclient_send_request (cl, msg); return rc; } /* * Synchronous request to synchronize with OSPF's LSDB. * Two steps required: register_event in order to get * dynamic updates and LSDB_Sync. */ int ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient) { struct msg *msg; int rc; struct lsa_filter_type filter; filter.typemask = 0xFFFF; /* all LSAs */ filter.origin = ANY_ORIGIN; filter.num_areas = 0; /* all Areas. */ msg = new_msg_register_event (ospf_apiclient_get_seqnr (), &filter); if (!msg) { fprintf (stderr, "new_msg_register_event failed\n"); return -1; } rc = ospf_apiclient_send_request (oclient, msg); if (rc != 0) goto out; msg = new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter); if (!msg) { fprintf (stderr, "new_msg_sync_lsdb failed\n"); return -1; } rc = ospf_apiclient_send_request (oclient, msg); out: return rc; } /* * Synchronous request to originate or update an LSA. */ int ospf_apiclient_lsa_originate (struct ospf_apiclient *oclient, struct in_addr ifaddr, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id, void *opaquedata, int opaquelen) { struct msg *msg; int rc; u_char buf[OSPF_MAX_LSA_SIZE]; struct lsa_header *lsah; u_int32_t tmp; /* We can only originate opaque LSAs */ if (!IS_OPAQUE_LSA (lsa_type)) { fprintf (stderr, "Cannot originate non-opaque LSA type %d\n", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* Make a new LSA from parameters */ lsah = (struct lsa_header *) buf; lsah->ls_age = 0; lsah->options = 0; lsah->type = lsa_type; tmp = SET_OPAQUE_LSID (opaque_type, opaque_id); lsah->id.s_addr = htonl (tmp); lsah->adv_router.s_addr = 0; lsah->ls_seqnum = 0; lsah->checksum = 0; lsah->length = htons (sizeof (struct lsa_header) + opaquelen); memcpy (((u_char *) lsah) + sizeof (struct lsa_header), opaquedata, opaquelen); msg = new_msg_originate_request (ospf_apiclient_get_seqnr (), ifaddr, area_id, lsah); if (!msg) { fprintf (stderr, "new_msg_originate_request failed\n"); return OSPF_API_NOMEMORY; } rc = ospf_apiclient_send_request (oclient, msg); return rc; } int ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id) { struct msg *msg; int rc; /* Only opaque LSA can be deleted */ if (!IS_OPAQUE_LSA (lsa_type)) { fprintf (stderr, "Cannot delete non-opaque LSA type %d\n", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* opaque_id is in host byte order and will be converted * to network byte order by new_msg_delete_request */ msg = new_msg_delete_request (ospf_apiclient_get_seqnr (), area_id, lsa_type, opaque_type, opaque_id); rc = ospf_apiclient_send_request (oclient, msg); return rc; } /* ----------------------------------------------------------- * Followings are handlers for messages from OSPF daemon * ----------------------------------------------------------- */ static void ospf_apiclient_handle_ready (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_ready_notify *r; r = (struct msg_ready_notify *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->ready_notify) { (oclient->ready_notify) (r->lsa_type, r->opaque_type, r->addr); } } static void ospf_apiclient_handle_new_if (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_new_if *n; n = (struct msg_new_if *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->new_if) { (oclient->new_if) (n->ifaddr, n->area_id); } } static void ospf_apiclient_handle_del_if (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_del_if *d; d = (struct msg_del_if *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->del_if) { (oclient->del_if) (d->ifaddr); } } static void ospf_apiclient_handle_ism_change (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_ism_change *m; m = (struct msg_ism_change *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->ism_change) { (oclient->ism_change) (m->ifaddr, m->area_id, m->status); } } static void ospf_apiclient_handle_nsm_change (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_nsm_change *m; m = (struct msg_nsm_change *) STREAM_DATA (msg->s); /* Invoke registered callback function. */ if (oclient->nsm_change) { (oclient->nsm_change) (m->ifaddr, m->nbraddr, m->router_id, m->status); } } static void ospf_apiclient_handle_lsa_update (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; int lsalen; cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s); /* Extract LSA from message */ lsalen = ntohs (cn->data.length); lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen); if (!lsa) { fprintf (stderr, "LSA update: Cannot allocate memory for LSA\n"); return; } memcpy (lsa, &(cn->data), lsalen); /* Invoke registered update callback function */ if (oclient->update_notify) { (oclient->update_notify) (cn->ifaddr, cn->area_id, cn->is_self_originated, lsa); } /* free memory allocated by ospf apiclient library */ XFREE (MTYPE_OSPF_APICLIENT, lsa); } static void ospf_apiclient_handle_lsa_delete (struct ospf_apiclient *oclient, struct msg *msg) { struct msg_lsa_change_notify *cn; struct lsa_header *lsa; int lsalen; cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s); /* Extract LSA from message */ lsalen = ntohs (cn->data.length); lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen); if (!lsa) { fprintf (stderr, "LSA delete: Cannot allocate memory for LSA\n"); return; } memcpy (lsa, &(cn->data), lsalen); /* Invoke registered update callback function */ if (oclient->delete_notify) { (oclient->delete_notify) (cn->ifaddr, cn->area_id, cn->is_self_originated, lsa); } /* free memory allocated by ospf apiclient library */ XFREE (MTYPE_OSPF_APICLIENT, lsa); } static void ospf_apiclient_msghandle (struct ospf_apiclient *oclient, struct msg *msg) { /* Call message handler function. */ switch (msg->hdr.msgtype) { case MSG_READY_NOTIFY: ospf_apiclient_handle_ready (oclient, msg); break; case MSG_NEW_IF: ospf_apiclient_handle_new_if (oclient, msg); break; case MSG_DEL_IF: ospf_apiclient_handle_del_if (oclient, msg); break; case MSG_ISM_CHANGE: ospf_apiclient_handle_ism_change (oclient, msg); break; case MSG_NSM_CHANGE: ospf_apiclient_handle_nsm_change (oclient, msg); break; case MSG_LSA_UPDATE_NOTIFY: ospf_apiclient_handle_lsa_update (oclient, msg); break; case MSG_LSA_DELETE_NOTIFY: ospf_apiclient_handle_lsa_delete (oclient, msg); break; default: fprintf (stderr, "ospf_apiclient_read: Unknown message type: %d\n", msg->hdr.msgtype); break; } } /* ----------------------------------------------------------- * Callback handler registration * ----------------------------------------------------------- */ void ospf_apiclient_register_callback (struct ospf_apiclient *oclient, void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr), void (*new_if) (struct in_addr ifaddr, struct in_addr area_id), void (*del_if) (struct in_addr ifaddr), void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status), void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status), void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa), void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa)) { assert (oclient); assert (update_notify); /* Register callback function */ oclient->ready_notify = ready_notify; oclient->new_if = new_if; oclient->del_if = del_if; oclient->ism_change = ism_change; oclient->nsm_change = nsm_change; oclient->update_notify = update_notify; oclient->delete_notify = delete_notify; } /* ----------------------------------------------------------- * Asynchronous message handling * ----------------------------------------------------------- */ int ospf_apiclient_handle_async (struct ospf_apiclient *oclient) { struct msg *msg; /* Get a message */ msg = msg_read (oclient->fd_async); if (!msg) { /* Connection broke down */ return -1; } /* Handle message */ ospf_apiclient_msghandle (oclient, msg); /* Don't forget to free this message */ msg_free (msg); return 0; } quagga-0.99.24.1/ospfclient/README0000644000175000017500000000014112476520570013256 00000000000000For more information about this software check out: http://www.tik.ee.ethz.ch/~keller/ospfapi/ quagga-0.99.24.1/ospfclient/NEWS0000644000175000017500000000003112476520570013073 00000000000000This file contains news. quagga-0.99.24.1/ospfclient/INSTALL0000644000175000017500000001722712476520570013444 00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. quagga-0.99.24.1/ospfclient/COPYING0000644000175000017500000004307112476520570013442 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. quagga-0.99.24.1/ospfclient/AUTHORS0000644000175000017500000000004512476520570013451 00000000000000Ralph Keller quagga-0.99.24.1/ospfclient/ospf_apiclient.h0000644000175000017500000001101512476520570015550 00000000000000/* * Client side of OSPF API. * Copyright (C) 2001, 2002, 2003 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _OSPF_APICLIENT_H #define _OSPF_APICLIENT_H #define MTYPE_OSPF_APICLIENT 0 /* Structure for the OSPF API client */ struct ospf_apiclient { /* Sockets for sync requests and async notifications */ int fd_sync; int fd_async; /* Pointer to callback functions */ void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr); void (*new_if) (struct in_addr ifaddr, struct in_addr area_id); void (*del_if) (struct in_addr ifaddr); void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status); void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status); void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa); void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char self_origin, struct lsa_header * lsa); }; /* --------------------------------------------------------- * API function prototypes. * --------------------------------------------------------- */ /* Open connection to OSPF daemon. Two ports will be allocated on client, sync channel at syncport and reverse channel at syncport+1 */ struct ospf_apiclient *ospf_apiclient_connect (char *host, int syncport); /* Shutdown connection to OSPF daemon. */ int ospf_apiclient_close (struct ospf_apiclient *oclient); /* Synchronous request to register opaque type. */ int ospf_apiclient_register_opaque_type (struct ospf_apiclient *oclient, u_char ltype, u_char otype); /* Synchronous request to register event mask. */ int ospf_apiclient_register_events (struct ospf_apiclient *oclient, u_int32_t mask); /* Register callback functions.*/ void ospf_apiclient_register_callback (struct ospf_apiclient *oclient, void (*ready_notify) (u_char lsa_type, u_char opaque_type, struct in_addr addr), void (*new_if) (struct in_addr ifaddr, struct in_addr area_id), void (*del_if) (struct in_addr ifaddr), void (*ism_change) (struct in_addr ifaddr, struct in_addr area_id, u_char status), void (*nsm_change) (struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status), void (*update_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char selforig, struct lsa_header * lsa), void (*delete_notify) (struct in_addr ifaddr, struct in_addr area_id, u_char selforig, struct lsa_header * lsa)); /* Synchronous request to synchronize LSDB. */ int ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient); /* Synchronous request to originate or update opaque LSA. */ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient, struct in_addr ifaddr, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id, void *opaquedata, int opaquelen); /* Synchronous request to delete opaque LSA. Parameter opaque_id is in host byte order */ int ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id); /* Fetch async message and handle it */ int ospf_apiclient_handle_async (struct ospf_apiclient *oclient); #endif /* _OSPF_APICLIENT_H */ quagga-0.99.24.1/ospfclient/Makefile.am0000644000175000017500000000112312476520570014433 00000000000000## Automake.am for OSPF API client AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 sbin_PROGRAMS = ospfclient libospfapiclient_la_SOURCES = \ ospf_apiclient.c ospfapiheaderdir = $(pkgincludedir)/ospfapi ospfapiheader_HEADERS = \ ospf_apiclient.h ospfclient_SOURCES = \ ospfclient.c ospfclient_LDADD = libospfapiclient.la \ ../ospfd/libospf.la ../lib/libzebra.la @LIBCAP@ ospfclient_CFLAGS = $(AM_CFLAGS) $(PICFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) $(PILDFLAGS) quagga-0.99.24.1/ospfclient/Makefile.in0000644000175000017500000006631412476521251014456 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospfclient$(EXEEXT) subdir = ospfclient DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(ospfapiheader_HEADERS) AUTHORS COPYING \ INSTALL NEWS README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(ospfapiheaderdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libospfapiclient_la_LIBADD = am_libospfapiclient_la_OBJECTS = ospf_apiclient.lo libospfapiclient_la_OBJECTS = $(am_libospfapiclient_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libospfapiclient_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libospfapiclient_la_LDFLAGS) \ $(LDFLAGS) -o $@ PROGRAMS = $(sbin_PROGRAMS) am_ospfclient_OBJECTS = ospfclient-ospfclient.$(OBJEXT) ospfclient_OBJECTS = $(am_ospfclient_OBJECTS) ospfclient_DEPENDENCIES = libospfapiclient.la ../ospfd/libospf.la \ ../lib/libzebra.la ospfclient_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(ospfclient_CFLAGS) \ $(CFLAGS) $(ospfclient_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospfapiclient_la_SOURCES) $(ospfclient_SOURCES) DIST_SOURCES = $(libospfapiclient_la_SOURCES) $(ospfclient_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(ospfapiheader_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib lib_LTLIBRARIES = libospfapiclient.la libospfapiclient_la_LDFLAGS = -version-info 0:0:0 libospfapiclient_la_SOURCES = \ ospf_apiclient.c ospfapiheaderdir = $(pkgincludedir)/ospfapi ospfapiheader_HEADERS = \ ospf_apiclient.h ospfclient_SOURCES = \ ospfclient.c ospfclient_LDADD = libospfapiclient.la \ ../ospfd/libospf.la ../lib/libzebra.la @LIBCAP@ ospfclient_CFLAGS = $(AM_CFLAGS) $(PICFLAGS) ospfclient_LDFLAGS = $(AM_LDFLAGS) $(PILDFLAGS) all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospfclient/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospfclient/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libospfapiclient.la: $(libospfapiclient_la_OBJECTS) $(libospfapiclient_la_DEPENDENCIES) $(EXTRA_libospfapiclient_la_DEPENDENCIES) $(AM_V_CCLD)$(libospfapiclient_la_LINK) -rpath $(libdir) $(libospfapiclient_la_OBJECTS) $(libospfapiclient_la_LIBADD) $(LIBS) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospfclient$(EXEEXT): $(ospfclient_OBJECTS) $(ospfclient_DEPENDENCIES) $(EXTRA_ospfclient_DEPENDENCIES) @rm -f ospfclient$(EXEEXT) $(AM_V_CCLD)$(ospfclient_LINK) $(ospfclient_OBJECTS) $(ospfclient_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_apiclient.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfclient-ospfclient.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< ospfclient-ospfclient.o: ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -MT ospfclient-ospfclient.o -MD -MP -MF $(DEPDIR)/ospfclient-ospfclient.Tpo -c -o ospfclient-ospfclient.o `test -f 'ospfclient.c' || echo '$(srcdir)/'`ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ospfclient.c' object='ospfclient-ospfclient.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -c -o ospfclient-ospfclient.o `test -f 'ospfclient.c' || echo '$(srcdir)/'`ospfclient.c ospfclient-ospfclient.obj: ospfclient.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -MT ospfclient-ospfclient.obj -MD -MP -MF $(DEPDIR)/ospfclient-ospfclient.Tpo -c -o ospfclient-ospfclient.obj `if test -f 'ospfclient.c'; then $(CYGPATH_W) 'ospfclient.c'; else $(CYGPATH_W) '$(srcdir)/ospfclient.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ospfclient-ospfclient.Tpo $(DEPDIR)/ospfclient-ospfclient.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ospfclient.c' object='ospfclient-ospfclient.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ospfclient_CFLAGS) $(CFLAGS) -c -o ospfclient-ospfclient.obj `if test -f 'ospfclient.c'; then $(CYGPATH_W) 'ospfclient.c'; else $(CYGPATH_W) '$(srcdir)/ospfclient.c'; fi` mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-ospfapiheaderHEADERS: $(ospfapiheader_HEADERS) @$(NORMAL_INSTALL) @list='$(ospfapiheader_HEADERS)'; test -n "$(ospfapiheaderdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ospfapiheaderdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ospfapiheaderdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(ospfapiheaderdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(ospfapiheaderdir)" || exit $$?; \ done uninstall-ospfapiheaderHEADERS: @$(NORMAL_UNINSTALL) @list='$(ospfapiheader_HEADERS)'; test -n "$(ospfapiheaderdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(ospfapiheaderdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(ospfapiheaderdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-ospfapiheaderHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES uninstall-ospfapiheaderHEADERS \ uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-libLTLIBRARIES \ install-man install-ospfapiheaderHEADERS install-pdf \ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-libLTLIBRARIES uninstall-ospfapiheaderHEADERS \ uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/watchquagga/0000755000175000017500000000000012476521356012613 500000000000000quagga-0.99.24.1/watchquagga/watchquagga.c0000644000175000017500000011317712476520570015202 00000000000000/* Monitor status of quagga daemons and restart if necessary. Copyright (C) 2004 Andrew J. Schorr This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #ifndef MIN #define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y)) #endif /* Macros to help randomize timers. */ #define JITTER(X) ((random() % ((X)+1))-((X)/2)) #define FUZZY(X) ((X)+JITTER((X)/20)) #define DEFAULT_PERIOD 5 #define DEFAULT_TIMEOUT 10 #define DEFAULT_RESTART_TIMEOUT 20 #define DEFAULT_LOGLEVEL LOG_INFO #define DEFAULT_MIN_RESTART 60 #define DEFAULT_MAX_RESTART 600 #ifdef PATH_WATCHQUAGGA_PID #define DEFAULT_PIDFILE PATH_WATCHQUAGGA_PID #else #define DEFAULT_PIDFILE STATEDIR "/watchquagga.pid" #endif #ifdef DAEMON_VTY_DIR #define VTYDIR DAEMON_VTY_DIR #else #define VTYDIR STATEDIR #endif #define PING_TOKEN "PING" /* Needs to be global, referenced somewhere inside libzebra. */ struct thread_master *master; typedef enum { MODE_MONITOR = 0, MODE_GLOBAL_RESTART, MODE_SEPARATE_RESTART, MODE_PHASED_ZEBRA_RESTART, MODE_PHASED_ALL_RESTART } watch_mode_t; static const char *mode_str[] = { "monitor", "global restart", "individual daemon restart", "phased zebra restart", "phased global restart for any failure", }; typedef enum { PHASE_NONE = 0, PHASE_STOPS_PENDING, PHASE_WAITING_DOWN, PHASE_ZEBRA_RESTART_PENDING, PHASE_WAITING_ZEBRA_UP } restart_phase_t; static const char *phase_str[] = { "None", "Stop jobs running", "Waiting for other daemons to come down", "Zebra restart job running", "Waiting for zebra to come up", "Start jobs running", }; #define PHASE_TIMEOUT (3*gs.restart_timeout) struct restart_info { const char *name; const char *what; pid_t pid; struct timeval time; long interval; struct thread *t_kill; int kills; }; static struct global_state { watch_mode_t mode; restart_phase_t phase; struct thread *t_phase_hanging; const char *vtydir; long period; long timeout; long restart_timeout; long min_restart_interval; long max_restart_interval; int do_ping; struct daemon *daemons; const char *restart_command; const char *start_command; const char *stop_command; struct restart_info restart; int unresponsive_restart; int loglevel; struct daemon *special; /* points to zebra when doing phased restart */ int numdaemons; int numpids; int numdown; /* # of daemons that are not UP or UNRESPONSIVE */ } gs = { .mode = MODE_MONITOR, .phase = PHASE_NONE, .vtydir = VTYDIR, .period = 1000*DEFAULT_PERIOD, .timeout = DEFAULT_TIMEOUT, .restart_timeout = DEFAULT_RESTART_TIMEOUT, .loglevel = DEFAULT_LOGLEVEL, .min_restart_interval = DEFAULT_MIN_RESTART, .max_restart_interval = DEFAULT_MAX_RESTART, .do_ping = 1, }; typedef enum { DAEMON_INIT, DAEMON_DOWN, DAEMON_CONNECTING, DAEMON_UP, DAEMON_UNRESPONSIVE } daemon_state_t; #define IS_UP(DMN) \ (((DMN)->state == DAEMON_UP) || ((DMN)->state == DAEMON_UNRESPONSIVE)) static const char *state_str[] = { "Init", "Down", "Connecting", "Up", "Unresponsive", }; struct daemon { const char *name; daemon_state_t state; int fd; struct timeval echo_sent; u_int connect_tries; struct thread *t_wakeup; struct thread *t_read; struct thread *t_write; struct daemon *next; struct restart_info restart; }; static const struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "statedir", required_argument, NULL, 'S'}, { "no-echo", no_argument, NULL, 'e'}, { "loglevel", required_argument, NULL, 'l'}, { "interval", required_argument, NULL, 'i'}, { "timeout", required_argument, NULL, 't'}, { "restart-timeout", required_argument, NULL, 'T'}, { "restart", required_argument, NULL, 'r'}, { "start-command", required_argument, NULL, 's'}, { "kill-command", required_argument, NULL, 'k'}, { "restart-all", required_argument, NULL, 'R'}, { "all-restart", no_argument, NULL, 'a'}, { "always-all-restart", no_argument, NULL, 'A'}, { "unresponsive-restart", no_argument, NULL, 'z'}, { "min-restart-interval", required_argument, NULL, 'm'}, { "max-restart-interval", required_argument, NULL, 'M'}, { "pid-file", required_argument, NULL, 'p'}, { "blank-string", required_argument, NULL, 'b'}, { "help", no_argument, NULL, 'h'}, { "version", no_argument, NULL, 'v'}, { NULL, 0, NULL, 0 } }; static int try_connect(struct daemon *dmn); static int wakeup_send_echo(struct thread *t_wakeup); static void try_restart(struct daemon *dmn); static void phase_check(void); static int usage(const char *progname, int status) { if (status != 0) fprintf(stderr, "Try `%s --help' for more information.\n", progname); else printf("Usage : %s [OPTION...] ...\n\n\ Watchdog program to monitor status of quagga daemons and try to restart\n\ them if they are down or unresponsive. It determines whether a daemon is\n\ up based on whether it can connect to the daemon's vty unix stream socket.\n\ It then repeatedly sends echo commands over that socket to determine whether\n\ the daemon is responsive. If the daemon crashes, we will receive an EOF\n\ on the socket connection and know immediately that the daemon is down.\n\n\ The daemons to be monitored should be listed on the command line.\n\n\ This program can run in one of 5 modes:\n\n\ 0. Mode: %s.\n\ Just monitor and report on status changes. Example:\n\ %s -d zebra ospfd bgpd\n\n\ 1. Mode: %s.\n\ Whenever any daemon hangs or crashes, use the given command to restart\n\ them all. Example:\n\ %s -dz \\\n\ -R '/sbin/service zebra restart; /sbin/service ospfd restart' \\\n\ zebra ospfd\n\n\ 2. Mode: %s.\n\ When any single daemon hangs or crashes, restart only the daemon that's\n\ in trouble using the supplied restart command. Example:\n\ %s -dz -r '/sbin/service %%s restart' zebra ospfd bgpd\n\n\ 3. Mode: %s.\n\ The same as the previous mode, except that there is special treatment when\n\ the zebra daemon is in trouble. In that case, a phased restart approach\n\ is used: 1. stop all other daemons; 2. restart zebra; 3. start the other\n\ daemons. Example:\n\ %s -adz -r '/sbin/service %%s restart' \\\n\ -s '/sbin/service %%s start' \\\n\ -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ 4. Mode: %s.\n\ This is the same as the previous mode, except that the phased restart\n\ procedure is used whenever any of the daemons hangs or crashes. Example:\n\ %s -Adz -r '/sbin/service %%s restart' \\\n\ -s '/sbin/service %%s start' \\\n\ -k '/sbin/service %%s stop' zebra ospfd bgpd\n\n\ As of this writing, it is believed that mode 2 [%s]\n\ is not safe, and mode 3 [%s] may not be safe with some of the\n\ routing daemons.\n\n\ In order to avoid attempting to restart the daemons in a fast loop,\n\ the -m and -M options allow you to control the minimum delay between\n\ restart commands. The minimum restart delay is recalculated each time\n\ a restart is attempted: if the time since the last restart attempt exceeds\n\ twice the -M value, then the restart delay is set to the -m value.\n\ Otherwise, the interval is doubled (but capped at the -M value).\n\n\ Options:\n\ -d, --daemon Run in daemon mode. In this mode, error messages are sent\n\ to syslog instead of stdout.\n\ -S, --statedir Set the vty socket directory (default is %s)\n\ -e, --no-echo Do not ping the daemons to test responsiveness (this\n\ option is necessary if the daemons do not support the\n\ echo command)\n\ -l, --loglevel Set the logging level (default is %d).\n\ The value should range from %d (LOG_EMERG) to %d (LOG_DEBUG),\n\ but it can be set higher than %d if extra-verbose debugging\n\ messages are desired.\n\ -m, --min-restart-interval\n\ Set the minimum seconds to wait between invocations of daemon\n\ restart commands (default is %d).\n\ -M, --max-restart-interval\n\ Set the maximum seconds to wait between invocations of daemon\n\ restart commands (default is %d).\n\ -i, --interval Set the status polling interval in seconds (default is %d)\n\ -t, --timeout Set the unresponsiveness timeout in seconds (default is %d)\n\ -T, --restart-timeout\n\ Set the restart (kill) timeout in seconds (default is %d).\n\ If any background jobs are still running after this much\n\ time has elapsed, they will be killed.\n\ -r, --restart Supply a Bourne shell command to use to restart a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ Note that -r and -R are incompatible.\n\ -s, --start-command\n\ Supply a Bourne shell to command to use to start a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ -k, --kill-command\n\ Supply a Bourne shell to command to use to stop a single\n\ daemon. The command string should include '%%s' where the\n\ name of the daemon should be substituted.\n\ -R, --restart-all\n\ When one or more daemons is down, try to restart everything\n\ using the Bourne shell command supplied as the argument.\n\ Note that -r and -R are incompatible.\n\ -z, --unresponsive-restart\n\ When a daemon is unresponsive, treat it as being down for\n\ restart purposes.\n\ -a, --all-restart\n\ When zebra hangs or crashes, restart all daemons using\n\ this phased approach: 1. stop all other daemons; 2. restart\n\ zebra; 3. start other daemons. Requires -r, -s, and -k.\n\ -A, --always-all-restart\n\ When any daemon (not just zebra) hangs or crashes, use the\n\ same phased restart mechanism described above for -a.\n\ Requires -r, -s, and -k.\n\ -p, --pid-file Set process identifier file name\n\ (default is %s).\n\ -b, --blank-string\n\ When the supplied argument string is found in any of the\n\ various shell command arguments (-r, -s, -k, or -R), replace\n\ it with a space. This is an ugly hack to circumvent problems\n\ passing command-line arguments with embedded spaces.\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ ", progname,mode_str[0],progname,mode_str[1],progname,mode_str[2], progname,mode_str[3],progname,mode_str[4],progname,mode_str[2],mode_str[3], VTYDIR,DEFAULT_LOGLEVEL,LOG_EMERG,LOG_DEBUG,LOG_DEBUG, DEFAULT_MIN_RESTART,DEFAULT_MAX_RESTART, DEFAULT_PERIOD,DEFAULT_TIMEOUT,DEFAULT_RESTART_TIMEOUT,DEFAULT_PIDFILE); return status; } static pid_t run_background(const char *shell_cmd) { pid_t child; switch (child = fork()) { case -1: zlog_err("fork failed, cannot run command [%s]: %s", shell_cmd,safe_strerror(errno)); return -1; case 0: /* Child process. */ /* Use separate process group so child processes can be killed easily. */ if (setpgid(0,0) < 0) zlog_warn("warning: setpgid(0,0) failed: %s",safe_strerror(errno)); { const char *argv[4] = { "sh", "-c", shell_cmd, NULL}; execv("/bin/sh",(char *const *)argv); zlog_err("execv(/bin/sh -c '%s') failed: %s", shell_cmd,safe_strerror(errno)); _exit(127); } default: /* Parent process: we will reap the child later. */ zlog_err("Forked background command [pid %d]: %s",(int)child,shell_cmd); return child; } } static struct timeval * time_elapsed(struct timeval *result, const struct timeval *start_time) { gettimeofday(result,NULL); result->tv_sec -= start_time->tv_sec; result->tv_usec -= start_time->tv_usec; while (result->tv_usec < 0) { result->tv_usec += 1000000L; result->tv_sec--; } return result; } static int restart_kill(struct thread *t_kill) { struct restart_info *restart = THREAD_ARG(t_kill); struct timeval delay; time_elapsed(&delay,&restart->time); zlog_warn("Warning: %s %s child process %d still running after " "%ld seconds, sending signal %d", restart->what,restart->name,(int)restart->pid,delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM)); kill(-restart->pid,(restart->kills ? SIGKILL : SIGTERM)); restart->kills++; restart->t_kill = thread_add_timer(master,restart_kill,restart, gs.restart_timeout); return 0; } static struct restart_info * find_child(pid_t child) { if (gs.mode == MODE_GLOBAL_RESTART) { if (gs.restart.pid == child) return &gs.restart; } else { struct daemon *dmn; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn->restart.pid == child) return &dmn->restart; } } return NULL; } static void sigchild(void) { pid_t child; int status; const char *name; const char *what; struct restart_info *restart; switch (child = waitpid(-1,&status,WNOHANG)) { case -1: zlog_err("waitpid failed: %s",safe_strerror(errno)); return; case 0: zlog_warn("SIGCHLD received, but waitpid did not reap a child"); return; } if ((restart = find_child(child)) != NULL) { name = restart->name; what = restart->what; restart->pid = 0; gs.numpids--; thread_cancel(restart->t_kill); restart->t_kill = NULL; /* Update restart time to reflect the time the command completed. */ gettimeofday(&restart->time,NULL); } else { zlog_err("waitpid returned status for an unknown child process %d", (int)child); name = "(unknown)"; what = "background"; } if (WIFSTOPPED(status)) zlog_warn("warning: %s %s process %d is stopped", what,name,(int)child); else if (WIFSIGNALED(status)) zlog_warn("%s %s process %d terminated due to signal %d", what,name,(int)child,WTERMSIG(status)); else if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) zlog_warn("%s %s process %d exited with non-zero status %d", what,name,(int)child,WEXITSTATUS(status)); else zlog_debug("%s %s process %d exited normally",what,name,(int)child); } else zlog_err("cannot interpret %s %s process %d wait status 0x%x", what,name,(int)child,status); phase_check(); } static int run_job(struct restart_info *restart, const char *cmdtype, const char *command, int force, int update_interval) { struct timeval delay; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("attempting to %s %s",cmdtype,restart->name); if (restart->pid) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("cannot %s %s, previous pid %d still running", cmdtype,restart->name,(int)restart->pid); return -1; } /* Note: time_elapsed test must come before the force test, since we need to make sure that delay is initialized for use below in updating the restart interval. */ if ((time_elapsed(&delay,&restart->time)->tv_sec < restart->interval) && !force) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing %s %s: " "elapsed time %ld < retry interval %ld", cmdtype,restart->name,(long)delay.tv_sec,restart->interval); return -1; } gettimeofday(&restart->time,NULL); restart->kills = 0; { char cmd[strlen(command)+strlen(restart->name)+1]; snprintf(cmd,sizeof(cmd),command,restart->name); if ((restart->pid = run_background(cmd)) > 0) { restart->t_kill = thread_add_timer(master,restart_kill,restart, gs.restart_timeout); restart->what = cmdtype; gs.numpids++; } else restart->pid = 0; } /* Calculate the new restart interval. */ if (update_interval) { if (delay.tv_sec > 2*gs.max_restart_interval) restart->interval = gs.min_restart_interval; else if ((restart->interval *= 2) > gs.max_restart_interval) restart->interval = gs.max_restart_interval; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("restart %s interval is now %ld", restart->name,restart->interval); } return restart->pid; } #define SET_READ_HANDLER(DMN) \ (DMN)->t_read = thread_add_read(master,handle_read,(DMN),(DMN)->fd) #define SET_WAKEUP_DOWN(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_down,(DMN), \ FUZZY(gs.period)) #define SET_WAKEUP_UNRESPONSIVE(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_unresponsive,(DMN), \ FUZZY(gs.period)) #define SET_WAKEUP_ECHO(DMN) \ (DMN)->t_wakeup = thread_add_timer_msec(master,wakeup_send_echo,(DMN), \ FUZZY(gs.period)) static int wakeup_down(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (try_connect(dmn) < 0) SET_WAKEUP_DOWN(dmn); if ((dmn->connect_tries > 1) && (dmn->state != DAEMON_UP)) try_restart(dmn); return 0; } static int wakeup_init(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (try_connect(dmn) < 0) { SET_WAKEUP_DOWN(dmn); zlog_err("%s state -> down : initial connection attempt failed", dmn->name); dmn->state = DAEMON_DOWN; } return 0; } static void daemon_down(struct daemon *dmn, const char *why) { if (IS_UP(dmn) || (dmn->state == DAEMON_INIT)) zlog_err("%s state -> down : %s",dmn->name,why); else if (gs.loglevel > LOG_DEBUG) zlog_debug("%s still down : %s",dmn->name,why); if (IS_UP(dmn)) gs.numdown++; dmn->state = DAEMON_DOWN; if (dmn->fd >= 0) { close(dmn->fd); dmn->fd = -1; } THREAD_OFF(dmn->t_read); THREAD_OFF(dmn->t_write); THREAD_OFF(dmn->t_wakeup); if (try_connect(dmn) < 0) SET_WAKEUP_DOWN(dmn); phase_check(); } static int handle_read(struct thread *t_read) { struct daemon *dmn = THREAD_ARG(t_read); static const char resp[sizeof(PING_TOKEN)+4] = PING_TOKEN "\n"; char buf[sizeof(resp)+100]; ssize_t rc; struct timeval delay; dmn->t_read = NULL; if ((rc = read(dmn->fd,buf,sizeof(buf))) < 0) { char why[100]; if (ERRNO_IO_RETRY(errno)) { /* Pretend it never happened. */ SET_READ_HANDLER(dmn); return 0; } snprintf(why,sizeof(why),"unexpected read error: %s", safe_strerror(errno)); daemon_down(dmn,why); return 0; } if (rc == 0) { daemon_down(dmn,"read returned EOF"); return 0; } if (!dmn->echo_sent.tv_sec) { char why[sizeof(buf)+100]; snprintf(why,sizeof(why),"unexpected read returns %d bytes: %.*s", (int)rc,(int)rc,buf); daemon_down(dmn,why); return 0; } /* We are expecting an echo response: is there any chance that the response would not be returned entirely in the first read? That seems inconceivable... */ if ((rc != sizeof(resp)) || memcmp(buf,resp,sizeof(resp))) { char why[100+sizeof(buf)]; snprintf(why,sizeof(why),"read returned bad echo response of %d bytes " "(expecting %u): %.*s", (int)rc,(u_int)sizeof(resp),(int)rc,buf); daemon_down(dmn,why); return 0; } time_elapsed(&delay,&dmn->echo_sent); dmn->echo_sent.tv_sec = 0; if (dmn->state == DAEMON_UNRESPONSIVE) { if (delay.tv_sec < gs.timeout) { dmn->state = DAEMON_UP; zlog_warn("%s state -> up : echo response received after %ld.%06ld " "seconds", dmn->name,delay.tv_sec,delay.tv_usec); } else zlog_warn("%s: slow echo response finally received after %ld.%06ld " "seconds", dmn->name,delay.tv_sec,delay.tv_usec); } else if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: echo response received after %ld.%06ld seconds", dmn->name,delay.tv_sec,delay.tv_usec); SET_READ_HANDLER(dmn); if (dmn->t_wakeup) thread_cancel(dmn->t_wakeup); SET_WAKEUP_ECHO(dmn); return 0; } static void daemon_up(struct daemon *dmn, const char *why) { dmn->state = DAEMON_UP; gs.numdown--; dmn->connect_tries = 0; zlog_notice("%s state -> up : %s",dmn->name,why); if (gs.do_ping) SET_WAKEUP_ECHO(dmn); phase_check(); } static int check_connect(struct thread *t_write) { struct daemon *dmn = THREAD_ARG(t_write); int sockerr; socklen_t reslen = sizeof(sockerr); dmn->t_write = NULL; if (getsockopt(dmn->fd,SOL_SOCKET,SO_ERROR,(char *)&sockerr,&reslen) < 0) { zlog_warn("%s: check_connect: getsockopt failed: %s", dmn->name,safe_strerror(errno)); daemon_down(dmn,"getsockopt failed checking connection success"); return 0; } if ((reslen == sizeof(sockerr)) && sockerr) { char why[100]; snprintf(why,sizeof(why), "getsockopt reports that connection attempt failed: %s", safe_strerror(sockerr)); daemon_down(dmn,why); return 0; } daemon_up(dmn,"delayed connect succeeded"); return 0; } static int wakeup_connect_hanging(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); char why[100]; dmn->t_wakeup = NULL; snprintf(why,sizeof(why),"connection attempt timed out after %ld seconds", gs.timeout); daemon_down(dmn,why); return 0; } /* Making connection to protocol daemon. */ static int try_connect(struct daemon *dmn) { int sock; struct sockaddr_un addr; socklen_t len; if (gs.loglevel > LOG_DEBUG+1) zlog_debug("%s: attempting to connect",dmn->name); dmn->connect_tries++; memset (&addr, 0, sizeof (struct sockaddr_un)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s.vty", gs.vtydir,dmn->name); #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN len = addr.sun_len = SUN_LEN(&addr); #else len = sizeof (addr.sun_family) + strlen (addr.sun_path); #endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */ /* Quick check to see if we might succeed before we go to the trouble of creating a socket. */ if (access(addr.sun_path, W_OK) < 0) { if (errno != ENOENT) zlog_err("%s: access to socket %s denied: %s", dmn->name,addr.sun_path,safe_strerror(errno)); return -1; } if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { zlog_err("%s(%s): cannot make socket: %s", __func__,addr.sun_path, safe_strerror(errno)); return -1; } if (set_nonblocking(sock) < 0) { zlog_err("%s(%s): set_nonblocking(%d) failed", __func__, addr.sun_path, sock); close(sock); return -1; } if (connect (sock, (struct sockaddr *) &addr, len) < 0) { if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { if (gs.loglevel > LOG_DEBUG) zlog_debug("%s(%s): connect failed: %s", __func__,addr.sun_path, safe_strerror(errno)); close (sock); return -1; } if (gs.loglevel > LOG_DEBUG) zlog_debug("%s: connection in progress",dmn->name); dmn->state = DAEMON_CONNECTING; dmn->fd = sock; dmn->t_write = thread_add_write(master,check_connect,dmn,dmn->fd); dmn->t_wakeup = thread_add_timer(master,wakeup_connect_hanging,dmn, gs.timeout); SET_READ_HANDLER(dmn); return 0; } dmn->fd = sock; SET_READ_HANDLER(dmn); daemon_up(dmn,"connect succeeded"); return 1; } static int phase_hanging(struct thread *t_hanging) { gs.t_phase_hanging = NULL; zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart", phase_str[gs.phase],PHASE_TIMEOUT); gs.phase = PHASE_NONE; return 0; } static void set_phase(restart_phase_t new_phase) { gs.phase = new_phase; if (gs.t_phase_hanging) thread_cancel(gs.t_phase_hanging); gs.t_phase_hanging = thread_add_timer(master,phase_hanging,NULL, PHASE_TIMEOUT); } static void phase_check(void) { switch (gs.phase) { case PHASE_NONE: break; case PHASE_STOPS_PENDING: if (gs.numpids) break; zlog_info("Phased restart: all routing daemon stop jobs have completed."); set_phase(PHASE_WAITING_DOWN); /*FALLTHRU*/ case PHASE_WAITING_DOWN: if (gs.numdown+IS_UP(gs.special) < gs.numdaemons) break; zlog_info("Phased restart: all routing daemons now down."); run_job(&gs.special->restart,"restart",gs.restart_command,1,1); set_phase(PHASE_ZEBRA_RESTART_PENDING); /*FALLTHRU*/ case PHASE_ZEBRA_RESTART_PENDING: if (gs.special->restart.pid) break; zlog_info("Phased restart: %s restart job completed.",gs.special->name); set_phase(PHASE_WAITING_ZEBRA_UP); /*FALLTHRU*/ case PHASE_WAITING_ZEBRA_UP: if (!IS_UP(gs.special)) break; zlog_info("Phased restart: %s is now up.",gs.special->name); { struct daemon *dmn; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn != gs.special) run_job(&dmn->restart,"start",gs.start_command,1,0); } } gs.phase = PHASE_NONE; THREAD_OFF(gs.t_phase_hanging); zlog_notice("Phased global restart has completed."); break; } } static void try_restart(struct daemon *dmn) { switch (gs.mode) { case MODE_MONITOR: return; case MODE_GLOBAL_RESTART: run_job(&gs.restart,"restart",gs.restart_command,0,1); break; case MODE_SEPARATE_RESTART: run_job(&dmn->restart,"restart",gs.restart_command,0,1); break; case MODE_PHASED_ZEBRA_RESTART: if (dmn != gs.special) { if ((gs.special->state == DAEMON_UP) && (gs.phase == PHASE_NONE)) run_job(&dmn->restart,"restart",gs.restart_command,0,1); else zlog_debug("%s: postponing restart attempt because master %s daemon " "not up [%s], or phased restart in progress", dmn->name,gs.special->name,state_str[gs.special->state]); break; } /*FALLTHRU*/ case MODE_PHASED_ALL_RESTART: if ((gs.phase != PHASE_NONE) || gs.numpids) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing phased global restart: restart already in " "progress [%s], or outstanding child processes [%d]", phase_str[gs.phase],gs.numpids); break; } /* Is it too soon for a restart? */ { struct timeval delay; if (time_elapsed(&delay,&gs.special->restart.time)->tv_sec < gs.special->restart.interval) { if (gs.loglevel > LOG_DEBUG+1) zlog_debug("postponing phased global restart: " "elapsed time %ld < retry interval %ld", (long)delay.tv_sec,gs.special->restart.interval); break; } } zlog_info("Phased restart: stopping all routing daemons."); /* First step: stop all other daemons. */ for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (dmn != gs.special) run_job(&dmn->restart,"stop",gs.stop_command,1,1); } set_phase(PHASE_STOPS_PENDING); break; default: zlog_err("error: unknown restart mode %d",gs.mode); break; } } static int wakeup_unresponsive(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (dmn->state != DAEMON_UNRESPONSIVE) zlog_err("%s: no longer unresponsive (now %s), " "wakeup should have been cancelled!", dmn->name,state_str[dmn->state]); else { SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); } return 0; } static int wakeup_no_answer(struct thread *t_wakeup) { struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; dmn->state = DAEMON_UNRESPONSIVE; zlog_err("%s state -> unresponsive : no response yet to ping " "sent %ld seconds ago",dmn->name,gs.timeout); if (gs.unresponsive_restart) { SET_WAKEUP_UNRESPONSIVE(dmn); try_restart(dmn); } return 0; } static int wakeup_send_echo(struct thread *t_wakeup) { static const char echocmd[] = "echo " PING_TOKEN; ssize_t rc; struct daemon *dmn = THREAD_ARG(t_wakeup); dmn->t_wakeup = NULL; if (((rc = write(dmn->fd,echocmd,sizeof(echocmd))) < 0) || ((size_t)rc != sizeof(echocmd))) { char why[100+sizeof(echocmd)]; snprintf(why,sizeof(why),"write '%s' returned %d instead of %u", echocmd,(int)rc,(u_int)sizeof(echocmd)); daemon_down(dmn,why); } else { gettimeofday(&dmn->echo_sent,NULL); dmn->t_wakeup = thread_add_timer(master,wakeup_no_answer,dmn,gs.timeout); } return 0; } static void sigint(void) { zlog_notice("Terminating on signal"); exit(0); } static int valid_command(const char *cmd) { char *p; return ((p = strchr(cmd,'%')) != NULL) && (*(p+1) == 's') && !strchr(p+1,'%'); } /* This is an ugly hack to circumvent problems with passing command-line arguments that contain spaces. The fix is to use a configuration file. */ static char * translate_blanks(const char *cmd, const char *blankstr) { char *res; char *p; size_t bslen = strlen(blankstr); if (!(res = strdup(cmd))) { perror("strdup"); exit(1); } while ((p = strstr(res,blankstr)) != NULL) { *p = ' '; if (bslen != 1) memmove(p+1,p+bslen,strlen(p+bslen)+1); } return res; } int main(int argc, char **argv) { const char *progname; int opt; int daemon_mode = 0; const char *pidfile = DEFAULT_PIDFILE; const char *special = "zebra"; const char *blankstr = NULL; static struct quagga_signal_t my_signals[] = { { .signal = SIGINT, .handler = sigint, }, { .signal = SIGTERM, .handler = sigint, }, { .signal = SIGCHLD, .handler = sigchild, }, }; if ((progname = strrchr (argv[0], '/')) != NULL) progname++; else progname = argv[0]; gs.restart.name = "all"; while ((opt = getopt_long(argc, argv, "aAb:dek:l:m:M:i:p:r:R:S:s:t:T:zvh", longopts, 0)) != EOF) { switch (opt) { case 0: break; case 'a': if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } gs.mode = MODE_PHASED_ZEBRA_RESTART; break; case 'A': if ((gs.mode != MODE_MONITOR) && (gs.mode != MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } gs.mode = MODE_PHASED_ALL_RESTART; break; case 'b': blankstr = optarg; break; case 'd': daemon_mode = 1; break; case 'e': gs.do_ping = 0; break; case 'k': if (!valid_command(optarg)) { fprintf(stderr,"Invalid kill command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.stop_command = optarg; break; case 'l': { char garbage[3]; if ((sscanf(optarg,"%d%1s",&gs.loglevel,garbage) != 1) || (gs.loglevel < LOG_EMERG)) { fprintf(stderr,"Invalid loglevel argument: %s\n",optarg); return usage(progname,1); } } break; case 'm': { char garbage[3]; if ((sscanf(optarg,"%ld%1s", &gs.min_restart_interval,garbage) != 1) || (gs.min_restart_interval < 0)) { fprintf(stderr,"Invalid min_restart_interval argument: %s\n", optarg); return usage(progname,1); } } break; case 'M': { char garbage[3]; if ((sscanf(optarg,"%ld%1s", &gs.max_restart_interval,garbage) != 1) || (gs.max_restart_interval < 0)) { fprintf(stderr,"Invalid max_restart_interval argument: %s\n", optarg); return usage(progname,1); } } break; case 'i': { char garbage[3]; int period; if ((sscanf(optarg,"%d%1s",&period,garbage) != 1) || (gs.period < 1)) { fprintf(stderr,"Invalid interval argument: %s\n",optarg); return usage(progname,1); } gs.period = 1000*period; } break; case 'p': pidfile = optarg; break; case 'r': if ((gs.mode == MODE_GLOBAL_RESTART) || (gs.mode == MODE_SEPARATE_RESTART)) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } if (!valid_command(optarg)) { fprintf(stderr, "Invalid restart command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.restart_command = optarg; if (gs.mode == MODE_MONITOR) gs.mode = MODE_SEPARATE_RESTART; break; case 'R': if (gs.mode != MODE_MONITOR) { fputs("Ambiguous operating mode selected.\n",stderr); return usage(progname,1); } if (strchr(optarg,'%')) { fprintf(stderr, "Invalid restart-all arg, must not contain '%%s': %s\n", optarg); return usage(progname,1); } gs.restart_command = optarg; gs.mode = MODE_GLOBAL_RESTART; break; case 's': if (!valid_command(optarg)) { fprintf(stderr,"Invalid start command, must contain '%%s': %s\n", optarg); return usage(progname,1); } gs.start_command = optarg; break; case 'S': gs.vtydir = optarg; break; case 't': { char garbage[3]; if ((sscanf(optarg,"%ld%1s",&gs.timeout,garbage) != 1) || (gs.timeout < 1)) { fprintf(stderr,"Invalid timeout argument: %s\n",optarg); return usage(progname,1); } } break; case 'T': { char garbage[3]; if ((sscanf(optarg,"%ld%1s",&gs.restart_timeout,garbage) != 1) || (gs.restart_timeout < 1)) { fprintf(stderr,"Invalid restart timeout argument: %s\n",optarg); return usage(progname,1); } } break; case 'z': gs.unresponsive_restart = 1; break; case 'v': printf ("%s version %s\n", progname, QUAGGA_VERSION); puts("Copyright 2004 Andrew J. Schorr"); return 0; case 'h': return usage(progname,0); default: fputs("Invalid option.\n",stderr); return usage(progname,1); } } if (gs.unresponsive_restart && (gs.mode == MODE_MONITOR)) { fputs("Option -z requires a -r or -R restart option.\n",stderr); return usage(progname,1); } switch (gs.mode) { case MODE_MONITOR: if (gs.restart_command || gs.start_command || gs.stop_command) { fprintf(stderr,"No kill/(re)start commands needed for %s mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; case MODE_GLOBAL_RESTART: case MODE_SEPARATE_RESTART: if (!gs.restart_command || gs.start_command || gs.stop_command) { fprintf(stderr,"No start/kill commands needed in [%s] mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; case MODE_PHASED_ZEBRA_RESTART: case MODE_PHASED_ALL_RESTART: if (!gs.restart_command || !gs.start_command || !gs.stop_command) { fprintf(stderr, "Need start, kill, and restart commands in [%s] mode.\n", mode_str[gs.mode]); return usage(progname,1); } break; } if (blankstr) { if (gs.restart_command) gs.restart_command = translate_blanks(gs.restart_command,blankstr); if (gs.start_command) gs.start_command = translate_blanks(gs.start_command,blankstr); if (gs.stop_command) gs.stop_command = translate_blanks(gs.stop_command,blankstr); } gs.restart.interval = gs.min_restart_interval; master = thread_master_create(); signal_init (master, array_size(my_signals), my_signals); srandom(time(NULL)); { int i; struct daemon *tail = NULL; for (i = optind; i < argc; i++) { struct daemon *dmn; if (!(dmn = (struct daemon *)calloc(1,sizeof(*dmn)))) { fprintf(stderr,"calloc(1,%u) failed: %s\n", (u_int)sizeof(*dmn), safe_strerror(errno)); return 1; } dmn->name = dmn->restart.name = argv[i]; dmn->state = DAEMON_INIT; gs.numdaemons++; gs.numdown++; dmn->fd = -1; dmn->t_wakeup = thread_add_timer_msec(master,wakeup_init,dmn, 100+(random() % 900)); dmn->restart.interval = gs.min_restart_interval; if (tail) tail->next = dmn; else gs.daemons = dmn; tail = dmn; if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || (gs.mode == MODE_PHASED_ALL_RESTART)) && !strcmp(dmn->name,special)) gs.special = dmn; } } if (!gs.daemons) { fputs("Must specify one or more daemons to monitor.\n",stderr); return usage(progname,1); } if (((gs.mode == MODE_PHASED_ZEBRA_RESTART) || (gs.mode == MODE_PHASED_ALL_RESTART)) && !gs.special) { fprintf(stderr,"In mode [%s], but cannot find master daemon %s\n", mode_str[gs.mode],special); return usage(progname,1); } if (gs.special && (gs.numdaemons < 2)) { fprintf(stderr,"Mode [%s] does not make sense with only 1 daemon " "to watch.\n",mode_str[gs.mode]); return usage(progname,1); } zlog_default = openzlog(progname, ZLOG_NONE, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); if (daemon_mode) { zlog_set_level(NULL, ZLOG_DEST_SYSLOG, MIN(gs.loglevel,LOG_DEBUG)); if (daemon (0, 0) < 0) { fprintf(stderr, "Watchquagga daemon failed: %s", strerror(errno)); exit (1); } } else zlog_set_level(NULL, ZLOG_DEST_STDOUT, MIN(gs.loglevel,LOG_DEBUG)); /* Make sure we're not already running. */ pid_output (pidfile); /* Announce which daemons are being monitored. */ { struct daemon *dmn; size_t len = 0; for (dmn = gs.daemons; dmn; dmn = dmn->next) len += strlen(dmn->name)+1; { char buf[len+1]; char *p = buf; for (dmn = gs.daemons; dmn; dmn = dmn->next) { if (p != buf) *p++ = ' '; strcpy(p,dmn->name); p += strlen(p); } zlog_notice("%s %s watching [%s], mode [%s]", progname, QUAGGA_VERSION, buf, mode_str[gs.mode]); } } { struct thread thread; while (thread_fetch (master, &thread)) thread_call (&thread); } /* Not reached. */ return 0; } quagga-0.99.24.1/watchquagga/Makefile.am0000644000175000017500000000052612476520570014567 00000000000000## Process this file with Automake to create Makefile.in AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) sbin_PROGRAMS = watchquagga watchquagga_SOURCES = watchquagga.c watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ quagga-0.99.24.1/watchquagga/Makefile.in0000644000175000017500000005037412476521251014603 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = watchquagga$(EXEEXT) subdir = watchquagga DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am_watchquagga_OBJECTS = watchquagga.$(OBJEXT) watchquagga_OBJECTS = $(am_watchquagga_OBJECTS) watchquagga_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(watchquagga_SOURCES) DIST_SOURCES = $(watchquagga_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSTATEDIR=\"$(localstatedir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) watchquagga_SOURCES = watchquagga.c watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu watchquagga/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu watchquagga/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list watchquagga$(EXEEXT): $(watchquagga_OBJECTS) $(watchquagga_DEPENDENCIES) $(EXTRA_watchquagga_DEPENDENCIES) @rm -f watchquagga$(EXEEXT) $(AM_V_CCLD)$(LINK) $(watchquagga_OBJECTS) $(watchquagga_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchquagga.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/isisd/0000755000175000017500000000000012476521356011432 500000000000000quagga-0.99.24.1/isisd/topology/0000755000175000017500000000000012476521356013306 500000000000000quagga-0.99.24.1/isisd/topology/random.c0000644000175000017500000001277112476520570014657 00000000000000/*********************************************************************/ /* */ /* current processor time in seconds */ /* difference between two calls is processor time spent by your code */ /* needs: , */ /* depends on compiler and OS */ /* */ /*********************************************************************/ #include #include /* * Prototypes. */ unsigned long timer(void); void init_rand(long); double rand01(void); double randg01(void); long nrand(long); void free_arc(void *); unsigned long timer () { struct tms hold; times(&hold); return (unsigned long) ((float) (hold.tms_utime) / 60.0); } /*********************************************************************/ /* */ /* Family of random number generators */ /* */ /* Initialisation: */ /* void init_rand ( seed ); */ /* long seed - any positive number */ /* if seed<=0 init_rand takes time */ /* from timer instead of seed */ /* */ /* Whole number uniformly distributed on [0,n): */ /* long nrand (n); */ /* long n */ /* */ /* Real number uniformly distributed on [0,1] */ /* double rand01(); */ /* */ /* Real number with Gauss(0,1) disitribution: */ /* double randg01(); */ /* */ /* Algorithm: */ /* x(n+1) = (x(n) * 5^13) mod 2^31 */ /* */ /*********************************************************************/ unsigned long internal_seed; void init_rand ( init_seed ) long init_seed; { internal_seed = ( init_seed > 0 ) ? (unsigned long) init_seed : (unsigned long) timer(); /* only odd numbers are acceptable */ if ( internal_seed % 2 == 0 ) internal_seed --; } /*********************************************************************/ /* */ /* Internal function irand may depend on OS and compiler */ /* */ /* irand assumption: */ /* unsigned long i,j; */ /* if i*j > max(unsigned long) */ /* 1. No overflow interruption */ /* 2. i*j = i*j mod max(unsigned long) */ /* */ /* This assumption is true for a lot of computers. */ /* If your computer fails: */ /* rename: irand <---> xrand */ /* */ /*********************************************************************/ #define A 1220703125 #define B 2147483647 #define BF 2147483647. static long irand () { internal_seed = ( internal_seed * A ) & B; return (long) internal_seed ; } #if 0 /* Not used. */ /*********************************************************************/ /* */ /* computer independent variant of irand */ /* */ /*********************************************************************/ #define T15 32768 #define T16 65536 #define A1 37252 #define A2 29589 static long xrand() { unsigned long is1, is2; is1 = internal_seed / T15; is2 = internal_seed % T15; internal_seed = ( (((is2 * A1) + (is1 * A2))% T16 )* T15 + (is2 * A2) ) & B; return (long) ( internal_seed ) ; } #endif /*********************************************************************/ double rand01() { return (double) (irand() / BF) ; } /*********************************************************************/ #define NK 12 double randg01() { int i; double sum = 0; for ( i = 0; i < NK; i++ ) sum += rand01(); return sum - 6.; /* if NK != 12 then you must return (12/NK)*sum - (NK/2) */ } #undef NK /*********************************************************************/ long nrand ( n ) long n; { return (long) ( rand01() * (double) n ); } /*********************************************************************/ #undef A #undef A1 #undef A2 #undef B #undef BF #undef T15 #undef T16 quagga-0.99.24.1/isisd/topology/spgrid.c0000644000175000017500000004446312476520570014672 00000000000000#include #include #include #include "random.c" #include #include "thread.h" #include "vty.h" #include "log.h" #include "linklist.h" #include "spgrid.h" #define DASH '-' #define VERY_FAR 100000000 #define DOUBLE_CYCLE 0 #define CYCLE 1 #define PATH 2 #define NO 0 #define YES 1 #define NODE( x, y ) (x*Y + y + 1) /* * Prototypes. */ void free_arc(void *); void help(struct vty *); void print_arc(struct vty *, struct list *, long, long, long); void hhelp(struct vty *); void usage(struct vty *); const char *graph_type[] = { "double cycle", "cycle", "path" }; struct arc *arc; char args[30]; long X, /* horizontal size of grid */ Y; /* vertical size of grid */ long x, y, y1, y2, yp, dl, dx, xn, yn, count, *mess; double n; long n0, source, i, i0, j, dij; double m; long m0, mc, k; long *p, p_t, l, lx; long seed, seed1, seed2; int ext=0; /* initialized by default values */ /* variables for generating one layer */ /* variables for generating spanning graph */ int c_f = 0, cw_f = 0, cm_f = 0, cl_f = 0; int cw = DOUBLE_CYCLE; /* type of spanning graph */ long cm = 0, /* lower bound of the interval */ cl = 100; /* upper bound of the interval */ /* variables for generating additional arcs */ int a_f = 0, ax_f = 0, am_f = 0, al_f = 0; long ax = 0, /* number of additional arcs */ am = 0, /* lower bound of the interval */ al = 100; /* upper bound of the interval */ /* variables for inter-layer arcs */ int i_f = 0, ip_f = 0, ix_f = 0, ih_f = 0, im_f = 0, il_f = 0, in_f = 0, is_f = 0; int ip = NO; /* to mess or not to mess */ long ix = 1, /* number of interlayered arcs in a NODE */ ih = 1, /* step between two layeres */ il = 10000, /* upper bound of the interval */ im = 1000; /* lower bound of the interval */ double in = 1, /* l *= in * |x1-x2| */ is = 0; /* l *= is * |x1-x2|^2 */ /* variables for artifical source */ int s_f = 0, sl_f = 0, sm_f = 0; long sl = VERY_FAR, /* upper bound of artifical arc */ sm, /* lower bound of artifical arc */ s; /* variables for potentials */ int p_f = 0, pl_f = 0, pm_f = 0, pn_f = 0, ps_f = 0; long pl, /* upper bound of the interval */ pm; /* lower bound of the interval */ double pn = 0, /* p += ln * (x+1) */ ps = 0; /* p += ls * (x+1)^2 */ int np; /* number of parameter parsing now */ void free_arc (void *val) { free(val); } void print_arc (struct vty *vty, struct list *topology, long i, long j, long length) { struct arc *myarc; l = length; if ( p_f ) l += ( p[i] - p[j] ); // vty_out (vty,"a %8ld %8ld %12ld%s", i, j, l ,VTY_NEWLINE); myarc = malloc (sizeof(struct arc)); myarc->from_node = i; myarc->to_node = j; myarc->distance = l; topology->del = free_arc; listnode_add (topology, myarc); } /* ---- help ---- */ void help (struct vty *vty) { // if ( args[2] == 'h') hhelp (vty); vty_out (vty,"grid network generator for shortest paths problem.%s",VTY_NEWLINE); vty_out (vty,"Generates problems in extended DIMACS format.%s",VTY_NEWLINE); vty_out (vty,"X Y seed [ -cl#i -cm#i -c{c|d|p} -ip -il#i -im#i -p -pl#i -pm#i... ]%s",VTY_NEWLINE); vty_out (vty,"#i - integer number%s",VTY_NEWLINE); vty_out (vty,"-cl#i - #i is the upper bound on layer arc lengths (default 100)%s",VTY_NEWLINE); vty_out (vty,"-cm#i - #i is the lower bound on layer arc lengths (default 0)%s",VTY_NEWLINE); vty_out (vty,"-c#t - #t is the type of connecting graph: { c | d | p }%s",VTY_NEWLINE); vty_out (vty," c - cycle, d - double cycle, p - path (default d)%s",VTY_NEWLINE); vty_out (vty,"-ip - shuffle inter-layer arcs (default NO)%s",VTY_NEWLINE); vty_out (vty,"-il#i - #i is the upper bound on inter-layer arc lengths (default 10000)%s",VTY_NEWLINE); vty_out (vty,"-im#i - #i is the lower bound on inter-layer arc lengths (default 1000)%s",VTY_NEWLINE); vty_out (vty,"-p - generate potentials%s",VTY_NEWLINE); vty_out (vty,"-pl#i - #i is the upper bound on potentials (default il)%s",VTY_NEWLINE); vty_out (vty,"-pm#i - #i is the lower bound on potentials (default im)%s",VTY_NEWLINE); vty_out (vty,"%s",VTY_NEWLINE); vty_out (vty,"-hh - extended help%s",VTY_NEWLINE); } /* --------- sophisticated help ------------ */ void hhelp (struct vty *vty) { /* zlog_info ( "\n'%s' - grid network generator for shortest paths problem.\n\ Generates problems in extended DIMACS format.\n\ \n\ %s X Y seed [ -cl#i -cm#i -c{c|d|p}\n\ -ax#i -al#i -am#i\n\ -ip -il#i -im#i -in#i -is#i -ix#i -ih#i\n\ -p -pl#i -pm#i -pn#f -ps#f\n\ -s -sl#i -sm#i\n\ ]\n\ %s -hh file_name\n\ \n\ #i - integer number #f - real number\n\ \n\ Parameters of connecting arcs within one layer:\n\ -cl#i - #i is the upper bound on arc lengths (default 100)\n\ -cm#i - #i is the lower bound on arc lengths (default 0)\n\ -c#t - #t is the type of connecting graph: { c | d | p }\n\ c - cycle, d - double cycle, p - path (default d)\n\ \n\ Parameters of additional arcs within one layer:\n\ -ax#i - #i is the number of additional arcs (default 0)\n\ -al#i - #i is the upper bound on arc lengths (default 100)\n\ -am#i - #i is the lower bound on arc lengths (default 0)\n\ \n\ Interlayerd arc parameters:\n\ -ip - shuffle inter-layer arcs (default NO)\n\ -il#i - #i is the upper bound on arc lengths (default 10000)\n\ -im#i - #i is the lower bound on arc lengths (default 1000)\n\ -in#f - multiply l(i, j) by #f * x(j)-x(i) (default 1)\n\ if #f=0 - don't multiply\n\ -is#f - multiply l(i, j) by #f * (x(j)-x(i))^2 (default NO)\n\ -ix#i - #i - is the number of arcs from a node (default 1)\n\ -ih#i - #i - is the step between connected layers (default 1)\n\ \n\ Potential parameters:\n\ -p - generate potentials \n\ -pl#i - #i is the upper bound on potentials (default ll)\n\ -pm#i - #i is the lower bound on potentials (default lm)\n\ -pn#f - multiply p(i) by #f * x(i) (default NO)\n\ -ps#f - multiply p(i) by #f * x(i)^2 (default NO)\n\ \n"); zlog_info ( " Artificial source parameters:\n\ -s - generate artificial source with default connecting arc lengths\n\ -sl#i - #i is the upper bound on art. arc lengths (default 100000000)\n\ -sm#i - #i is the lower bound on art. arc lengths (default sl)\n\" );*/ } /* ----- wrong usage ----- */ void usage (struct vty *vty) { vty_out (vty,"usage: X Y seed [-ll#i -lm#i -cl#i -p -pl#i -pm#i ...]%s",VTY_NEWLINE); vty_out (vty,"help: -h or -hh%s",VTY_NEWLINE); if ( np > 0 ) zlog_err ("error in parameter # %d\n\n", np ); } /* parsing parameters */ /* checks the validity of incoming parameters */ int spgrid_check_params ( struct vty *vty, int argc, const char **argv) { /* initialized by default values */ ext=0; /* variables for generating one layer */ /* variables for generating spanning graph */ c_f = 0; cw_f = 0; cm_f = 0; cl_f = 0; cw = PATH; /* type of spanning graph */ cm = 0; /* lower bound of the interval */ cl = 63; /* upper bound of the interval */ /* variables for generating additional arcs */ a_f = 0; ax_f = 0; am_f = 0; al_f = 0; ax = 0; /* number of additional arcs */ am = 0; /* lower bound of the interval */ al = 63; /* upper bound of the interval */ /* variables for inter-layer arcs */ i_f = 0; ip_f = 0; ix_f = 0; ih_f = 0; im_f = 0; il_f = 0; in_f = 0; is_f = 0; ip = NO; /* to mess or not to mess */ ix = 1; /* number of interlayered arcs in a NODE */ ih = 1; /* step between two layeres */ il = 63; //was 10000; /* upper bound of the interval */ im = 0; //was 1000; /* lower bound of the interval */ in = 1; /* l *= in * |x1-x2| */ is = 0; /* l *= is * |x1-x2|^2 */ /* variables for artifical source */ s_f = 0; sl_f = 0; sm_f = 0; sl = VERY_FAR; /* upper bound of artifical arc */ /* variables for potentials */ p_f = 0; pl_f = 0; pm_f = 0; pn_f = 0; ps_f = 0; pn = 0; /* p += ln * (x+1) */ ps = 0; /* p += ls * (x+1)^2 */ if ( argc < 1 ) { usage (vty); return 1; } np = 0; strcpy ( args, argv[0] ); if ((args[0] == DASH) && (args[1] == 'h')) help (vty); if ( argc < 3 ) { usage (vty); return 1; } /* first parameter - horizontal size */ np = 1; if ( ( X = atoi ( argv[0] ) ) < 1 ) { usage (vty); return 1; } /* second parameter - vertical size */ np = 2; if ( ( Y = atoi ( argv[1] ) ) < 1 ) { usage (vty); return 1; } /* third parameter - seed */ np=3; if ( ( seed = atoi ( argv[2] ) ) <= 0 ) { usage (vty); return 1; } /* other parameters */ for ( np = 3; np < argc; np ++ ) { strcpy ( args, argv[np] ); if ( args[0] != DASH ) { usage (vty); return 1; } switch ( args[1] ) { case 'c' : /* spanning graph in one layer */ c_f = 1; switch ( args[2] ) { case 'l': /* upper bound of the interval */ cl_f = 1; cl = atol ( &args[3] ); break; case 'm': /* lower bound */ cm_f = 1; cm = atol ( &args[3] ); break; case 'c': /* type - cycle */ cw_f = 1; cw = CYCLE; break; case 'd': /* type - double cycle */ cw_f = 1; cw = DOUBLE_CYCLE; break; case 'p': /* type - path */ cw_f = 1; cw = PATH; break; default: /* unknown switch value */ usage (vty); return 1; } break; case 'a' : /* additional arcs in one layer */ a_f = 1; switch ( args[2] ) { case 'l': /* upper bound of the interval */ al_f = 1; al = atol ( &args[3] ); break; case 'm': /* lower bound */ am_f = 1; am = atol ( &args[3] ); break; case 'x': /* number of additional arcs */ ax_f = 1; ax = atol ( &args[3] ); if ( ax < 0 ) { usage (vty); return 1; } break; default: /* unknown switch value */ { usage (vty); return 1; } } break; case 'i' : /* interlayered arcs */ i_f = 1; switch ( args[2] ) { case 'l': /* upper bound */ il_f = 1; il = atol ( &args[3] ); break; case 'm': /* lower bound */ im_f = 1; im = atol ( &args[3] ); break; case 'n': /* additional length: l *= in*|i1-i2| */ in_f = 1; in = atof ( &args[3] ); break; case 's': /* additional length: l *= is*|i1-i2|^2 */ is_f = 1; is = atof ( &args[3] ); break; case 'p': /* mess interlayered arcs */ ip_f = 1; ip = YES; break; case 'x': /* number of interlayered arcs */ ix_f = 1; ix = atof ( &args[3] ); if ( ix < 1 ) { usage (vty); return 1; } break; case 'h': /* step between two layeres */ ih_f = 1; ih = atof ( &args[3] ); if ( ih < 1 ) { usage (vty); return 1; } break; default: /* unknown switch value */ usage (vty); return 1; } break; case 's' : /* additional source */ s_f = 1; if ( strlen ( args ) > 2 ) { switch ( args[2] ) { case 'l': /* upper bound of art. arc */ sl_f = 1; sl = atol ( &args[3] ); break; case 'm': /* lower bound of art. arc */ sm_f = 1; sm = atol ( &args[3] ); break; default: /* unknown switch value */ usage (vty); return 1; } } break; case 'p' : /* potentials */ p_f = 1; if ( strlen ( args ) > 2 ) { switch ( args[2] ) { case 'l': /* upper bound */ pl_f = 1; pl = atol ( &args[3] ); break; case 'm': /* lower bound */ pm_f = 1; pm = atol ( &args[3] ); break; case 'n': /* additional: p *= pn*(x+1) */ pn_f = 1; pn = atof ( &args[3] ); break; case 's': /* additional: p = ps* (x+1)^2 */ ps_f = 1; ps = atof ( &args[3] ); break; default: /* unknown switch value */ usage (vty); return 1; } } break; default: /* unknoun case */ usage (vty); return 1; } } return 0; } /* generator of layered networks for the shortest paths problem; extended DIMACS format for output */ int gen_spgrid_topology (struct vty *vty, struct list *topology) { /* ----- ajusting parameters ----- */ /* spanning */ if ( cl < cm ) { lx = cl; cl = cm; cm = lx; } /* additional arcs */ if ( al < am ) { lx = al; al = am; am = lx; } /* interlayered arcs */ if ( il < im ) { lx = il; il = im; im = lx; } /* potential parameters */ if ( p_f ) { if ( ! pl_f ) pl = il; if ( ! pm_f ) pm = im; if ( pl < pm ) { lx = pl; pl = pm; pm = lx; } } /* number of nodes and arcs */ n = (double)X *(double)Y + 1; m = (double)Y; /* arcs from source */ switch ( cw ) { case PATH: mc = (double)Y - 1; break; case CYCLE: mc = (double)Y; break; case DOUBLE_CYCLE: mc = 2*(double)Y; } m += (double)X * (double)mc; /* spanning arcs */ m += (double)X * (double)ax; /* additional arcs */ /* interlayered arcs */ for ( x = 0; x < X; x ++ ) { dl = ( ( X - x - 1 ) + ( ih - 1 ) ) / ih; if ( dl > ix ) dl = ix; m += (double)Y * (double)dl; } /* artifical source parameters */ if ( s_f ) { m += n; n ++ ; if ( ! sm_f ) sm = sl; if ( sl < sm ) { lx = sl; sl = sm; sm = lx; } } if ( n >= (double)LONG_MAX || m >= (double)LONG_MAX ) { zlog_err ("Too large problem. It can't be generated\n"); exit (4); } else { n0 = (long)n; m0 = (long)m; } if ( ip_f ) mess = (long*) calloc ( Y, sizeof ( long ) ); /* printing title */ zlog_info ("Generating topology for ISIS"); source = ( s_f ) ? n0-1 : n0; if ( p_f ) /* generating potentials */ { p = (long*) calloc ( n0+1, sizeof (long) ); seed1 = 2*seed + 1; init_rand ( seed1); pl = pl - pm + 1; for ( x = 0; x < X; x ++ ) for ( y = 0; y < Y; y ++ ) { p_t = pm + nrand ( pl ); if ( pn_f ) p_t *= (long) ( (1 + x) * pn ); if ( ps_f ) p_t *= (long) ( (1 + x) * ( (1 + x) * ps )); p[ NODE ( x, y ) ] = p_t; } p[n0] = 0; if ( s_f ) p[n0-1] = 0; } if ( s_f ) /* additional arcs from artifical source */ { seed2 = 3*seed + 1; init_rand ( seed2 ); sl = sl - sm + 1; for ( x = X - 1; x >= 0; x -- ) for ( y = Y - 1; y >= 0; y -- ) { i = NODE ( x, y ); s = sm + nrand ( sl ); print_arc (vty, topology, n0, i, s ); } print_arc (vty, topology, n0, n0-1, 0 ); } /* ----- generating arcs within layers ----- */ init_rand ( seed ); cl = cl - cm + 1; al = al - am + 1; for ( x = 0; x < X; x ++ ) { /* generating arcs within one layer */ for ( y = 0; y < Y-1; y ++ ) { /* generating spanning graph */ i = NODE ( x, y ); j = NODE ( x, y+1 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } if ( cw <= CYCLE ) { i = NODE ( x, Y-1 ); j = NODE ( x, 0 ); l = cm + nrand ( cl ); print_arc (vty, topology, i, j, l ); if ( cw == DOUBLE_CYCLE ) { l = cm + nrand ( cl ); print_arc (vty, topology, j, i, l ); } } /* generating additional arcs */ for ( k = ax; k > 0; k -- ) { y1 = nrand ( Y ); do y2 = nrand ( Y ); while ( y2 == y1 ); i = NODE ( x, y1 ); j = NODE ( x, y2 ); l = am + nrand ( al ); print_arc (vty, topology, i, j, l ); } } /* ----- generating interlayered arcs ------ */ il = il - im + 1; /* arcs from the source */ for ( y = 0; y < Y; y ++ ) { l = im + nrand ( il ); i = NODE ( 0, y ); print_arc (vty, topology, source, i, l ); } for ( x = 0; x < X-1; x ++ ) { /* generating arcs from one layer */ for ( count = 0, xn = x + 1; count < ix && xn < X; count ++, xn += ih ) { if ( ip_f ) for ( y = 0; y < Y; y ++ ) mess[y] = y; for ( y = 0; y < Y; y ++ ) { i = NODE ( x, y ); dx = xn - x; if ( ip_f ) { yp = nrand(Y-y); yn = mess[ yp ]; mess[ yp ] = mess[ Y - y - 1 ]; } else yn = y; j = NODE ( xn, yn ); l = im + nrand ( il ); if ( in != 0 ) l *= (long) ( in * dx ); if ( is_f ) l *= (long) ( ( is * dx ) * dx ); print_arc (vty, topology, i, j, l ); } } } /* all is done */ return ext; return 0; } quagga-0.99.24.1/isisd/topology/spgrid.h0000644000175000017500000000250012476520570014661 00000000000000/* * IS-IS Rout(e)ing protocol - topology/spgrid.h Routines for manipulation of SSN and SRM flags * Copyright (C) 2001 Sampo Saaristo, Ofer Wald * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * Based on: * SPLIB Copyright C 1994 by Cherkassky, Goldberg, and Radzik * */ #ifndef _ZEBRA_ISIS_TOPOLOGY_SPGRID_H #define _ZEBRA_ISIS_TOPOLOGY_SPGRID_H struct arc { long from_node; long to_node; long distance; }; int gen_spgrid_topology (struct vty *vty, struct list *topology); int spgrid_check_params (struct vty *vty, int argc, const char **argv); #endif /* _ZEBRA_ISIS_TOPOLOGY_SPGRID_H */ quagga-0.99.24.1/isisd/topology/Makefile.am0000644000175000017500000000072112476520570015257 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libtopology.a libtopology_a_SOURCES = \ spgrid.c random.c libtopology_a_DEPENDENCIES = @LIB_REGEX@ libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.la noinst_HEADERS = \ spgrid.h ## File dependency. quagga-0.99.24.1/isisd/topology/Makefile.in0000644000175000017500000004517112476521251015275 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ subdir = isisd/topology DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libtopology_a_AR = $(AR) $(ARFLAGS) am_libtopology_a_OBJECTS = spgrid.$(OBJEXT) random.$(OBJEXT) libtopology_a_OBJECTS = $(am_libtopology_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libtopology_a_SOURCES) DIST_SOURCES = $(libtopology_a_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libtopology.a libtopology_a_SOURCES = \ spgrid.c random.c libtopology_a_DEPENDENCIES = @LIB_REGEX@ libtopology_a_LIBADD = @LIB_REGEX@ ../../lib/libzebra.la noinst_HEADERS = \ spgrid.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu isisd/topology/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu isisd/topology/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libtopology.a: $(libtopology_a_OBJECTS) $(libtopology_a_DEPENDENCIES) $(EXTRA_libtopology_a_DEPENDENCIES) $(AM_V_at)-rm -f libtopology.a $(AM_V_AR)$(libtopology_a_AR) libtopology.a $(libtopology_a_OBJECTS) $(libtopology_a_LIBADD) $(AM_V_at)$(RANLIB) libtopology.a mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spgrid.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(HEADERS) installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/isisd/isis_pfpacket.c0000644000175000017500000002616112476520570014345 00000000000000/* * IS-IS Rout(e)ing protocol - isis_pfpacket.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #if ISIS_METHOD == ISIS_METHOD_PFPACKET #include /* the L2 protocols */ #include #include "log.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_constants.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static char discard_buff[8192]; static char sock_buff[8192]; /* * if level is 0 we are joining p2p multicast * FIXME: and the p2p multicast being ??? */ static int isis_multicast_join (int fd, int registerto, int if_num) { struct packet_mreq mreq; memset (&mreq, 0, sizeof (mreq)); mreq.mr_ifindex = if_num; if (registerto) { mreq.mr_type = PACKET_MR_MULTICAST; mreq.mr_alen = ETH_ALEN; if (registerto == 1) memcpy (&mreq.mr_address, ALL_L1_ISS, ETH_ALEN); else if (registerto == 2) memcpy (&mreq.mr_address, ALL_L2_ISS, ETH_ALEN); else if (registerto == 3) memcpy (&mreq.mr_address, ALL_ISS, ETH_ALEN); else memcpy (&mreq.mr_address, ALL_ESS, ETH_ALEN); } else { mreq.mr_type = PACKET_MR_ALLMULTI; } #ifdef EXTREME_DEBUG zlog_debug ("isis_multicast_join(): fd=%d, reg_to=%d, if_num=%d, " "address = %02x:%02x:%02x:%02x:%02x:%02x", fd, registerto, if_num, mreq.mr_address[0], mreq.mr_address[1], mreq.mr_address[2], mreq.mr_address[3], mreq.mr_address[4], mreq.mr_address[5]); #endif /* EXTREME_DEBUG */ if (setsockopt (fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof (struct packet_mreq))) { zlog_warn ("isis_multicast_join(): setsockopt(): %s", safe_strerror (errno)); return ISIS_WARNING; } return ISIS_OK; } static int open_packet_socket (struct isis_circuit *circuit) { struct sockaddr_ll s_addr; int fd, retval = ISIS_OK; fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_ALL)); if (fd < 0) { zlog_warn ("open_packet_socket(): socket() failed %s", safe_strerror (errno)); return ISIS_WARNING; } /* * Bind to the physical interface */ memset (&s_addr, 0, sizeof (struct sockaddr_ll)); s_addr.sll_family = AF_PACKET; s_addr.sll_protocol = htons (ETH_P_ALL); s_addr.sll_ifindex = circuit->interface->ifindex; if (bind (fd, (struct sockaddr *) (&s_addr), sizeof (struct sockaddr_ll)) < 0) { zlog_warn ("open_packet_socket(): bind() failed: %s", safe_strerror (errno)); close (fd); return ISIS_WARNING; } circuit->fd = fd; if (if_is_broadcast (circuit->interface)) { /* * Join to multicast groups * according to * 8.4.2 - Broadcast subnetwork IIH PDUs * FIXME: is there a case only one will fail?? */ /* joining ALL_L1_ISS */ retval |= isis_multicast_join (circuit->fd, 1, circuit->interface->ifindex); /* joining ALL_L2_ISS */ retval |= isis_multicast_join (circuit->fd, 2, circuit->interface->ifindex); /* joining ALL_ISS (used in RFC 5309 p2p-over-lan as well) */ retval |= isis_multicast_join (circuit->fd, 3, circuit->interface->ifindex); } else { retval = isis_multicast_join (circuit->fd, 0, circuit->interface->ifindex); } return retval; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_packet_socket (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } /* Assign Rx and Tx callbacks are based on real if type */ if (if_is_broadcast (circuit->interface)) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else if (if_is_pointopoint (circuit->interface)) { circuit->tx = isis_send_pdu_p2p; circuit->rx = isis_recv_pdu_p2p; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } static inline int llc_check (u_char * llc) { if (*llc != ISO_SAP || *(llc + 1) != ISO_SAP || *(llc + 2) != 3) return 0; return 1; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread, addr_len; struct sockaddr_ll s_addr; u_char llc[LLC_LEN]; addr_len = sizeof (s_addr); memset (&s_addr, 0, sizeof (struct sockaddr_ll)); bytesread = recvfrom (circuit->fd, (void *) &llc, LLC_LEN, MSG_PEEK, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) { zlog_warn ("isis_recv_packet_bcast(): ifname %s, fd %d, bytesread %d, " "recvfrom(): %s", circuit->interface->name, circuit->fd, bytesread, safe_strerror (errno)); /* get rid of the packet */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); return ISIS_WARNING; } /* * Filtering by llc field, discard packets sent by this host (other circuit) */ if (!llc_check (llc) || s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); return ISIS_WARNING; } /* on lan we have to read to the static buff first */ bytesread = recvfrom (circuit->fd, sock_buff, sizeof (sock_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) { zlog_warn ("isis_recv_pdu_bcast(): recvfrom() failed"); return ISIS_WARNING; } /* then we lose the LLC */ stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, bytesread - LLC_LEN); memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen); return ISIS_OK; } int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread, addr_len; struct sockaddr_ll s_addr; memset (&s_addr, 0, sizeof (struct sockaddr_ll)); addr_len = sizeof (s_addr); /* we can read directly to the stream */ bytesread = stream_recvfrom (circuit->rcv_stream, circuit->fd, circuit->interface->mtu, 0, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ bytesread = recvfrom (circuit->fd, discard_buff, sizeof (discard_buff), MSG_DONTWAIT, (struct sockaddr *) &s_addr, (socklen_t *) &addr_len); if (bytesread < 0) zlog_warn ("isis_recv_pdu_p2p(): recvfrom() failed"); return ISIS_WARNING; } /* If we don't have protocol type 0x00FE which is * ISO over GRE we exit with pain :) */ if (ntohs (s_addr.sll_protocol) != 0x00FE) { zlog_warn ("isis_recv_pdu_p2p(): protocol mismatch(): %X", ntohs (s_addr.sll_protocol)); return ISIS_WARNING; } memcpy (ssnpa, &s_addr.sll_addr, s_addr.sll_halen); return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct msghdr msg; struct iovec iov[2]; /* we need to do the LLC in here because of P2P circuits, which will * not need it */ int written = 1; struct sockaddr_ll sa; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; /* RFC5309 section 4.1 recommends ALL_ISS */ if (circuit->circ_type == CIRCUIT_T_P2P) memcpy (&sa.sll_addr, ALL_ISS, ETH_ALEN); else if (level == 1) memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN); else memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN); /* on a broadcast circuit */ /* first we put the LLC in */ sock_buff[0] = 0xFE; sock_buff[1] = 0xFE; sock_buff[2] = 0x03; memset (&msg, 0, sizeof (msg)); msg.msg_name = &sa; msg.msg_namelen = sizeof (struct sockaddr_ll); msg.msg_iov = iov; msg.msg_iovlen = 2; iov[0].iov_base = sock_buff; iov[0].iov_len = LLC_LEN; iov[1].iov_base = circuit->snd_stream->data; iov[1].iov_len = stream_get_endp (circuit->snd_stream); written = sendmsg (circuit->fd, &msg, 0); return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { int written = 1; struct sockaddr_ll sa; stream_set_getp (circuit->snd_stream, 0); memset (&sa, 0, sizeof (struct sockaddr_ll)); sa.sll_family = AF_PACKET; sa.sll_protocol = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); sa.sll_ifindex = circuit->interface->ifindex; sa.sll_halen = ETH_ALEN; if (level == 1) memcpy (&sa.sll_addr, ALL_L1_ISS, ETH_ALEN); else memcpy (&sa.sll_addr, ALL_L2_ISS, ETH_ALEN); /* lets try correcting the protocol */ sa.sll_protocol = htons (0x00FE); written = sendto (circuit->fd, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream), 0, (struct sockaddr *) &sa, sizeof (struct sockaddr_ll)); return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_PFPACKET */ quagga-0.99.24.1/isisd/isis_dlpi.c0000644000175000017500000004000612476520570013472 00000000000000/* * IS-IS Rout(e)ing protocol - isis_dlpi.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #if ISIS_METHOD == ISIS_METHOD_DLPI #include #include #include #include #include #include #include #include #include #include "log.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; static t_uscalar_t dlpi_ctl[1024]; /* DLPI control messages */ /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static u_char sock_buff[8192]; static u_short pf_filter[] = { ENF_PUSHWORD + 0, /* Get the SSAP/DSAP values */ ENF_PUSHLIT | ENF_CAND, /* Check them */ ISO_SAP | (ISO_SAP << 8), ENF_PUSHWORD + 1, /* Get the control value */ ENF_PUSHLIT | ENF_AND, /* Isolate it */ #ifdef _BIG_ENDIAN 0xFF00, #else 0x00FF, #endif ENF_PUSHLIT | ENF_CAND, /* Test for expected value */ #ifdef _BIG_ENDIAN 0x0300 #else 0x0003 #endif }; /* * We would like to use something like libdlpi here, but that's not present on * all versions of Solaris or on any non-Solaris system, so it's nowhere near * as portable as we'd like. Thus, we use the standards-conformant DLPI * interfaces plus the (optional; not needed) Solaris packet filter module. */ static void dlpisend (int fd, const void *cbuf, size_t cbuflen, const void *dbuf, size_t dbuflen, int flags) { const struct strbuf *ctlptr = NULL; const struct strbuf *dataptr = NULL; struct strbuf ctlbuf, databuf; if (cbuf != NULL) { memset (&ctlbuf, 0, sizeof (ctlbuf)); ctlbuf.len = cbuflen; ctlbuf.buf = (void *)cbuf; ctlptr = &ctlbuf; } if (dbuf != NULL) { memset (&databuf, 0, sizeof (databuf)); databuf.len = dbuflen; databuf.buf = (void *)dbuf; dataptr = &databuf; } /* We assume this doesn't happen often and isn't operationally significant */ if (putmsg (fd, ctlptr, dataptr, flags) == -1) zlog_debug ("%s: putmsg: %s", __func__, safe_strerror (errno)); } static ssize_t dlpirctl (int fd) { struct pollfd fds[1]; struct strbuf ctlbuf, databuf; int flags, retv; do { /* Poll is used here in case the device doesn't speak DLPI correctly */ memset (fds, 0, sizeof (fds)); fds[0].fd = fd; fds[0].events = POLLIN | POLLPRI; if (poll (fds, 1, 1000) <= 0) return -1; memset (&ctlbuf, 0, sizeof (ctlbuf)); memset (&databuf, 0, sizeof (databuf)); ctlbuf.maxlen = sizeof (dlpi_ctl); ctlbuf.buf = (void *)dlpi_ctl; databuf.maxlen = sizeof (sock_buff); databuf.buf = (void *)sock_buff; flags = 0; retv = getmsg (fd, &ctlbuf, &databuf, &flags); if (retv < 0) return -1; } while (ctlbuf.len == 0); if (!(retv & MORECTL)) { while (retv & MOREDATA) { flags = 0; retv = getmsg (fd, NULL, &databuf, &flags); } return ctlbuf.len; } while (retv & MORECTL) { flags = 0; retv = getmsg (fd, &ctlbuf, &databuf, &flags); } return -1; } static int dlpiok (int fd, t_uscalar_t oprim) { int retv; dl_ok_ack_t *doa = (dl_ok_ack_t *)dlpi_ctl; retv = dlpirctl (fd); if (retv < DL_OK_ACK_SIZE || doa->dl_primitive != DL_OK_ACK || doa->dl_correct_primitive != oprim) { return -1; } else { return 0; } } static int dlpiinfo (int fd) { dl_info_req_t dir; ssize_t retv; memset (&dir, 0, sizeof (dir)); dir.dl_primitive = DL_INFO_REQ; /* Info_req uses M_PCPROTO. */ dlpisend (fd, &dir, sizeof (dir), NULL, 0, RS_HIPRI); retv = dlpirctl (fd); if (retv < DL_INFO_ACK_SIZE || dlpi_ctl[0] != DL_INFO_ACK) return -1; else return retv; } static int dlpiopen (const char *devpath, ssize_t *acklen) { int fd, flags; fd = open (devpath, O_RDWR | O_NONBLOCK | O_NOCTTY); if (fd == -1) return -1; /* All that we want is for the open itself to be non-blocking, not I/O. */ flags = fcntl (fd, F_GETFL, 0); if (flags != -1) fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); /* After opening, ask for information */ if ((*acklen = dlpiinfo (fd)) == -1) { close (fd); return -1; } return fd; } static int dlpiattach (int fd, int unit) { dl_attach_req_t dar; memset (&dar, 0, sizeof (dar)); dar.dl_primitive = DL_ATTACH_REQ; dar.dl_ppa = unit; dlpisend (fd, &dar, sizeof (dar), NULL, 0, 0); return dlpiok (fd, dar.dl_primitive); } static int dlpibind (int fd) { dl_bind_req_t dbr; int retv; dl_bind_ack_t *dba = (dl_bind_ack_t *)dlpi_ctl; memset (&dbr, 0, sizeof (dbr)); dbr.dl_primitive = DL_BIND_REQ; dbr.dl_service_mode = DL_CLDLS; dlpisend (fd, &dbr, sizeof (dbr), NULL, 0, 0); retv = dlpirctl (fd); if (retv < DL_BIND_ACK_SIZE || dba->dl_primitive != DL_BIND_ACK) return -1; else return 0; } static int dlpimcast (int fd, const u_char *mcaddr) { struct { dl_enabmulti_req_t der; u_char addr[ETHERADDRL]; } dler; memset (&dler, 0, sizeof (dler)); dler.der.dl_primitive = DL_ENABMULTI_REQ; dler.der.dl_addr_length = sizeof (dler.addr); dler.der.dl_addr_offset = dler.addr - (u_char *)&dler; memcpy (dler.addr, mcaddr, sizeof (dler.addr)); dlpisend (fd, &dler, sizeof (dler), NULL, 0, 0); return dlpiok (fd, dler.der.dl_primitive); } static int dlpiaddr (int fd, u_char *addr) { dl_phys_addr_req_t dpar; dl_phys_addr_ack_t *dpaa = (dl_phys_addr_ack_t *)dlpi_ctl; int retv; memset (&dpar, 0, sizeof (dpar)); dpar.dl_primitive = DL_PHYS_ADDR_REQ; dpar.dl_addr_type = DL_CURR_PHYS_ADDR; dlpisend (fd, &dpar, sizeof (dpar), NULL, 0, 0); retv = dlpirctl (fd); if (retv < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_primitive != DL_PHYS_ADDR_ACK) return -1; if (dpaa->dl_addr_offset < DL_PHYS_ADDR_ACK_SIZE || dpaa->dl_addr_length != ETHERADDRL || dpaa->dl_addr_offset + dpaa->dl_addr_length > retv) return -1; bcopy((char *)dpaa + dpaa->dl_addr_offset, addr, ETHERADDRL); return 0; } static int open_dlpi_dev (struct isis_circuit *circuit) { int fd, unit, retval; char devpath[MAXPATHLEN]; dl_info_ack_t *dia = (dl_info_ack_t *)dlpi_ctl; ssize_t acklen; /* Only broadcast-type are supported at the moment */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn ("%s: non-broadcast interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Try the vanity node first, if permitted */ if (getenv("DLPI_DEVONLY") == NULL) { (void) snprintf (devpath, sizeof(devpath), "/dev/net/%s", circuit->interface->name); fd = dlpiopen (devpath, &acklen); } /* Now try as an ordinary Style 1 node */ if (fd == -1) { (void) snprintf (devpath, sizeof (devpath), "/dev/%s", circuit->interface->name); unit = -1; fd = dlpiopen (devpath, &acklen); } /* If that fails, try again as Style 2 */ if (fd == -1) { char *cp; cp = devpath + strlen (devpath); while (--cp >= devpath && isdigit(*cp)) ; unit = strtol(cp, NULL, 0); *cp = '\0'; fd = dlpiopen (devpath, &acklen); /* If that too fails, then the device really doesn't exist */ if (fd == -1) { zlog_warn ("%s: unknown interface %s", __func__, circuit->interface->name); return ISIS_WARNING; } /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE2) { zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 2", circuit->interface->name, devpath); close (fd); return ISIS_WARNING; } /* If it succeeds, then we need to attach to the unit specified */ dlpiattach (fd, unit); /* Reget the information, as it may be different per node */ if ((acklen = dlpiinfo (fd)) == -1) { close (fd); return ISIS_WARNING; } } else { /* Double check the DLPI style */ if (dia->dl_provider_style != DL_STYLE1) { zlog_warn ("open_dlpi_dev(): interface %s: %s is not style 1", circuit->interface->name, devpath); close (fd); return ISIS_WARNING; } } /* Check that the interface we've got is the kind we expect */ if ((dia->dl_sap_length != 2 && dia->dl_sap_length != -2) || dia->dl_service_mode != DL_CLDLS || dia->dl_addr_length != ETHERADDRL + 2 || dia->dl_brdcst_addr_length != ETHERADDRL) { zlog_warn ("%s: unsupported interface type for %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } switch (dia->dl_mac_type) { case DL_CSMACD: case DL_ETHER: case DL_100VG: case DL_100VGTPR: case DL_ETH_CSMA: case DL_100BT: break; default: zlog_warn ("%s: unexpected mac type on %s: %d", __func__, circuit->interface->name, dia->dl_mac_type); close (fd); return ISIS_WARNING; } circuit->sap_length = dia->dl_sap_length; /* * The local hardware address is something that should be provided by way of * sockaddr_dl for the interface, but isn't on Solaris. We set it here based * on DLPI's reported address to avoid roto-tilling the world. * (Note that isis_circuit_if_add on Solaris doesn't set the snpa.) * * Unfortunately, GLD is broken and doesn't provide the address after attach, * so we need to be careful and use DL_PHYS_ADDR_REQ instead. */ if (dlpiaddr (fd, circuit->u.bc.snpa) == -1) { zlog_warn ("open_dlpi_dev(): interface %s: unable to get MAC address", circuit->interface->name); close (fd); return ISIS_WARNING; } /* Now bind to SAP 0. This gives us 802-type traffic. */ if (dlpibind (fd) == -1) { zlog_warn ("%s: cannot bind SAP 0 on %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } /* * Join to multicast groups according to * 8.4.2 - Broadcast subnetwork IIH PDUs */ retval = 0; retval |= dlpimcast (fd, ALL_L1_ISS); retval |= dlpimcast (fd, ALL_ISS); retval |= dlpimcast (fd, ALL_L2_ISS); if (retval != 0) { zlog_warn ("%s: unable to join multicast on %s", __func__, circuit->interface->name); close (fd); return ISIS_WARNING; } /* Push on the packet filter to avoid stray 802 packets */ if (ioctl (fd, I_PUSH, "pfmod") == 0) { struct packetfilt pfil; struct strioctl sioc; pfil.Pf_Priority = 0; pfil.Pf_FilterLen = sizeof (pf_filter) / sizeof (u_short); memcpy (pfil.Pf_Filter, pf_filter, sizeof (pf_filter)); /* pfmod does not support transparent ioctls */ sioc.ic_cmd = PFIOCSETF; sioc.ic_timout = 5; sioc.ic_len = sizeof (struct packetfilt); sioc.ic_dp = (char *)&pfil; if (ioctl (fd, I_STR, &sioc) == -1) zlog_warn("%s: could not perform PF_IOCSETF on %s", __func__, circuit->interface->name); } circuit->fd = fd; return ISIS_OK; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_dlpi_dev (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { struct pollfd fds[1]; struct strbuf ctlbuf, databuf; int flags, retv; dl_unitdata_ind_t *dui = (dl_unitdata_ind_t *)dlpi_ctl; memset (fds, 0, sizeof (fds)); fds[0].fd = circuit->fd; fds[0].events = POLLIN | POLLPRI; if (poll (fds, 1, 0) <= 0) return ISIS_WARNING; memset (&ctlbuf, 0, sizeof (ctlbuf)); memset (&databuf, 0, sizeof (databuf)); ctlbuf.maxlen = sizeof (dlpi_ctl); ctlbuf.buf = (void *)dlpi_ctl; databuf.maxlen = sizeof (sock_buff); databuf.buf = (void *)sock_buff; flags = 0; retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags); if (retv < 0) { zlog_warn ("isis_recv_pdu_bcast: getmsg failed: %s", safe_strerror (errno)); return ISIS_WARNING; } if (retv & (MORECTL | MOREDATA)) { while (retv & (MORECTL | MOREDATA)) { flags = 0; retv = getmsg (circuit->fd, &ctlbuf, &databuf, &flags); } return ISIS_WARNING; } if (ctlbuf.len < DL_UNITDATA_IND_SIZE || dui->dl_primitive != DL_UNITDATA_IND) return ISIS_WARNING; if (dui->dl_src_addr_length != ETHERADDRL + 2 || dui->dl_src_addr_offset < DL_UNITDATA_IND_SIZE || dui->dl_src_addr_offset + dui->dl_src_addr_length > ctlbuf.len) return ISIS_WARNING; memcpy (ssnpa, (char *)dui + dui->dl_src_addr_offset + (circuit->sap_length > 0 ? circuit->sap_length : 0), ETHERADDRL); if (databuf.len < LLC_LEN || sock_buff[0] != ISO_SAP || sock_buff[1] != ISO_SAP || sock_buff[2] != 3) return ISIS_WARNING; stream_write (circuit->rcv_stream, sock_buff + LLC_LEN, databuf.len - LLC_LEN); stream_set_getp (circuit->rcv_stream, 0); return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { dl_unitdata_req_t *dur = (dl_unitdata_req_t *)dlpi_ctl; char *dstaddr; u_short *dstsap; int buflen; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN; if (buflen > sizeof (sock_buff)) { zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " "output pdu size %d on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; } stream_set_getp (circuit->snd_stream, 0); memset (dur, 0, sizeof (*dur)); dur->dl_primitive = DL_UNITDATA_REQ; dur->dl_dest_addr_length = ETHERADDRL + 2; dur->dl_dest_addr_offset = sizeof (*dur); dstaddr = (char *)(dur + 1); if (circuit->sap_length < 0) { dstsap = (u_short *)(dstaddr + ETHERADDRL); } else { dstsap = (u_short *)dstaddr; dstaddr += circuit->sap_length; } if (level == 1) memcpy (dstaddr, ALL_L1_ISS, ETHERADDRL); else memcpy (dstaddr, ALL_L2_ISS, ETHERADDRL); /* Note: DLPI SAP values are in host byte order */ *dstsap = buflen; sock_buff[0] = ISO_SAP; sock_buff[1] = ISO_SAP; sock_buff[2] = 0x03; memcpy (sock_buff + LLC_LEN, circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); dlpisend (circuit->fd, dur, sizeof (*dur) + dur->dl_dest_addr_length, sock_buff, buflen, 0); return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_DLPI */ quagga-0.99.24.1/isisd/isis_bpf.c0000644000175000017500000002170412476520570013315 00000000000000/* * IS-IS Rout(e)ing protocol - isis_bpf.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #if ISIS_METHOD == ISIS_METHOD_BPF #include #include #include #include #include #include "log.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_circuit.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_constants.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "privs.h" extern struct zebra_privs_t isisd_privs; struct bpf_insn llcfilter[] = { BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN), /* check first byte */ BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 5), BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 1), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ISO_SAP, 0, 3), /* check second byte */ BPF_STMT (BPF_LD + BPF_B + BPF_ABS, ETHER_HDR_LEN + 2), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, 0x03, 0, 1), /* check third byte */ BPF_STMT (BPF_RET + BPF_K, (u_int) - 1), BPF_STMT (BPF_RET + BPF_K, 0) }; u_int readblen = 0; u_char *readbuff = NULL; /* * Table 9 - Architectural constants for use with ISO 8802 subnetworks * ISO 10589 - 8.4.8 */ u_char ALL_L1_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x14 }; u_char ALL_L2_ISS[6] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x15 }; u_char ALL_ISS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x05 }; u_char ALL_ESS[6] = { 0x09, 0x00, 0x2B, 0x00, 0x00, 0x04 }; static char sock_buff[8192]; static int open_bpf_dev (struct isis_circuit *circuit) { int i = 0, fd; char bpfdev[128]; struct ifreq ifr; u_int blen, immediate, seesent; struct timeval timeout; struct bpf_program bpf_prog; do { (void) snprintf (bpfdev, sizeof (bpfdev), "/dev/bpf%d", i++); fd = open (bpfdev, O_RDWR); } while (fd < 0 && errno == EBUSY); if (fd < 0) { zlog_warn ("open_bpf_dev(): failed to create bpf socket: %s", safe_strerror (errno)); return ISIS_WARNING; } zlog_debug ("Opened BPF device %s", bpfdev); memcpy (ifr.ifr_name, circuit->interface->name, sizeof (ifr.ifr_name)); if (ioctl (fd, BIOCSETIF, (caddr_t) & ifr) < 0) { zlog_warn ("open_bpf_dev(): failed to bind to interface: %s", safe_strerror (errno)); return ISIS_WARNING; } if (ioctl (fd, BIOCGBLEN, (caddr_t) & blen) < 0) { zlog_warn ("failed to get BPF buffer len"); blen = circuit->interface->mtu; } readblen = blen; if (readbuff == NULL) readbuff = malloc (blen); zlog_debug ("BPF buffer len = %u", blen); /* BPF(4): reads return immediately upon packet reception. * Otherwise, a read will block until either the kernel * buffer becomes full or a timeout occurs. */ immediate = 1; if (ioctl (fd, BIOCIMMEDIATE, (caddr_t) & immediate) < 0) { zlog_warn ("failed to set BPF dev to immediate mode"); } #ifdef BIOCSSEESENT /* * We want to see only incoming packets */ seesent = 0; if (ioctl (fd, BIOCSSEESENT, (caddr_t) & seesent) < 0) { zlog_warn ("failed to set BPF dev to incoming only mode"); } #endif /* * ...but all of them */ if (ioctl (fd, BIOCPROMISC) < 0) { zlog_warn ("failed to set BPF dev to promiscuous mode"); } /* * If the buffer length is smaller than our mtu, lets try to increase it */ if (blen < circuit->interface->mtu) { if (ioctl (fd, BIOCSBLEN, &circuit->interface->mtu) < 0) { zlog_warn ("failed to set BPF buffer len (%u to %u)", blen, circuit->interface->mtu); } } /* * Set a timeout parameter - hope this helps select() */ timeout.tv_sec = 600; timeout.tv_usec = 0; if (ioctl (fd, BIOCSRTIMEOUT, (caddr_t) & timeout) < 0) { zlog_warn ("failed to set BPF device timeout"); } /* * And set the filter */ memset (&bpf_prog, 0, sizeof (struct bpf_program)); bpf_prog.bf_len = 8; bpf_prog.bf_insns = &(llcfilter[0]); if (ioctl (fd, BIOCSETF, (caddr_t) & bpf_prog) < 0) { zlog_warn ("open_bpf_dev(): failed to install filter: %s", safe_strerror (errno)); return ISIS_WARNING; } assert (fd > 0); circuit->fd = fd; return ISIS_OK; } /* * Create the socket and set the tx/rx funcs */ int isis_sock_init (struct isis_circuit *circuit) { int retval = ISIS_OK; if (isisd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); retval = open_bpf_dev (circuit); if (retval != ISIS_OK) { zlog_warn ("%s: could not initialize the socket", __func__); goto end; } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { circuit->tx = isis_send_pdu_bcast; circuit->rx = isis_recv_pdu_bcast; } else if (circuit->circ_type == CIRCUIT_T_P2P) { circuit->tx = isis_send_pdu_p2p; circuit->rx = isis_recv_pdu_p2p; } else { zlog_warn ("isis_sock_init(): unknown circuit type"); retval = ISIS_WARNING; goto end; } end: if (isisd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); return retval; } int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread = 0, bytestoread, offset, one = 1; struct bpf_hdr *bpf_hdr; assert (circuit->fd > 0); if (ioctl (circuit->fd, FIONREAD, (caddr_t) & bytestoread) < 0) { zlog_warn ("ioctl() FIONREAD failed: %s", safe_strerror (errno)); } if (bytestoread) { bytesread = read (circuit->fd, readbuff, readblen); } if (bytesread < 0) { zlog_warn ("isis_recv_pdu_bcast(): read() failed: %s", safe_strerror (errno)); return ISIS_WARNING; } if (bytesread == 0) return ISIS_WARNING; bpf_hdr = (struct bpf_hdr *) readbuff; assert (bpf_hdr->bh_caplen == bpf_hdr->bh_datalen); offset = bpf_hdr->bh_hdrlen + LLC_LEN + ETHER_HDR_LEN; /* then we lose the BPF, LLC and ethernet headers */ stream_write (circuit->rcv_stream, readbuff + offset, bpf_hdr->bh_caplen - LLC_LEN - ETHER_HDR_LEN); stream_set_getp (circuit->rcv_stream, 0); memcpy (ssnpa, readbuff + bpf_hdr->bh_hdrlen + ETHER_ADDR_LEN, ETHER_ADDR_LEN); if (ioctl (circuit->fd, BIOCFLUSH, &one) < 0) zlog_warn ("Flushing failed: %s", safe_strerror (errno)); return ISIS_OK; } int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa) { int bytesread; bytesread = stream_read (circuit->rcv_stream, circuit->fd, circuit->interface->mtu); if (bytesread < 0) { zlog_warn ("isis_recv_pdu_p2p(): read () failed: %s", safe_strerror (errno)); return ISIS_WARNING; } return ISIS_OK; } int isis_send_pdu_bcast (struct isis_circuit *circuit, int level) { struct ether_header *eth; int written, buflen; buflen = stream_get_endp (circuit->snd_stream) + LLC_LEN + ETHER_HDR_LEN; if (buflen > sizeof (sock_buff)) { zlog_warn ("isis_send_pdu_bcast: sock_buff size %lu is less than " "output pdu size %d on circuit %s", sizeof (sock_buff), buflen, circuit->interface->name); return ISIS_WARNING; } stream_set_getp (circuit->snd_stream, 0); /* * First the eth header */ eth = (struct ether_header *) sock_buff; if (level == 1) memcpy (eth->ether_dhost, ALL_L1_ISS, ETHER_ADDR_LEN); else memcpy (eth->ether_dhost, ALL_L2_ISS, ETHER_ADDR_LEN); memcpy (eth->ether_shost, circuit->u.bc.snpa, ETHER_ADDR_LEN); eth->ether_type = htons (stream_get_endp (circuit->snd_stream) + LLC_LEN); /* * Then the LLC */ sock_buff[ETHER_HDR_LEN] = ISO_SAP; sock_buff[ETHER_HDR_LEN + 1] = ISO_SAP; sock_buff[ETHER_HDR_LEN + 2] = 0x03; /* then we copy the data */ memcpy (sock_buff + (LLC_LEN + ETHER_HDR_LEN), circuit->snd_stream->data, stream_get_endp (circuit->snd_stream)); /* now we can send this */ written = write (circuit->fd, sock_buff, buflen); return ISIS_OK; } int isis_send_pdu_p2p (struct isis_circuit *circuit, int level) { return ISIS_OK; } #endif /* ISIS_METHOD == ISIS_METHOD_BPF */ quagga-0.99.24.1/isisd/isis_main.c0000644000175000017500000001770112476520570013474 00000000000000/* * IS-IS Rout(e)ing protocol - isis_main.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "getopt.h" #include "thread.h" #include "log.h" #include #include "command.h" #include "vty.h" #include "memory.h" #include "stream.h" #include "if.h" #include "privs.h" #include "sigevent.h" #include "filter.h" #include "zclient.h" #include "isisd/dict.h" #include "include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" /* Default configuration file name */ #define ISISD_DEFAULT_CONFIG "isisd.conf" /* Default vty port */ #define ISISD_VTY_PORT 2608 /* isisd privileges */ zebra_capabilities_t _caps_p[] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t isisd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = sizeof (_caps_p) / sizeof (*_caps_p), .cap_num_i = 0 }; /* isisd options */ struct option longopts[] = { {"daemon", no_argument, NULL, 'd'}, {"config_file", required_argument, NULL, 'f'}, {"pid_file", required_argument, NULL, 'i'}, {"socket", required_argument, NULL, 'z'}, {"vty_addr", required_argument, NULL, 'A'}, {"vty_port", required_argument, NULL, 'P'}, {"user", required_argument, NULL, 'u'}, {"group", required_argument, NULL, 'g'}, {"version", no_argument, NULL, 'v'}, {"dryrun", no_argument, NULL, 'C'}, {"help", no_argument, NULL, 'h'}, {0} }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR ISISD_DEFAULT_CONFIG; char *config_file = NULL; /* isisd program name. */ char *progname; int daemon_mode = 0; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_ISISD_PID; /* for reload */ char _cwd[MAXPATHLEN]; char _progpath[MAXPATHLEN]; int _argc; char **_argv; char **_envp; /* * Prototypes. */ void reload(void); void sighup(void); void sigint(void); void sigterm(void); void sigusr1(void); /* Help information display. */ static void usage (int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\n\ Daemon which manages IS-IS routing\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } void reload () { zlog_debug ("Reload"); /* FIXME: Clean up func call here */ vty_reset (); (void) isisd_privs.change (ZPRIVS_RAISE); execve (_progpath, _argv, _envp); zlog_err ("Reload failed: cannot exec %s: %s", _progpath, safe_strerror (errno)); } static void terminate (int i) { exit (i); } /* * Signal handlers */ void sighup (void) { zlog_debug ("SIGHUP received"); reload (); return; } void sigint (void) { zlog_notice ("Terminating on signal SIGINT"); terminate (0); } void sigterm (void) { zlog_notice ("Terminating on signal SIGTERM"); terminate (0); } void sigusr1 (void) { zlog_debug ("SIGUSR1 received"); zlog_rotate (NULL); } struct quagga_signal_t isisd_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigterm, }, }; /* * Main routine of isisd. Parse arguments and handle IS-IS state machine. */ int main (int argc, char **argv, char **envp) { char *p; int opt, vty_port = ISISD_VTY_PORT; struct thread thread; char *config_file = NULL; char *vty_addr = NULL; int dryrun = 0; /* Get the programname without the preceding path. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ISIS, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); /* for reload */ _argc = argc; _argv = argv; _envp = envp; getcwd (_cwd, sizeof (_cwd)); if (*argv[0] == '.') snprintf (_progpath, sizeof (_progpath), "%s/%s", _cwd, _argv[0]); else snprintf (_progpath, sizeof (_progpath), "%s", argv[0]); /* Command line argument treatment. */ while (1) { opt = getopt_long (argc, argv, "df:i:z:hA:p:P:u:g:vC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and isisd not listening on isisd port... */ if (strcmp (optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); vty_port = (vty_port ? vty_port : ISISD_VTY_PORT); break; case 'u': isisd_privs.user = optarg; break; case 'g': isisd_privs.group = optarg; break; case 'v': printf ("ISISd version %s\n", ISISD_VERSION); printf ("Copyright (c) 2001-2002 Sampo Saaristo," " Ofer Wald and Hannes Gredler\n"); print_version ("Zebra"); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (0); break; default: usage (1); break; } } /* thread master */ master = thread_master_create (); /* random seed from time */ srand (time (NULL)); /* * initializations */ zprivs_init (&isisd_privs); signal_init (master, array_size (isisd_signals), isisd_signals); cmd_init (1); vty_init (master); memory_init (); access_list_init(); isis_init (); isis_circuit_init (); isis_spf_cmds_init (); /* create the global 'isis' instance */ isis_new (1); isis_zebra_init (); /* parse config file */ /* this is needed three times! because we have interfaces before the areas */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); /* demonize */ if (daemon_mode) daemon (0, 0); /* Process ID file creation. */ if (pid_file[0] != '\0') pid_output (pid_file); /* Make isis vty socket. */ vty_serv_sock (vty_addr, vty_port, ISIS_VTYSH_PATH); /* Print banner. */ zlog_notice ("Quagga-ISISd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Start finite state machine. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ exit (0); } quagga-0.99.24.1/isisd/isis_routemap.c0000644000175000017500000000502312476520570014376 00000000000000/* * IS-IS Rout(e)ing protocol - isis_routemap.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "log.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "routemap.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_zebra.h" extern struct isis *isis; /* * Prototypes. */ void isis_route_map_upd(const char *); void isis_route_map_event(route_map_event_t, const char *); void isis_route_map_init(void); void isis_route_map_upd (const char *name) { int i = 0; if (!isis) return; for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { if (isis->rmap[i].name) isis->rmap[i].map = route_map_lookup_by_name (isis->rmap[i].name); else isis->rmap[i].map = NULL; } /* FIXME: do the address family sub-mode AF_INET6 here ? */ } void isis_route_map_event (route_map_event_t event, const char *name) { int type; if (!isis) return; for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (isis->rmap[type].name && isis->rmap[type].map && !strcmp (isis->rmap[type].name, name)) { isis_distribute_list_update (type); } } } void isis_route_map_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (isis_route_map_upd); route_map_delete_hook (isis_route_map_upd); route_map_event_hook (isis_route_map_event); } quagga-0.99.24.1/isisd/isis_route.c0000644000175000017500000004406012476520570013704 00000000000000/* * IS-IS Rout(e)ing protocol - isis_route.c * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * based on ../ospf6d/ospf6_route.[ch] * by Yasuhiro Ohara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "log.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_zebra.h" static struct isis_nexthop * isis_nexthop_create (struct in_addr *ip, unsigned int ifindex) { struct listnode *node; struct isis_nexthop *nexthop; for (ALL_LIST_ELEMENTS_RO (isis->nexthops, node, nexthop)) { if (nexthop->ifindex != ifindex) continue; if (ip && memcmp (&nexthop->ip, ip, sizeof (struct in_addr)) != 0) continue; nexthop->lock++; return nexthop; } nexthop = XCALLOC (MTYPE_ISIS_NEXTHOP, sizeof (struct isis_nexthop)); if (!nexthop) { zlog_err ("ISIS-Rte: isis_nexthop_create: out of memory!"); } nexthop->ifindex = ifindex; memcpy (&nexthop->ip, ip, sizeof (struct in_addr)); listnode_add (isis->nexthops, nexthop); nexthop->lock++; return nexthop; } static void isis_nexthop_delete (struct isis_nexthop *nexthop) { nexthop->lock--; if (nexthop->lock == 0) { listnode_delete (isis->nexthops, nexthop); XFREE (MTYPE_ISIS_NEXTHOP, nexthop); } return; } static int nexthoplookup (struct list *nexthops, struct in_addr *ip, unsigned int ifindex) { struct listnode *node; struct isis_nexthop *nh; for (ALL_LIST_ELEMENTS_RO (nexthops, node, nh)) { if (!(memcmp (ip, &nh->ip, sizeof (struct in_addr))) && ifindex == nh->ifindex) return 1; } return 0; } #ifdef EXTREME_DEBUG static void nexthop_print (struct isis_nexthop *nh) { u_char buf[BUFSIZ]; inet_ntop (AF_INET, &nh->ip, (char *) buf, BUFSIZ); zlog_debug (" %s %u", buf, nh->ifindex); } static void nexthops_print (struct list *nhs) { struct listnode *node; struct isis_nexthop *nh; for (ALL_LIST_ELEMENTS_RO (nhs, node, nh)) nexthop_print (nh); } #endif /* EXTREME_DEBUG */ #ifdef HAVE_IPV6 static struct isis_nexthop6 * isis_nexthop6_new (struct in6_addr *ip6, unsigned int ifindex) { struct isis_nexthop6 *nexthop6; nexthop6 = XCALLOC (MTYPE_ISIS_NEXTHOP6, sizeof (struct isis_nexthop6)); if (!nexthop6) { zlog_err ("ISIS-Rte: isis_nexthop_create6: out of memory!"); } nexthop6->ifindex = ifindex; memcpy (&nexthop6->ip6, ip6, sizeof (struct in6_addr)); nexthop6->lock++; return nexthop6; } static struct isis_nexthop6 * isis_nexthop6_create (struct in6_addr *ip6, unsigned int ifindex) { struct listnode *node; struct isis_nexthop6 *nexthop6; for (ALL_LIST_ELEMENTS_RO (isis->nexthops6, node, nexthop6)) { if (nexthop6->ifindex != ifindex) continue; if (ip6 && memcmp (&nexthop6->ip6, ip6, sizeof (struct in6_addr)) != 0) continue; nexthop6->lock++; return nexthop6; } nexthop6 = isis_nexthop6_new (ip6, ifindex); return nexthop6; } static void isis_nexthop6_delete (struct isis_nexthop6 *nexthop6) { nexthop6->lock--; if (nexthop6->lock == 0) { listnode_delete (isis->nexthops6, nexthop6); XFREE (MTYPE_ISIS_NEXTHOP6, nexthop6); } return; } static int nexthop6lookup (struct list *nexthops6, struct in6_addr *ip6, unsigned int ifindex) { struct listnode *node; struct isis_nexthop6 *nh6; for (ALL_LIST_ELEMENTS_RO (nexthops6, node, nh6)) { if (!(memcmp (ip6, &nh6->ip6, sizeof (struct in6_addr))) && ifindex == nh6->ifindex) return 1; } return 0; } #ifdef EXTREME_DEBUG static void nexthop6_print (struct isis_nexthop6 *nh6) { u_char buf[BUFSIZ]; inet_ntop (AF_INET6, &nh6->ip6, (char *) buf, BUFSIZ); zlog_debug (" %s %u", buf, nh6->ifindex); } static void nexthops6_print (struct list *nhs6) { struct listnode *node; struct isis_nexthop6 *nh6; for (ALL_LIST_ELEMENTS_RO (nhs6, node, nh6)) nexthop6_print (nh6); } #endif /* EXTREME_DEBUG */ #endif /* HAVE_IPV6 */ static void adjinfo2nexthop (struct list *nexthops, struct isis_adjacency *adj) { struct isis_nexthop *nh; struct listnode *node; struct in_addr *ipv4_addr; if (adj->ipv4_addrs == NULL) return; for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr)) { if (!nexthoplookup (nexthops, ipv4_addr, adj->circuit->interface->ifindex)) { nh = isis_nexthop_create (ipv4_addr, adj->circuit->interface->ifindex); nh->router_address = adj->router_address; listnode_add (nexthops, nh); } } } #ifdef HAVE_IPV6 static void adjinfo2nexthop6 (struct list *nexthops6, struct isis_adjacency *adj) { struct listnode *node; struct in6_addr *ipv6_addr; struct isis_nexthop6 *nh6; if (!adj->ipv6_addrs) return; for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { if (!nexthop6lookup (nexthops6, ipv6_addr, adj->circuit->interface->ifindex)) { nh6 = isis_nexthop6_create (ipv6_addr, adj->circuit->interface->ifindex); nh6->router_address6 = adj->router_address6; listnode_add (nexthops6, nh6); } } } #endif /* HAVE_IPV6 */ static struct isis_route_info * isis_route_info_new (struct prefix *prefix, uint32_t cost, uint32_t depth, struct list *adjacencies) { struct isis_route_info *rinfo; struct isis_adjacency *adj; struct listnode *node; rinfo = XCALLOC (MTYPE_ISIS_ROUTE_INFO, sizeof (struct isis_route_info)); if (!rinfo) { zlog_err ("ISIS-Rte: isis_route_info_new: out of memory!"); return NULL; } if (prefix->family == AF_INET) { rinfo->nexthops = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) { /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); /* update neighbor router address */ if (depth == 2 && prefix->prefixlen == 32) adj->router_address = prefix->u.prefix4; adjinfo2nexthop (rinfo->nexthops, adj); } } #ifdef HAVE_IPV6 if (prefix->family == AF_INET6) { rinfo->nexthops6 = list_new (); for (ALL_LIST_ELEMENTS_RO (adjacencies, node, adj)) { /* check for force resync this route */ if (CHECK_FLAG (adj->circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF)) SET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); /* update neighbor router address */ if (depth == 2 && prefix->prefixlen == 128) adj->router_address6 = prefix->u.prefix6; adjinfo2nexthop6 (rinfo->nexthops6, adj); } } #endif /* HAVE_IPV6 */ rinfo->cost = cost; rinfo->depth = depth; return rinfo; } static void isis_route_info_delete (struct isis_route_info *route_info) { if (route_info->nexthops) { route_info->nexthops->del = (void (*)(void *)) isis_nexthop_delete; list_delete (route_info->nexthops); } #ifdef HAVE_IPV6 if (route_info->nexthops6) { route_info->nexthops6->del = (void (*)(void *)) isis_nexthop6_delete; list_delete (route_info->nexthops6); } #endif /* HAVE_IPV6 */ XFREE (MTYPE_ISIS_ROUTE_INFO, route_info); } static int isis_route_info_same_attrib (struct isis_route_info *new, struct isis_route_info *old) { if (new->cost != old->cost) return 0; if (new->depth != old->depth) return 0; return 1; } static int isis_route_info_same (struct isis_route_info *new, struct isis_route_info *old, u_char family) { struct listnode *node; struct isis_nexthop *nexthop; #ifdef HAVE_IPV6 struct isis_nexthop6 *nexthop6; #endif /* HAVE_IPV6 */ if (!CHECK_FLAG (old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return 0; if (CHECK_FLAG (new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) return 0; if (!isis_route_info_same_attrib (new, old)) return 0; if (family == AF_INET) { for (ALL_LIST_ELEMENTS_RO (new->nexthops, node, nexthop)) if (nexthoplookup (old->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; for (ALL_LIST_ELEMENTS_RO (old->nexthops, node, nexthop)) if (nexthoplookup (new->nexthops, &nexthop->ip, nexthop->ifindex) == 0) return 0; } #ifdef HAVE_IPV6 else if (family == AF_INET6) { for (ALL_LIST_ELEMENTS_RO (new->nexthops6, node, nexthop6)) if (nexthop6lookup (old->nexthops6, &nexthop6->ip6, nexthop6->ifindex) == 0) return 0; for (ALL_LIST_ELEMENTS_RO (old->nexthops6, node, nexthop6)) if (nexthop6lookup (new->nexthops6, &nexthop6->ip6, nexthop6->ifindex) == 0) return 0; } #endif /* HAVE_IPV6 */ return 1; } struct isis_route_info * isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, struct list *adjacencies, struct isis_area *area, int level) { struct route_node *route_node; struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL; u_char buff[BUFSIZ]; u_char family; family = prefix->family; /* for debugs */ prefix2str (prefix, (char *) buff, BUFSIZ); rinfo_new = isis_route_info_new (prefix, cost, depth, adjacencies); if (!rinfo_new) { zlog_err ("ISIS-Rte (%s): isis_route_create: out of memory!", area->area_tag); return NULL; } if (family == AF_INET) route_node = route_node_get (area->route_table[level - 1], prefix); #ifdef HAVE_IPV6 else if (family == AF_INET6) route_node = route_node_get (area->route_table6[level - 1], prefix); #endif /* HAVE_IPV6 */ else { isis_route_info_delete (rinfo_new); return NULL; } rinfo_old = route_node->info; if (!rinfo_old) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route created: %s", area->area_tag, buff); route_info = rinfo_new; UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } else { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route already exists: %s", area->area_tag, buff); if (isis_route_info_same (rinfo_new, rinfo_old, family)) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route unchanged: %s", area->area_tag, buff); isis_route_info_delete (rinfo_new); route_info = rinfo_old; } else { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte (%s) route changed: %s", area->area_tag, buff); isis_route_info_delete (rinfo_old); route_info = rinfo_new; UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } } SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE); route_node->info = route_info; return route_info; } static void isis_route_delete (struct prefix *prefix, struct route_table *table) { struct route_node *rode; struct isis_route_info *rinfo; char buff[BUFSIZ]; /* for log */ prefix2str (prefix, buff, BUFSIZ); rode = route_node_get (table, prefix); rinfo = rode->info; if (rinfo == NULL) { if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte: tried to delete non-existant route %s", buff); return; } if (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) { UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); if (isis->debugs & DEBUG_RTE_EVENTS) zlog_debug ("ISIS-Rte: route delete %s", buff); isis_zebra_route_update (prefix, rinfo); } isis_route_info_delete (rinfo); rode->info = NULL; return; } /* Validating routes in particular table. */ static void isis_route_validate_table (struct isis_area *area, struct route_table *table) { struct route_node *rnode, *drnode; struct isis_route_info *rinfo; u_char buff[BUFSIZ]; for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; rinfo = rnode->info; if (isis->debugs & DEBUG_RTE_EVENTS) { prefix2str (&rnode->p, (char *) buff, BUFSIZ); zlog_debug ("ISIS-Rte (%s): route validate: %s %s %s %s", area->area_tag, (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED) ? "synced" : "not-synced"), (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC) ? "resync" : "not-resync"), (CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE) ? "active" : "inactive"), buff); } isis_zebra_route_update (&rnode->p, rinfo); if (!CHECK_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE)) { /* Area is either L1 or L2 => we use level route tables directly for * validating => no problems with deleting routes. */ if (area->is_type != IS_LEVEL_1_AND_2) { isis_route_delete (&rnode->p, table); continue; } /* If area is L1L2, we work with merge table and therefore must * delete node from level tables as well before deleting route info. * FIXME: Is it performance problem? There has to be the better way. * Like not to deal with it here at all (see the next comment)? */ if (rnode->p.family == AF_INET) { drnode = route_node_get (area->route_table[0], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; drnode = route_node_get (area->route_table[1], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; } #ifdef HAVE_IPV6 if (rnode->p.family == AF_INET6) { drnode = route_node_get (area->route_table6[0], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; drnode = route_node_get (area->route_table6[1], &rnode->p); if (drnode->info == rnode->info) drnode->info = NULL; } #endif isis_route_delete (&rnode->p, table); } } } /* Function to validate route tables for L1L2 areas. In this case we can't use * level route tables directly, we have to merge them at first. L1 routes are * preferred over the L2 ones. * * Merge algorithm is trivial (at least for now). All L1 paths are copied into * merge table at first, then L2 paths are added if L1 path for same prefix * doesn't already exists there. * * FIXME: Is it right place to do it at all? Maybe we should push both levels * to the RIB with different zebra route types and let RIB handle this? */ static void isis_route_validate_merge (struct isis_area *area, int family) { struct route_table *table = NULL; struct route_table *merge; struct route_node *rnode, *mrnode; merge = route_table_init (); if (family == AF_INET) table = area->route_table[0]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[0]; #endif for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; mrnode = route_node_get (merge, &rnode->p); mrnode->info = rnode->info; } if (family == AF_INET) table = area->route_table[1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[1]; #endif for (rnode = route_top (table); rnode; rnode = route_next (rnode)) { if (rnode->info == NULL) continue; mrnode = route_node_get (merge, &rnode->p); if (mrnode->info != NULL) continue; mrnode->info = rnode->info; } isis_route_validate_table (area, merge); route_table_finish (merge); } /* Walk through route tables and propagate necessary changes into RIB. In case * of L1L2 area, level tables have to be merged at first. */ void isis_route_validate (struct isis_area *area) { struct listnode *node; struct isis_circuit *circuit; if (area->is_type == IS_LEVEL_1) isis_route_validate_table (area, area->route_table[0]); else if (area->is_type == IS_LEVEL_2) isis_route_validate_table (area, area->route_table[1]); else isis_route_validate_merge (area, AF_INET); #ifdef HAVE_IPV6 if (area->is_type == IS_LEVEL_1) isis_route_validate_table (area, area->route_table6[0]); else if (area->is_type == IS_LEVEL_2) isis_route_validate_table (area, area->route_table6[1]); else isis_route_validate_merge (area, AF_INET6); #endif /* walk all circuits and reset any spf specific flags */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); return; } void isis_route_invalidate_table (struct isis_area *area, struct route_table *table) { struct route_node *rode; struct isis_route_info *rinfo; for (rode = route_top (table); rode; rode = route_next (rode)) { if (rode->info == NULL) continue; rinfo = rode->info; UNSET_FLAG (rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE); } } void isis_route_invalidate (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) isis_route_invalidate_table (area, area->route_table[0]); if (area->is_type & IS_LEVEL_2) isis_route_invalidate_table (area, area->route_table[1]); } quagga-0.99.24.1/isisd/isis_spf.c0000644000175000017500000013314212476520570013336 00000000000000/* * IS-IS Rout(e)ing protocol - isis_spf.c * The SPT algorithm * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "log.h" #include "command.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "if.h" #include "table.h" #include "isis_constants.h" #include "isis_common.h" #include "isis_flags.h" #include "dict.h" #include "isisd.h" #include "isis_misc.h" #include "isis_adjacency.h" #include "isis_circuit.h" #include "isis_tlv.h" #include "isis_pdu.h" #include "isis_lsp.h" #include "isis_dynhn.h" #include "isis_spf.h" #include "isis_route.h" #include "isis_csm.h" int isis_run_spf_l1 (struct thread *thread); int isis_run_spf_l2 (struct thread *thread); /* 7.2.7 */ static void remove_excess_adjs (struct list *adjs) { struct listnode *node, *excess = NULL; struct isis_adjacency *adj, *candidate = NULL; int comp; for (ALL_LIST_ELEMENTS_RO (adjs, node, adj)) { if (excess == NULL) excess = node; candidate = listgetdata (excess); if (candidate->sys_type < adj->sys_type) { excess = node; candidate = adj; continue; } if (candidate->sys_type > adj->sys_type) continue; comp = memcmp (candidate->sysid, adj->sysid, ISIS_SYS_ID_LEN); if (comp > 0) { excess = node; candidate = adj; continue; } if (comp < 0) continue; if (candidate->circuit->circuit_id > adj->circuit->circuit_id) { excess = node; candidate = adj; continue; } if (candidate->circuit->circuit_id < adj->circuit->circuit_id) continue; comp = memcmp (candidate->snpa, adj->snpa, ETH_ALEN); if (comp > 0) { excess = node; candidate = adj; continue; } } list_delete_node (adjs, excess); return; } static const char * vtype2string (enum vertextype vtype) { switch (vtype) { case VTYPE_PSEUDO_IS: return "pseudo_IS"; break; case VTYPE_PSEUDO_TE_IS: return "pseudo_TE-IS"; break; case VTYPE_NONPSEUDO_IS: return "IS"; break; case VTYPE_NONPSEUDO_TE_IS: return "TE-IS"; break; case VTYPE_ES: return "ES"; break; case VTYPE_IPREACH_INTERNAL: return "IP internal"; break; case VTYPE_IPREACH_EXTERNAL: return "IP external"; break; case VTYPE_IPREACH_TE: return "IP TE"; break; #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: return "IP6 internal"; break; case VTYPE_IP6REACH_EXTERNAL: return "IP6 external"; break; #endif /* HAVE_IPV6 */ default: return "UNKNOWN"; } return NULL; /* Not reached */ } static const char * vid2string (struct isis_vertex *vertex, u_char * buff) { switch (vertex->type) { case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: return print_sys_hostname (vertex->N.id); break; case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: case VTYPE_ES: return print_sys_hostname (vertex->N.id); break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ prefix2str ((struct prefix *) &vertex->N.prefix, (char *) buff, BUFSIZ); break; default: return "UNKNOWN"; } return (char *) buff; } static struct isis_vertex * isis_vertex_new (void *id, enum vertextype vtype) { struct isis_vertex *vertex; vertex = XCALLOC (MTYPE_ISIS_VERTEX, sizeof (struct isis_vertex)); if (vertex == NULL) { zlog_err ("isis_vertex_new Out of memory!"); return NULL; } vertex->type = vtype; switch (vtype) { case VTYPE_ES: case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN); break; case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: memcpy (vertex->N.id, (u_char *) id, ISIS_SYS_ID_LEN + 1); break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ memcpy (&vertex->N.prefix, (struct prefix *) id, sizeof (struct prefix)); break; default: zlog_err ("WTF!"); } vertex->Adj_N = list_new (); vertex->parents = list_new (); vertex->children = list_new (); return vertex; } static void isis_vertex_del (struct isis_vertex *vertex) { list_delete (vertex->Adj_N); vertex->Adj_N = NULL; list_delete (vertex->parents); vertex->parents = NULL; list_delete (vertex->children); vertex->children = NULL; memset(vertex, 0, sizeof(struct isis_vertex)); XFREE (MTYPE_ISIS_VERTEX, vertex); return; } static void isis_vertex_adj_del (struct isis_vertex *vertex, struct isis_adjacency *adj) { struct listnode *node, *nextnode; if (!vertex) return; for (node = listhead (vertex->Adj_N); node; node = nextnode) { nextnode = listnextnode(node); if (listgetdata(node) == adj) list_delete_node(vertex->Adj_N, node); } return; } struct isis_spftree * isis_spftree_new (struct isis_area *area) { struct isis_spftree *tree; tree = XCALLOC (MTYPE_ISIS_SPFTREE, sizeof (struct isis_spftree)); if (tree == NULL) { zlog_err ("ISIS-Spf: isis_spftree_new Out of memory!"); return NULL; } tree->tents = list_new (); tree->paths = list_new (); tree->area = area; tree->last_run_timestamp = 0; tree->last_run_duration = 0; tree->runcount = 0; tree->pending = 0; return tree; } void isis_spftree_del (struct isis_spftree *spftree) { THREAD_TIMER_OFF (spftree->t_spf); spftree->tents->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->tents); spftree->tents = NULL; spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete (spftree->paths); spftree->paths = NULL; XFREE (MTYPE_ISIS_SPFTREE, spftree); return; } void isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj) { struct listnode *node; if (!adj) return; for (node = listhead (spftree->tents); node; node = listnextnode (node)) isis_vertex_adj_del (listgetdata (node), adj); for (node = listhead (spftree->paths); node; node = listnextnode (node)) isis_vertex_adj_del (listgetdata (node), adj); return; } void spftree_area_init (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] == NULL) area->spftree[0] = isis_spftree_new (area); #ifdef HAVE_IPV6 if (area->spftree6[0] == NULL) area->spftree6[0] = isis_spftree_new (area); #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] == NULL) area->spftree[1] = isis_spftree_new (area); #ifdef HAVE_IPV6 if (area->spftree6[1] == NULL) area->spftree6[1] = isis_spftree_new (area); #endif } return; } void spftree_area_del (struct isis_area *area) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] != NULL) { isis_spftree_del (area->spftree[0]); area->spftree[0] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[0]) { isis_spftree_del (area->spftree6[0]); area->spftree6[0] = NULL; } #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] != NULL) { isis_spftree_del (area->spftree[1]); area->spftree[1] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[1] != NULL) { isis_spftree_del (area->spftree6[1]); area->spftree6[1] = NULL; } #endif } return; } void spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj) { if (area->is_type & IS_LEVEL_1) { if (area->spftree[0] != NULL) isis_spftree_adj_del (area->spftree[0], adj); #ifdef HAVE_IPV6 if (area->spftree6[0] != NULL) isis_spftree_adj_del (area->spftree6[0], adj); #endif } if (area->is_type & IS_LEVEL_2) { if (area->spftree[1] != NULL) isis_spftree_adj_del (area->spftree[1], adj); #ifdef HAVE_IPV6 if (area->spftree6[1] != NULL) isis_spftree_adj_del (area->spftree6[1], adj); #endif } return; } /* * Find the system LSP: returns the LSP in our LSP database * associated with the given system ID. */ static struct isis_lsp * isis_root_system_lsp (struct isis_area *area, int level, u_char *sysid) { struct isis_lsp *lsp; u_char lspid[ISIS_SYS_ID_LEN + 2]; memcpy (lspid, sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lspid) = 0; LSP_FRAGMENT (lspid) = 0; lsp = lsp_search (lspid, area->lspdb[level - 1]); if (lsp && lsp->lsp_header->rem_lifetime != 0) return lsp; return NULL; } /* * Add this IS to the root of SPT */ static struct isis_vertex * isis_spf_add_root (struct isis_spftree *spftree, int level, u_char *sysid) { struct isis_vertex *vertex; struct isis_lsp *lsp; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif /* EXTREME_DEBUG */ lsp = isis_root_system_lsp (spftree->area, level, sysid); if (lsp == NULL) zlog_warn ("ISIS-Spf: could not find own l%d LSP!", level); if (!spftree->area->oldmetric) vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_TE_IS); else vertex = isis_vertex_new (sysid, VTYPE_NONPSEUDO_IS); listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: added this IS %s %s depth %d dist %d to PATHS", vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ return vertex; } static struct isis_vertex * isis_find_vertex (struct list *list, void *id, enum vertextype vtype) { struct listnode *node; struct isis_vertex *vertex; struct prefix *p1, *p2; for (ALL_LIST_ELEMENTS_RO (list, node, vertex)) { if (vertex->type != vtype) continue; switch (vtype) { case VTYPE_ES: case VTYPE_NONPSEUDO_IS: case VTYPE_NONPSEUDO_TE_IS: if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN) == 0) return vertex; break; case VTYPE_PSEUDO_IS: case VTYPE_PSEUDO_TE_IS: if (memcmp ((u_char *) id, vertex->N.id, ISIS_SYS_ID_LEN + 1) == 0) return vertex; break; case VTYPE_IPREACH_INTERNAL: case VTYPE_IPREACH_EXTERNAL: case VTYPE_IPREACH_TE: #ifdef HAVE_IPV6 case VTYPE_IP6REACH_INTERNAL: case VTYPE_IP6REACH_EXTERNAL: #endif /* HAVE_IPV6 */ p1 = (struct prefix *) id; p2 = (struct prefix *) &vertex->N.id; if (p1->family == p2->family && p1->prefixlen == p2->prefixlen && memcmp (&p1->u.prefix, &p2->u.prefix, PSIZE (p1->prefixlen)) == 0) return vertex; break; } } return NULL; } /* * Add a vertex to TENT sorted by cost and by vertextype on tie break situation */ static struct isis_vertex * isis_spf_add2tent (struct isis_spftree *spftree, enum vertextype vtype, void *id, uint32_t cost, int depth, int family, struct isis_adjacency *adj, struct isis_vertex *parent) { struct isis_vertex *vertex, *v; struct listnode *node; struct isis_adjacency *parent_adj; #ifdef EXTREME_DEBUG u_char buff[BUFSIZ]; #endif assert (isis_find_vertex (spftree->paths, id, vtype) == NULL); assert (isis_find_vertex (spftree->tents, id, vtype) == NULL); vertex = isis_vertex_new (id, vtype); vertex->d_N = cost; vertex->depth = depth; if (parent) { listnode_add (vertex->parents, parent); if (listnode_lookup (parent->children, vertex) == NULL) listnode_add (parent->children, vertex); } if (parent && parent->Adj_N && listcount(parent->Adj_N) > 0) { for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) listnode_add (vertex->Adj_N, parent_adj); } else if (adj) { listnode_add (vertex->Adj_N, adj); } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: add to TENT %s %s %s depth %d dist %d adjcount %d", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N, listcount(vertex->Adj_N)); #endif /* EXTREME_DEBUG */ if (list_isempty (spftree->tents)) { listnode_add (spftree->tents, vertex); return vertex; } /* XXX: This cant use the standard ALL_LIST_ELEMENTS macro */ for (node = listhead (spftree->tents); node; node = listnextnode (node)) { v = listgetdata (node); if (v->d_N > vertex->d_N) { list_add_node_prev (spftree->tents, node, vertex); break; } else if (v->d_N == vertex->d_N && v->type > vertex->type) { /* Tie break, add according to type */ list_add_node_prev (spftree->tents, node, vertex); break; } } if (node == NULL) listnode_add (spftree->tents, vertex); return vertex; } static void isis_spf_add_local (struct isis_spftree *spftree, enum vertextype vtype, void *id, struct isis_adjacency *adj, uint32_t cost, int family, struct isis_vertex *parent) { struct isis_vertex *vertex; vertex = isis_find_vertex (spftree->tents, id, vtype); if (vertex) { /* C.2.5 c) */ if (vertex->d_N == cost) { if (adj) listnode_add (vertex->Adj_N, adj); /* d) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); if (parent && (listnode_lookup (vertex->parents, parent) == NULL)) listnode_add (vertex->parents, parent); if (parent && (listnode_lookup (parent->children, vertex) == NULL)) listnode_add (parent->children, vertex); return; } else if (vertex->d_N < cost) { /* e) do nothing */ return; } else { /* vertex->d_N > cost */ /* f) */ struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; listnode_delete (spftree->tents, vertex); assert (listcount (vertex->children) == 0); for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) listnode_delete(pvertex->children, vertex); isis_vertex_del (vertex); } } isis_spf_add2tent (spftree, vtype, id, cost, 1, family, adj, parent); return; } static void process_N (struct isis_spftree *spftree, enum vertextype vtype, void *id, uint32_t dist, uint16_t depth, int family, struct isis_vertex *parent) { struct isis_vertex *vertex; #ifdef EXTREME_DEBUG u_char buff[255]; #endif assert (spftree && parent); /* RFC3787 section 5.1 */ if (spftree->area->newmetric == 1) { if (dist > MAX_WIDE_PATH_METRIC) return; } /* C.2.6 b) */ else if (spftree->area->oldmetric == 1) { if (dist > MAX_NARROW_PATH_METRIC) return; } /* c) */ vertex = isis_find_vertex (spftree->paths, id, vtype); if (vertex) { #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d already found from PATH", print_sys_hostname (vertex->N.id), vtype2string (vtype), vid2string (vertex, buff), dist); #endif /* EXTREME_DEBUG */ assert (dist >= vertex->d_N); return; } vertex = isis_find_vertex (spftree->tents, id, vtype); /* d) */ if (vertex) { /* 1) */ #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N %s %s %s dist %d parent %s adjcount %d", print_sys_hostname (vertex->N.id), vtype2string (vtype), vid2string (vertex, buff), dist, (parent ? print_sys_hostname (parent->N.id) : "null"), (parent ? listcount (parent->Adj_N) : 0)); #endif /* EXTREME_DEBUG */ if (vertex->d_N == dist) { struct listnode *node; struct isis_adjacency *parent_adj; for (ALL_LIST_ELEMENTS_RO (parent->Adj_N, node, parent_adj)) if (listnode_lookup(vertex->Adj_N, parent_adj) == NULL) listnode_add (vertex->Adj_N, parent_adj); /* 2) */ if (listcount (vertex->Adj_N) > ISIS_MAX_PATH_SPLITS) remove_excess_adjs (vertex->Adj_N); if (listnode_lookup (vertex->parents, parent) == NULL) listnode_add (vertex->parents, parent); if (listnode_lookup (parent->children, vertex) == NULL) listnode_add (parent->children, vertex); /* 3) */ return; } else if (vertex->d_N < dist) { return; /* 4) */ } else { struct listnode *pnode, *pnextnode; struct isis_vertex *pvertex; listnode_delete (spftree->tents, vertex); assert (listcount (vertex->children) == 0); for (ALL_LIST_ELEMENTS (vertex->parents, pnode, pnextnode, pvertex)) listnode_delete(pvertex->children, vertex); isis_vertex_del (vertex); } } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_N add2tent %s %s dist %d parent %s", print_sys_hostname(id), vtype2string (vtype), dist, (parent ? print_sys_hostname (parent->N.id) : "null")); #endif /* EXTREME_DEBUG */ isis_spf_add2tent (spftree, vtype, id, dist, depth, family, NULL, parent); return; } /* * C.2.6 Step 1 */ static int isis_spf_process_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family, u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; uint32_t dist; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipv4_reach; enum vertextype vtype; struct prefix prefix; #ifdef HAVE_IPV6 struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ static const u_char null_sysid[ISIS_SYS_ID_LEN]; if (!speaks (lsp->tlv_data.nlpids, family)) return ISIS_OK; lspfragloop: if (lsp->lsp_header->seq_num == 0) { zlog_warn ("isis_spf_process_lsp(): lsp with 0 seq_num - ignore"); return ISIS_WARNING; } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); #endif /* EXTREME_DEBUG */ if (!ISIS_MASK_LSP_OL_BIT (lsp->lsp_header->lsp_bits)) { if (lsp->tlv_data.is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { /* C.2.6 a) */ /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!memcmp (is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, depth + 1, family, parent); } } if (lsp->tlv_data.te_is_neighs) { for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; if (!memcmp (te_is_neigh->neigh_id, null_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + GET_TE_METRIC(te_is_neigh); vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, depth + 1, family, parent); } } } if (family == AF_INET && lsp->tlv_data.ipv4_int_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_INTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } if (family == AF_INET && lsp->tlv_data.ipv4_ext_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, node, ipreach)) { dist = cost + ipreach->metrics.metric_default; vtype = VTYPE_IPREACH_EXTERNAL; prefix.u.prefix4 = ipreach->prefix; prefix.prefixlen = ip_masklen (ipreach->mask); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } if (family == AF_INET && lsp->tlv_data.te_ipv4_reachs) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, node, te_ipv4_reach)) { assert ((te_ipv4_reach->control & 0x3F) <= IPV4_MAX_BITLEN); dist = cost + ntohl (te_ipv4_reach->te_metric); vtype = VTYPE_IPREACH_TE; prefix.u.prefix4 = newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control); prefix.prefixlen = (te_ipv4_reach->control & 0x3F); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } #ifdef HAVE_IPV6 if (family == AF_INET6 && lsp->tlv_data.ipv6_reachs) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, node, ip6reach)) { assert (ip6reach->prefix_len <= IPV6_MAX_BITLEN); dist = cost + ntohl(ip6reach->metric); vtype = (ip6reach->control_info & CTRL_INFO_DISTRIBUTION) ? VTYPE_IP6REACH_EXTERNAL : VTYPE_IP6REACH_INTERNAL; prefix.prefixlen = ip6reach->prefix_len; memcpy (&prefix.u.prefix6.s6_addr, ip6reach->prefix, PSIZE (ip6reach->prefix_len)); apply_mask (&prefix); process_N (spftree, vtype, (void *) &prefix, dist, depth + 1, family, parent); } } #endif /* HAVE_IPV6 */ if (fragnode == NULL) fragnode = listhead (lsp->lspu.frags); else fragnode = listnextnode (fragnode); if (fragnode) { lsp = listgetdata (fragnode); goto lspfragloop; } return ISIS_OK; } static int isis_spf_process_pseudo_lsp (struct isis_spftree *spftree, struct isis_lsp *lsp, uint32_t cost, uint16_t depth, int family, u_char *root_sysid, struct isis_vertex *parent) { struct listnode *node, *fragnode = NULL; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; enum vertextype vtype; uint32_t dist; pseudofragloop: if (lsp->lsp_header->seq_num == 0) { zlog_warn ("isis_spf_process_pseudo_lsp(): lsp with 0 seq_num" " - do not process"); return ISIS_WARNING; } #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: process_pseudo_lsp %s", print_sys_hostname(lsp->lsp_header->lsp_id)); #endif /* EXTREME_DEBUG */ /* RFC3787 section 4 SHOULD ignore overload bit in pseudo LSPs */ if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, node, is_neigh)) { /* Two way connectivity */ if (!memcmp (is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + is_neigh->metrics.metric_default; vtype = LSP_PSEUDO_ID (is_neigh->neigh_id) ? VTYPE_PSEUDO_IS : VTYPE_NONPSEUDO_IS; process_N (spftree, vtype, (void *) is_neigh->neigh_id, dist, depth + 1, family, parent); } if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, node, te_is_neigh)) { /* Two way connectivity */ if (!memcmp (te_is_neigh->neigh_id, root_sysid, ISIS_SYS_ID_LEN)) continue; dist = cost + GET_TE_METRIC(te_is_neigh); vtype = LSP_PSEUDO_ID (te_is_neigh->neigh_id) ? VTYPE_PSEUDO_TE_IS : VTYPE_NONPSEUDO_TE_IS; process_N (spftree, vtype, (void *) te_is_neigh->neigh_id, dist, depth + 1, family, parent); } if (fragnode == NULL) fragnode = listhead (lsp->lspu.frags); else fragnode = listnextnode (fragnode); if (fragnode) { lsp = listgetdata (fragnode); goto pseudofragloop; } return ISIS_OK; } static int isis_spf_preload_tent (struct isis_spftree *spftree, int level, int family, u_char *root_sysid, struct isis_vertex *parent) { struct isis_circuit *circuit; struct listnode *cnode, *anode, *ipnode; struct isis_adjacency *adj; struct isis_lsp *lsp; struct list *adj_list; struct list *adjdb; struct prefix_ipv4 *ipv4; struct prefix prefix; int retval = ISIS_OK; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; static u_char null_lsp_id[ISIS_SYS_ID_LEN + 2]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ for (ALL_LIST_ELEMENTS_RO (spftree->area->circuit_list, cnode, circuit)) { if (circuit->state != C_STATE_UP) continue; if (!(circuit->is_type & level)) continue; if (family == AF_INET && !circuit->ip_router) continue; #ifdef HAVE_IPV6 if (family == AF_INET6 && !circuit->ipv6_router) continue; #endif /* HAVE_IPV6 */ /* * Add IP(v6) addresses of this circuit */ if (family == AF_INET) { prefix.family = AF_INET; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { prefix.u.prefix4 = ipv4->prefix; prefix.prefixlen = ipv4->prefixlen; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IPREACH_INTERNAL, &prefix, NULL, 0, family, parent); } } #ifdef HAVE_IPV6 if (family == AF_INET6) { prefix.family = AF_INET6; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) { prefix.prefixlen = ipv6->prefixlen; prefix.u.prefix6 = ipv6->prefix; apply_mask (&prefix); isis_spf_add_local (spftree, VTYPE_IP6REACH_INTERNAL, &prefix, NULL, 0, family, parent); } } #endif /* HAVE_IPV6 */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* * Add the adjacencies */ adj_list = list_new (); adjdb = circuit->u.bc.adjdb[level - 1]; isis_adj_build_up_list (adjdb, adj_list); if (listcount (adj_list) == 0) { list_delete (adj_list); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no L%d adjacencies on circuit %s", level, circuit->interface->name); continue; } for (ALL_LIST_ELEMENTS_RO (adj_list, anode, adj)) { if (!speaks (&adj->nlpids, family)) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: isis_spf_add_local (spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); memcpy (lsp_id, adj->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = 0; LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) zlog_warn ("ISIS-Spf: No LSP %s found for IS adjacency " "L%d on %s (ID %u)", rawlspid_print (lsp_id), level, circuit->interface->name, circuit->circuit_id); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknow adj type"); } } list_delete (adj_list); /* * Add the pseudonode */ if (level == 1) memcpy (lsp_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (lsp_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); /* can happen during DR reboot */ if (memcmp (lsp_id, null_lsp_id, ISIS_SYS_ID_LEN + 1) == 0) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: No L%d DR on %s (ID %d)", level, circuit->interface->name, circuit->circuit_id); continue; } adj = isis_adj_lookup (lsp_id, adjdb); /* if no adj, we are the dis or error */ if (!adj && !circuit->u.bc.is_dr[level - 1]) { zlog_warn ("ISIS-Spf: No adjacency found from root " "to L%d DR %s on %s (ID %d)", level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } lsp = lsp_search (lsp_id, spftree->area->lspdb[level - 1]); if (lsp == NULL || lsp->lsp_header->rem_lifetime == 0) { zlog_warn ("ISIS-Spf: No lsp (%p) found from root " "to L%d DR %s on %s (ID %d)", lsp, level, rawlspid_print (lsp_id), circuit->interface->name, circuit->circuit_id); continue; } isis_spf_process_pseudo_lsp (spftree, lsp, circuit->te_metric[level - 1], 0, family, root_sysid, parent); } else if (circuit->circ_type == CIRCUIT_T_P2P) { adj = circuit->u.p2p.neighbor; if (!adj) continue; switch (adj->sys_type) { case ISIS_SYSTYPE_ES: isis_spf_add_local (spftree, VTYPE_ES, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_IS: case ISIS_SYSTYPE_L1_IS: case ISIS_SYSTYPE_L2_IS: if (speaks (&adj->nlpids, family)) isis_spf_add_local (spftree, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS, adj->sysid, adj, circuit->te_metric[level - 1], family, parent); break; case ISIS_SYSTYPE_UNKNOWN: default: zlog_warn ("isis_spf_preload_tent unknown adj type"); break; } } else if (circuit->circ_type == CIRCUIT_T_LOOPBACK) { continue; } else { zlog_warn ("isis_spf_preload_tent unsupported media"); retval = ISIS_WARNING; } } return retval; } /* * The parent(s) for vertex is set when added to TENT list * now we just put the child pointer(s) in place */ static void add_to_paths (struct isis_spftree *spftree, struct isis_vertex *vertex, int level) { u_char buff[BUFSIZ]; if (isis_find_vertex (spftree->paths, vertex->N.id, vertex->type)) return; listnode_add (spftree->paths, vertex); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: added %s %s %s depth %d dist %d to PATHS", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vid2string (vertex, buff), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ if (vertex->type > VTYPE_ES) { if (listcount (vertex->Adj_N) > 0) isis_route_create ((struct prefix *) &vertex->N.prefix, vertex->d_N, vertex->depth, vertex->Adj_N, spftree->area, level); else if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf: no adjacencies do not install route for " "%s depth %d dist %d", vid2string (vertex, buff), vertex->depth, vertex->d_N); } return; } static void init_spt (struct isis_spftree *spftree) { spftree->tents->del = spftree->paths->del = (void (*)(void *)) isis_vertex_del; list_delete_all_node (spftree->tents); list_delete_all_node (spftree->paths); spftree->tents->del = spftree->paths->del = NULL; return; } static int isis_run_spf (struct isis_area *area, int level, int family, u_char *sysid) { int retval = ISIS_OK; struct listnode *node; struct isis_vertex *vertex; struct isis_vertex *root_vertex; struct isis_spftree *spftree = NULL; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; struct route_table *table = NULL; struct timeval time_now; unsigned long long start_time, end_time; /* Get time that can't roll backwards. */ quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); start_time = time_now.tv_sec; start_time = (start_time * 1000000) + time_now.tv_usec; if (family == AF_INET) spftree = area->spftree[level - 1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) spftree = area->spftree6[level - 1]; #endif assert (spftree); assert (sysid); /* Make all routes in current route table inactive. */ if (family == AF_INET) table = area->route_table[level - 1]; #ifdef HAVE_IPV6 else if (family == AF_INET6) table = area->route_table6[level - 1]; #endif isis_route_invalidate_table (area, table); /* * C.2.5 Step 0 */ init_spt (spftree); /* a) */ root_vertex = isis_spf_add_root (spftree, level, sysid); /* b) */ retval = isis_spf_preload_tent (spftree, level, family, sysid, root_vertex); if (retval != ISIS_OK) { zlog_warn ("ISIS-Spf: failed to load TENT SPF-root:%s", print_sys_hostname(sysid)); goto out; } /* * C.2.7 Step 2 */ if (listcount (spftree->tents) == 0) { zlog_warn ("ISIS-Spf: TENT is empty SPF-root:%s", print_sys_hostname(sysid)); goto out; } while (listcount (spftree->tents) > 0) { node = listhead (spftree->tents); vertex = listgetdata (node); #ifdef EXTREME_DEBUG zlog_debug ("ISIS-Spf: get TENT node %s %s depth %d dist %d to PATHS", print_sys_hostname (vertex->N.id), vtype2string (vertex->type), vertex->depth, vertex->d_N); #endif /* EXTREME_DEBUG */ /* Remove from tent list and add to paths list */ list_delete_node (spftree->tents, node); add_to_paths (spftree, vertex, level); switch (vertex->type) { case VTYPE_PSEUDO_IS: case VTYPE_NONPSEUDO_IS: case VTYPE_PSEUDO_TE_IS: case VTYPE_NONPSEUDO_TE_IS: memcpy (lsp_id, vertex->N.id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, area->lspdb[level - 1]); if (lsp && lsp->lsp_header->rem_lifetime != 0) { if (LSP_PSEUDO_ID (lsp_id)) { isis_spf_process_pseudo_lsp (spftree, lsp, vertex->d_N, vertex->depth, family, sysid, vertex); } else { isis_spf_process_lsp (spftree, lsp, vertex->d_N, vertex->depth, family, sysid, vertex); } } else { zlog_warn ("ISIS-Spf: No LSP found for %s", rawlspid_print (lsp_id)); } break; default:; } } out: isis_route_validate (area); spftree->pending = 0; spftree->runcount++; spftree->last_run_timestamp = time (NULL); quagga_gettime(QUAGGA_CLK_MONOTONIC, &time_now); end_time = time_now.tv_sec; end_time = (end_time * 1000000) + time_now.tv_usec; spftree->last_run_duration = end_time - start_time; return retval; } int isis_run_spf_l1 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree[0]->t_spf = NULL; area->spftree[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) retval = isis_run_spf (area, 1, AF_INET, isis->sysid); return retval; } int isis_run_spf_l2 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree[1]->t_spf = NULL; area->spftree[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF", area->area_tag); if (area->ip_circuits) retval = isis_run_spf (area, 2, AF_INET, isis->sysid); return retval; } int isis_spf_schedule (struct isis_area *area, int level) { struct isis_spftree *spftree = area->spftree[level - 1]; time_t now = time (NULL); int diff = now - spftree->last_run_timestamp; assert (diff >= 0); assert (area->is_type & level); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", area->area_tag, level, diff); if (spftree->pending) return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); /* wait configured min_spf_interval before doing the SPF */ if (diff >= area->min_spf_interval[level-1]) return isis_run_spf (area, level, AF_INET, isis->sysid); if (level == 1) THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l1, area, area->min_spf_interval[0] - diff); else THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf_l2, area, area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", area->area_tag, level, area->min_spf_interval[level-1] - diff); spftree->pending = 1; return ISIS_OK; } #ifdef HAVE_IPV6 static int isis_run_spf6_l1 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree6[0]->t_spf = NULL; area->spftree6[0]->pending = 0; if (!(area->is_type & IS_LEVEL_1)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L1 SPF needed, periodic SPF", area->area_tag); if (area->ipv6_circuits) retval = isis_run_spf (area, 1, AF_INET6, isis->sysid); return retval; } static int isis_run_spf6_l2 (struct thread *thread) { struct isis_area *area; int retval = ISIS_OK; area = THREAD_ARG (thread); assert (area); area->spftree6[1]->t_spf = NULL; area->spftree6[1]->pending = 0; if (!(area->is_type & IS_LEVEL_2)) { if (isis->debugs & DEBUG_SPF_EVENTS) zlog_warn ("ISIS-SPF (%s) area does not share level", area->area_tag); return ISIS_WARNING; } if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L2 SPF needed, periodic SPF.", area->area_tag); if (area->ipv6_circuits) retval = isis_run_spf (area, 2, AF_INET6, isis->sysid); return retval; } int isis_spf_schedule6 (struct isis_area *area, int level) { int retval = ISIS_OK; struct isis_spftree *spftree = area->spftree6[level - 1]; time_t now = time (NULL); time_t diff = now - spftree->last_run_timestamp; assert (diff >= 0); assert (area->is_type & level); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF schedule called, lastrun %d sec ago", area->area_tag, level, diff); if (spftree->pending) return ISIS_OK; THREAD_TIMER_OFF (spftree->t_spf); /* wait configured min_spf_interval before doing the SPF */ if (diff >= area->min_spf_interval[level-1]) return isis_run_spf (area, level, AF_INET6, isis->sysid); if (level == 1) THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l1, area, area->min_spf_interval[0] - diff); else THREAD_TIMER_ON (master, spftree->t_spf, isis_run_spf6_l2, area, area->min_spf_interval[1] - diff); if (isis->debugs & DEBUG_SPF_EVENTS) zlog_debug ("ISIS-Spf (%s) L%d SPF scheduled %d sec from now", area->area_tag, level, area->min_spf_interval[level-1] - diff); spftree->pending = 1; return retval; } #endif static void isis_print_paths (struct vty *vty, struct list *paths, u_char *root_sysid) { struct listnode *node; struct listnode *anode; struct isis_vertex *vertex; struct isis_adjacency *adj; u_char buff[BUFSIZ]; vty_out (vty, "Vertex Type Metric " "Next-Hop Interface Parent%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (paths, node, vertex)) { if (memcmp (vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { vty_out (vty, "%-20s %-12s %-6s", print_sys_hostname (root_sysid), "", ""); vty_out (vty, "%-30s", ""); } else { int rows = 0; vty_out (vty, "%-20s %-12s %-6u ", vid2string (vertex, buff), vtype2string (vertex->type), vertex->d_N); for (ALL_LIST_ELEMENTS_RO (vertex->Adj_N, anode, adj)) { if (adj) { if (rows) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-20s %-12s %-6s ", "", "", ""); } vty_out (vty, "%-20s %-9s ", print_sys_hostname (adj->sysid), adj->circuit->interface->name); ++rows; } } if (rows == 0) vty_out (vty, "%-30s ", ""); } /* Print list of parents for the ECMP DAG */ if (listcount (vertex->parents) > 0) { struct listnode *pnode; struct isis_vertex *pvertex; int rows = 0; for (ALL_LIST_ELEMENTS_RO (vertex->parents, pnode, pvertex)) { if (rows) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-72s", ""); } vty_out (vty, "%s(%d)", vid2string (pvertex, buff), pvertex->type); ++rows; } } else { vty_out (vty, " NULL "); } #if 0 if (listcount (vertex->children) > 0) { struct listnode *cnode; struct isis_vertex *cvertex; for (ALL_LIST_ELEMENTS_RO (vertex->children, cnode, cvertex)) { vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%-72s", ""); vty_out (vty, "%s(%d) ", vid2string (cvertex, buff), cvertex->type); } } #endif vty_out (vty, "%s", VTY_NEWLINE); } } DEFUN (show_isis_topology, show_isis_topology_cmd, "show isis topology", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n") { struct listnode *node; struct isis_area *area; int level; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); for (level = 0; level < ISIS_LEVELS; level++) { if (area->ip_circuits > 0 && area->spftree[level] && area->spftree[level]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IP%s", level + 1, VTY_NEWLINE); isis_print_paths (vty, area->spftree[level]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[level] && area->spftree6[level]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-%d routers that speak IPv6%s", level + 1, VTY_NEWLINE); isis_print_paths (vty, area->spftree6[level]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_isis_topology_l1, show_isis_topology_l1_cmd, "show isis topology level-1", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-1 routers in the area\n") { struct listnode *node; struct isis_area *area; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (area->ip_circuits > 0 && area->spftree[0] && area->spftree[0]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-1 routers that speak IP%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree[0]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[0] && area->spftree6[0]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-1 routers that speak IPv6%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree6[0]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_isis_topology_l2, show_isis_topology_l2_cmd, "show isis topology level-2", SHOW_STR "IS-IS information\n" "IS-IS paths to Intermediate Systems\n" "Paths to all level-2 routers in the domain\n") { struct listnode *node; struct isis_area *area; if (!isis->area_list || isis->area_list->count == 0) return CMD_SUCCESS; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (area->ip_circuits > 0 && area->spftree[1] && area->spftree[1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-2 routers that speak IP%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree[1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0 && area->spftree6[1] && area->spftree6[1]->paths->count > 0) { vty_out (vty, "IS-IS paths to level-2 routers that speak IPv6%s", VTY_NEWLINE); isis_print_paths (vty, area->spftree6[1]->paths, isis->sysid); vty_out (vty, "%s", VTY_NEWLINE); } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } void isis_spf_cmds_init () { install_element (VIEW_NODE, &show_isis_topology_cmd); install_element (VIEW_NODE, &show_isis_topology_l1_cmd); install_element (VIEW_NODE, &show_isis_topology_l2_cmd); install_element (ENABLE_NODE, &show_isis_topology_cmd); install_element (ENABLE_NODE, &show_isis_topology_l1_cmd); install_element (ENABLE_NODE, &show_isis_topology_l2_cmd); } quagga-0.99.24.1/isisd/isis_events.c0000644000175000017500000002450612476520570014055 00000000000000/* * IS-IS Rout(e)ing protocol - isis_events.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "table.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #include "isisd/isis_spf.h" /* debug isis-spf spf-events 4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4 4w4d: ISIS-Spf (tlt): L2, 0000.0000.0042.01-00 TLV contents changed, code 0x2 4w4d: ISIS-Spf (tlt): L2, new LSP 0 DEAD.BEEF.0043.00-00 4w5d: ISIS-Spf (tlt): L1 SPF needed, periodic SPF, from 0x6091C844 4w5d: ISIS-Spf (tlt): L2 SPF needed, periodic SPF, from 0x6091C844 */ void isis_event_circuit_state_change (struct isis_circuit *circuit, struct isis_area *area, int up) { area->circuit_state_changes++; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) circuit %s", area->area_tag, up ? "up" : "down"); /* * Regenerate LSPs this affects */ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } static void area_resign_level (struct isis_area *area, int level) { if (area->lspdb[level - 1]) { lsp_db_destroy (area->lspdb[level - 1]); area->lspdb[level - 1] = NULL; } if (area->spftree[level - 1]) { isis_spftree_del (area->spftree[level - 1]); area->spftree[level - 1] = NULL; } #ifdef HAVE_IPV6 if (area->spftree6[level - 1]) { isis_spftree_del (area->spftree6[level - 1]); area->spftree6[level - 1] = NULL; } #endif if (area->route_table[level - 1]) { route_table_finish (area->route_table[level - 1]); area->route_table[level - 1] = NULL; } #ifdef HAVE_IPV6 if (area->route_table6[level - 1]) { route_table_finish (area->route_table6[level - 1]); area->route_table6[level - 1] = NULL; } #endif /* HAVE_IPV6 */ THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); } void isis_event_system_type_change (struct isis_area *area, int newtype) { struct listnode *node; struct isis_circuit *circuit; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) system type change %s -> %s", area->area_tag, circuit_t2string (area->is_type), circuit_t2string (newtype)); if (area->is_type == newtype) return; /* No change */ switch (area->is_type) { case IS_LEVEL_1: if (newtype == IS_LEVEL_2) area_resign_level (area, IS_LEVEL_1); if (area->lspdb[1] == NULL) area->lspdb[1] = lsp_db_init (); if (area->route_table[1] == NULL) area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 if (area->route_table6[1] == NULL) area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ break; case IS_LEVEL_1_AND_2: if (newtype == IS_LEVEL_1) area_resign_level (area, IS_LEVEL_2); else area_resign_level (area, IS_LEVEL_1); break; case IS_LEVEL_2: if (newtype == IS_LEVEL_1) area_resign_level (area, IS_LEVEL_2); if (area->lspdb[0] == NULL) area->lspdb[0] = lsp_db_init (); if (area->route_table[0] == NULL) area->route_table[0] = route_table_init (); #ifdef HAVE_IPV6 if (area->route_table6[0] == NULL) area->route_table6[0] = route_table_init (); #endif /* HAVE_IPV6 */ break; default: break; } area->is_type = newtype; /* override circuit's is_type */ if (area->is_type != IS_LEVEL_1_AND_2) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) isis_event_circuit_type_change (circuit, newtype); } spftree_area_init (area); if (newtype & IS_LEVEL_1) lsp_generate (area, IS_LEVEL_1); if (newtype & IS_LEVEL_2) lsp_generate (area, IS_LEVEL_2); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return; } static void circuit_commence_level (struct isis_circuit *circuit, int level) { if (level == 1) { if (! circuit->is_passive) THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, isis_jitter (circuit->hello_interval[0], IIH_JITTER)); circuit->u.bc.lan_neighs[0] = list_new (); } } else { if (! circuit->is_passive) THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); circuit->u.bc.lan_neighs[1] = list_new (); } } return; } static void circuit_resign_level (struct isis_circuit *circuit, int level) { int idx = level - 1; THREAD_TIMER_OFF (circuit->t_send_csnp[idx]); THREAD_TIMER_OFF (circuit->t_send_psnp[idx]); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[idx]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[idx]); circuit->u.bc.run_dr_elect[idx] = 0; list_delete (circuit->u.bc.lan_neighs[idx]); circuit->u.bc.lan_neighs[idx] = NULL; } return; } void isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype) { if (circuit->state != C_STATE_UP) { circuit->is_type = newtype; return; } if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) circuit type change %s -> %s", circuit->area->area_tag, circuit_t2string (circuit->is_type), circuit_t2string (newtype)); if (circuit->is_type == newtype) return; /* No change */ if (!(newtype & circuit->area->is_type)) { zlog_err ("ISIS-Evt (%s) circuit type change - invalid level %s because" " area is %s", circuit->area->area_tag, circuit_t2string (newtype), circuit_t2string (circuit->area->is_type)); return; } if (! circuit->is_passive) { switch (circuit->is_type) { case IS_LEVEL_1: if (newtype == IS_LEVEL_2) circuit_resign_level (circuit, 1); circuit_commence_level (circuit, 2); break; case IS_LEVEL_1_AND_2: if (newtype == IS_LEVEL_1) circuit_resign_level (circuit, 2); else circuit_resign_level (circuit, 1); break; case IS_LEVEL_2: if (newtype == IS_LEVEL_1) circuit_resign_level (circuit, 2); circuit_commence_level (circuit, 1); break; default: break; } } circuit->is_type = newtype; lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } /* 04/18/2002 by Gwak. */ /************************************************************************** * * EVENTS for LSP generation * * 1) an Adajacency or Circuit Up/Down event * 2) a chnage in Circuit metric * 3) a change in Reachable Address metric * 4) a change in manualAreaAddresses * 5) a change in systemID * 6) a change in DIS status * 7) a chnage in the waiting status * * *********************************************************************** * * current support event * * 1) Adjacency Up/Down event * 6) a change in DIS status * * ***********************************************************************/ void isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate) { /* adjacency state change event. * - the only proto-type was supported */ /* invalid arguments */ if (!adj || !adj->circuit || !adj->circuit->area) return; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) Adjacency State change", adj->circuit->area->area_tag); /* LSP generation again */ lsp_regenerate_schedule (adj->circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return; } /* events supporting code */ int isis_event_dis_status_change (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); /* invalid arguments */ if (!circuit || !circuit->area) return 0; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) DIS status change", circuit->area->area_tag); /* LSP generation again */ lsp_regenerate_schedule (circuit->area, IS_LEVEL_1 | IS_LEVEL_2, 0); return 0; } void isis_event_auth_failure (char *area_tag, const char *error_string, u_char *sysid) { if (isis->debugs & DEBUG_EVENTS) zlog_debug ("ISIS-Evt (%s) Authentication failure %s from %s", area_tag, error_string, sysid_print (sysid)); return; } quagga-0.99.24.1/isisd/isis_csm.c0000644000175000017500000001303712476520570013330 00000000000000/* * IS-IS Rout(e)ing protocol - isis_csm.c * IS-IS circuit state machine * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" extern struct isis *isis; static const char *csm_statestr[] = { "C_STATE_NA", "C_STATE_INIT", "C_STATE_CONF", "C_STATE_UP" }; #define STATE2STR(S) csm_statestr[S] static const char *csm_eventstr[] = { "NO_STATE", "ISIS_ENABLE", "IF_UP_FROM_Z", "ISIS_DISABLE", "IF_DOWN_FROM_Z", }; #define EVENT2STR(E) csm_eventstr[E] struct isis_circuit * isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg) { int old_state; old_state = circuit ? circuit->state : C_STATE_NA; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("CSM_EVENT: %s", EVENT2STR (event)); switch (old_state) { case C_STATE_NA: if (circuit) zlog_warn ("Non-null circuit while state C_STATE_NA"); assert (circuit == NULL); switch (event) { case ISIS_ENABLE: circuit = isis_circuit_new (); isis_circuit_configure (circuit, (struct isis_area *) arg); circuit->state = C_STATE_CONF; break; case IF_UP_FROM_Z: circuit = isis_circuit_new (); isis_circuit_if_add (circuit, (struct interface *) arg); listnode_add (isis->init_circ_list, circuit); circuit->state = C_STATE_INIT; break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: zlog_warn ("circuit already disconnected"); break; } break; case C_STATE_INIT: assert (circuit); switch (event) { case ISIS_ENABLE: isis_circuit_configure (circuit, (struct isis_area *) arg); if (isis_circuit_up (circuit) != ISIS_OK) { isis_circuit_deconfigure (circuit, (struct isis_area *) arg); break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change (circuit, circuit->area, 1); listnode_delete (isis->init_circ_list, circuit); break; case IF_UP_FROM_Z: assert (circuit); zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: zlog_warn ("circuit already disabled"); break; case IF_DOWN_FROM_Z: isis_circuit_if_del (circuit, (struct interface *) arg); listnode_delete (isis->init_circ_list, circuit); isis_circuit_del (circuit); circuit = NULL; break; } break; case C_STATE_CONF: assert (circuit); switch (event) { case ISIS_ENABLE: zlog_warn ("circuit already enabled"); break; case IF_UP_FROM_Z: isis_circuit_if_add (circuit, (struct interface *) arg); if (isis_circuit_up (circuit) != ISIS_OK) { isis_circuit_if_del (circuit, (struct interface *) arg); break; } circuit->state = C_STATE_UP; isis_event_circuit_state_change (circuit, circuit->area, 1); break; case ISIS_DISABLE: isis_circuit_deconfigure (circuit, (struct isis_area *) arg); isis_circuit_del (circuit); circuit = NULL; break; case IF_DOWN_FROM_Z: zlog_warn ("circuit already disconnected"); break; } break; case C_STATE_UP: assert (circuit); switch (event) { case ISIS_ENABLE: zlog_warn ("circuit already configured"); break; case IF_UP_FROM_Z: zlog_warn ("circuit already connected"); break; case ISIS_DISABLE: isis_circuit_down (circuit); isis_circuit_deconfigure (circuit, (struct isis_area *) arg); circuit->state = C_STATE_INIT; isis_event_circuit_state_change (circuit, (struct isis_area *)arg, 0); listnode_add (isis->init_circ_list, circuit); break; case IF_DOWN_FROM_Z: isis_circuit_down (circuit); isis_circuit_if_del (circuit, (struct interface *) arg); circuit->state = C_STATE_CONF; isis_event_circuit_state_change (circuit, circuit->area, 0); break; } break; default: zlog_warn ("Invalid circuit state %d", old_state); } if (isis->debugs & DEBUG_EVENTS) zlog_debug ("CSM_STATE_CHANGE: %s -> %s ", STATE2STR (old_state), circuit ? STATE2STR (circuit->state) : STATE2STR (C_STATE_NA)); return circuit; } quagga-0.99.24.1/isisd/iso_checksum.c0000644000175000017500000000370512476520570014174 00000000000000/* * IS-IS Rout(e)ing protocol - iso_checksum.c * ISO checksum related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "iso_checksum.h" #include "checksum.h" /* * Calculations of the OSI checksum. * ISO/IEC 8473 defines the sum as * * L * sum a (mod 255) = 0 * 1 i * * L * sum (L-i+1)a (mod 255) = 0 * 1 i * */ /* * Verifies that the checksum is correct. * Return 0 on correct and 1 on invalid checksum. * Based on Annex C.4 of ISO/IEC 8473 */ int iso_csum_verify (u_char * buffer, int len, uint16_t * csum) { u_int16_t checksum; u_int32_t c0; u_int32_t c1; c0 = *csum & 0xff00; c1 = *csum & 0x00ff; /* * If both are zero return correct */ if (c0 == 0 && c1 == 0) return 0; /* * If either, but not both are zero return incorrect */ if (c0 == 0 || c1 == 0) return 1; /* Offset of checksum from the start of the buffer */ int offset = (u_char *) csum - buffer; checksum = fletcher_checksum(buffer, len, offset); if (checksum == *csum) return 0; return 1; } quagga-0.99.24.1/isisd/isis_dynhn.c0000644000175000017500000001031712476520570013664 00000000000000/* * IS-IS Rout(e)ing protocol - isis_dynhn.c * Dynamic hostname cache * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "vty.h" #include "linklist.h" #include "memory.h" #include "log.h" #include "stream.h" #include "command.h" #include "if.h" #include "thread.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" extern struct host host; struct list *dyn_cache = NULL; static int dyn_cache_cleanup (struct thread *); void dyn_cache_init (void) { if (dyn_cache == NULL) dyn_cache = list_new (); THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120); return; } static int dyn_cache_cleanup (struct thread *thread) { struct listnode *node, *nnode; struct isis_dynhn *dyn; time_t now = time (NULL); isis->t_dync_clean = NULL; for (ALL_LIST_ELEMENTS (dyn_cache, node, nnode, dyn)) { if ((now - dyn->refresh) < MAX_LSP_LIFETIME) continue; list_delete_node (dyn_cache, node); XFREE (MTYPE_ISIS_DYNHN, dyn); } THREAD_TIMER_ON (master, isis->t_dync_clean, dyn_cache_cleanup, NULL, 120); return ISIS_OK; } struct isis_dynhn * dynhn_find_by_id (u_char * id) { struct listnode *node = NULL; struct isis_dynhn *dyn = NULL; for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) if (memcmp (dyn->id, id, ISIS_SYS_ID_LEN) == 0) return dyn; return NULL; } struct isis_dynhn * dynhn_find_by_name (const char *hostname) { struct listnode *node = NULL; struct isis_dynhn *dyn = NULL; for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) if (strncmp ((char *)dyn->name.name, hostname, 255) == 0) return dyn; return NULL; } void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level) { struct isis_dynhn *dyn; dyn = dynhn_find_by_id (id); if (dyn) { memcpy (&dyn->name, hostname, hostname->namelen + 1); memcpy (dyn->id, id, ISIS_SYS_ID_LEN); dyn->refresh = time (NULL); return; } dyn = XCALLOC (MTYPE_ISIS_DYNHN, sizeof (struct isis_dynhn)); if (!dyn) { zlog_warn ("isis_dynhn_insert(): out of memory!"); return; } /* we also copy the length */ memcpy (&dyn->name, hostname, hostname->namelen + 1); memcpy (dyn->id, id, ISIS_SYS_ID_LEN); dyn->refresh = time (NULL); dyn->level = level; listnode_add (dyn_cache, dyn); return; } void isis_dynhn_remove (u_char * id) { struct isis_dynhn *dyn; dyn = dynhn_find_by_id (id); if (!dyn) return; listnode_delete (dyn_cache, dyn); XFREE (MTYPE_ISIS_DYNHN, dyn); return; } /* * Level System ID Dynamic Hostname (notag) * 2 0000.0000.0001 foo-gw * 2 0000.0000.0002 bar-gw * * 0000.0000.0004 this-gw */ void dynhn_print_all (struct vty *vty) { struct listnode *node; struct isis_dynhn *dyn; vty_out (vty, "Level System ID Dynamic Hostname%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (dyn_cache, node, dyn)) { vty_out (vty, "%-7d", dyn->level); vty_out (vty, "%-15s%-15s%s", sysid_print (dyn->id), dyn->name.name, VTY_NEWLINE); } vty_out (vty, " * %s %s%s", sysid_print (isis->sysid), unix_hostname (), VTY_NEWLINE); return; } quagga-0.99.24.1/isisd/isis_flags.c0000644000175000017500000000417712476520570013647 00000000000000/* * IS-IS Rout(e)ing protocol - isis_flags.c * Routines for manipulation of SSN and SRM flags * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "linklist.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" void flags_initialize (struct flags *flags) { flags->maxindex = 0; flags->free_idcs = NULL; } long int flags_get_index (struct flags *flags) { struct listnode *node; long int index; if (flags->free_idcs == NULL || flags->free_idcs->count == 0) { index = flags->maxindex++; } else { node = listhead (flags->free_idcs); index = (long int) listgetdata (node); listnode_delete (flags->free_idcs, (void *) index); index--; } return index; } void flags_free_index (struct flags *flags, long int index) { if (index + 1 == flags->maxindex) { flags->maxindex--; return; } if (flags->free_idcs == NULL) { flags->free_idcs = list_new (); } listnode_add (flags->free_idcs, (void *) (index + 1)); return; } int flags_any_set (u_int32_t * flags) { u_int32_t zero[ISIS_MAX_CIRCUITS]; memset (zero, 0x00, ISIS_MAX_CIRCUITS * 4); return bcmp (flags, zero, ISIS_MAX_CIRCUITS * 4); } quagga-0.99.24.1/isisd/isis_dr.c0000644000175000017500000002376412476520570013163 00000000000000/* * IS-IS Rout(e)ing protocol - isis_dr.c * IS-IS designated router related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "hash.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "stream.h" #include "if.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_misc.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_constants.h" #include "isisd/isis_pdu.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_dr.h" #include "isisd/isis_events.h" const char * isis_disflag2string (int disflag) { switch (disflag) { case ISIS_IS_NOT_DIS: return "is not DIS"; case ISIS_IS_DIS: return "is DIS"; case ISIS_WAS_DIS: return "was DIS"; default: return "unknown DIS state"; } return NULL; /* not reached */ } int isis_run_dr_l1 (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->u.bc.run_dr_elect[0]) zlog_warn ("isis_run_dr(): run_dr_elect already set for l1"); circuit->u.bc.t_run_dr[0] = NULL; circuit->u.bc.run_dr_elect[0] = 1; return ISIS_OK; } int isis_run_dr_l2 (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->u.bc.run_dr_elect[1]) zlog_warn ("isis_run_dr(): run_dr_elect already set for l2"); circuit->u.bc.t_run_dr[1] = NULL; circuit->u.bc.run_dr_elect[1] = 1; return ISIS_OK; } static int isis_check_dr_change (struct isis_adjacency *adj, int level) { int i; if (adj->dis_record[level - 1].dis != adj->dis_record[(1 * ISIS_LEVELS) + level - 1].dis) /* was there a DIS state transition ? */ { adj->dischanges[level - 1]++; /* ok rotate the history list through */ for (i = DIS_RECORDS - 1; i > 0; i--) { adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].dis; adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change = adj->dis_record[((i - 1) * ISIS_LEVELS) + level - 1].last_dis_change; } } return ISIS_OK; } int isis_dr_elect (struct isis_circuit *circuit, int level) { struct list *adjdb; struct listnode *node; struct isis_adjacency *adj, *adj_dr = NULL; struct list *list = list_new (); u_char own_prio; int biggest_prio = -1; int cmp_res, retval = ISIS_OK; own_prio = circuit->priority[level - 1]; adjdb = circuit->u.bc.adjdb[level - 1]; if (!adjdb) { zlog_warn ("isis_dr_elect() adjdb == NULL"); list_delete (list); return ISIS_WARNING; } isis_adj_build_up_list (adjdb, list); /* * Loop the adjacencies and find the one with the biggest priority */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) { /* clear flag for show output */ adj->dis_record[level - 1].dis = ISIS_IS_NOT_DIS; adj->dis_record[level - 1].last_dis_change = time (NULL); if (adj->prio[level - 1] > biggest_prio) { biggest_prio = adj->prio[level - 1]; adj_dr = adj; } else if (adj->prio[level - 1] == biggest_prio) { /* * Comparison of MACs breaks a tie */ if (adj_dr) { cmp_res = memcmp (adj_dr->snpa, adj->snpa, ETH_ALEN); if (cmp_res < 0) { adj_dr = adj; } if (cmp_res == 0) zlog_warn ("isis_dr_elect(): multiple adjacencies with same SNPA"); } else { adj_dr = adj; } } } if (!adj_dr) { /* * Could not find the DR - means we are alone. Resign if we were DR. */ if (circuit->u.bc.is_dr[level - 1]) retval = isis_dr_resign (circuit, level); list_delete (list); return retval; } /* * Now we have the DR adjacency, compare it to self */ if (adj_dr->prio[level - 1] < own_prio || (adj_dr->prio[level - 1] == own_prio && memcmp (adj_dr->snpa, circuit->u.bc.snpa, ETH_ALEN) < 0)) { adj_dr->dis_record[level - 1].dis = ISIS_IS_NOT_DIS; adj_dr->dis_record[level - 1].last_dis_change = time (NULL); /* rotate the history log */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) isis_check_dr_change (adj, level); /* We are the DR, commence DR */ if (circuit->u.bc.is_dr[level - 1] == 0 && listcount (list) > 0) retval = isis_dr_commence (circuit, level); } else { /* ok we have found the DIS - lets mark the adjacency */ /* set flag for show output */ adj_dr->dis_record[level - 1].dis = ISIS_IS_DIS; adj_dr->dis_record[level - 1].last_dis_change = time (NULL); /* now loop through a second time to check if there has been a DIS change * if yes rotate the history log */ for (ALL_LIST_ELEMENTS_RO (list, node, adj)) isis_check_dr_change (adj, level); /* * We are not DR - if we were -> resign */ if (circuit->u.bc.is_dr[level - 1]) retval = isis_dr_resign (circuit, level); } list_delete (list); return retval; } int isis_dr_resign (struct isis_circuit *circuit, int level) { u_char id[ISIS_SYS_ID_LEN + 2]; zlog_debug ("isis_dr_resign l%d", level); circuit->u.bc.is_dr[level - 1] = 0; circuit->u.bc.run_dr_elect[level - 1] = 0; THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[level - 1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); circuit->lsp_regenerate_pending[level - 1] = 0; memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, level); if (level == 1) { memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); THREAD_TIMER_OFF (circuit->t_send_csnp[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER)); } else { memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); THREAD_TIMER_OFF (circuit->t_send_csnp[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[level - 1], PSNP_JITTER)); } thread_add_event (master, isis_event_dis_status_change, circuit, 0); return ISIS_OK; } int isis_dr_commence (struct isis_circuit *circuit, int level) { u_char old_dr[ISIS_SYS_ID_LEN + 2]; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("isis_dr_commence l%d", level); /* Lets keep a pause in DR election */ circuit->u.bc.run_dr_elect[level - 1] = 0; if (level == 1) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); else THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); circuit->u.bc.is_dr[level - 1] = 1; if (level == 1) { memcpy (old_dr, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (old_dr) = 0; if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l1_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l1_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ lsp_generate_pseudo (circuit, 1); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[level - 1], CSNP_JITTER)); } else { memcpy (old_dr, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (old_dr) = 0; if (LSP_PSEUDO_ID (old_dr)) { /* there was a dr elected, purge its LSPs from the db */ lsp_purge_pseudo (old_dr, circuit, level); } memcpy (circuit->u.bc.l2_desig_is, isis->sysid, ISIS_SYS_ID_LEN); *(circuit->u.bc.l2_desig_is + ISIS_SYS_ID_LEN) = circuit->circuit_id; assert (circuit->circuit_id); /* must be non-zero */ /* if (circuit->t_send_l1_psnp) thread_cancel (circuit->t_send_l1_psnp); */ lsp_generate_pseudo (circuit, 2); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[level - 1], CSNP_JITTER)); } thread_add_event (master, isis_event_dis_status_change, circuit, 0); return ISIS_OK; } quagga-0.99.24.1/isisd/isis_zebra.c0000644000175000017500000003742212476520570013655 00000000000000/* * IS-IS Rout(e)ing protocol - isis_zebra.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "command.h" #include "memory.h" #include "log.h" #include "if.h" #include "network.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "linklist.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_misc.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isis_lsp.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" struct zclient *zclient = NULL; /* Router-id update message from zebra. */ static int isis_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length) { struct isis_area *area; struct listnode *node; struct prefix router_id; zebra_router_id_update_read (zclient->ibuf, &router_id); if (isis->router_id == router_id.u.prefix4.s_addr) return 0; isis->router_id = router_id.u.prefix4.s_addr; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) if (listcount (area->area_addrs) > 0) lsp_regenerate_schedule (area, area->is_type, 0); return 0; } static int isis_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("Zebra I/F add: %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu); if (if_is_operative (ifp)) isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); return 0; } static int isis_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct stream *s; s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (!ifp) return 0; if (if_is_operative (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("Zebra I/F delete: %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric, ifp->mtu); isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); /* Cannot call if_delete because we should retain the pseudo interface in case there is configuration info attached to it. */ if_delete_retain(ifp); ifp->ifindex = IFINDEX_INTERNAL; return 0; } static int isis_zebra_if_state_up (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; isis_csm_state_change (IF_UP_FROM_Z, circuit_scan_by_ifp (ifp), ifp); return 0; } static int isis_zebra_if_state_down (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct isis_circuit *circuit; ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; circuit = isis_csm_state_change (IF_DOWN_FROM_Z, circuit_scan_by_ifp (ifp), ifp); if (circuit) SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF); return 0; } static int isis_zebra_if_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; struct prefix *p; char buf[BUFSIZ]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (c == NULL) return 0; p = c->address; prefix2str (p, buf, BUFSIZ); #ifdef EXTREME_DEBUG if (p->family == AF_INET) zlog_debug ("connected IP address %s", buf); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zlog_debug ("connected IPv6 address %s", buf); #endif /* HAVE_IPV6 */ #endif /* EXTREME_DEBUG */ if (if_is_operative (c->ifp)) isis_circuit_add_addr (circuit_scan_by_ifp (c->ifp), c); return 0; } static int isis_zebra_if_address_del (int command, struct zclient *client, zebra_size_t length) { struct connected *c; struct interface *ifp; #ifdef EXTREME_DEBUG struct prefix *p; u_char buf[BUFSIZ]; #endif /* EXTREME_DEBUG */ c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); if (c == NULL) return 0; ifp = c->ifp; #ifdef EXTREME_DEBUG p = c->address; prefix2str (p, buf, BUFSIZ); if (p->family == AF_INET) zlog_debug ("disconnected IP address %s", buf); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zlog_debug ("disconnected IPv6 address %s", buf); #endif /* HAVE_IPV6 */ #endif /* EXTREME_DEBUG */ if (if_is_operative (ifp)) isis_circuit_del_addr (circuit_scan_by_ifp (ifp), c); connected_free (c); return 0; } static void isis_zebra_route_add_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { u_char message, flags; int psize; struct stream *stream; struct isis_nexthop *nexthop; struct listnode *node; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; if (zclient->redist[ZEBRA_ROUTE_ISIS]) { message = 0; flags = 0; SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); #if 0 SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); #endif stream = zclient->obuf; stream_reset (stream); zclient_create_header (stream, ZEBRA_IPV4_ROUTE_ADD); /* type */ stream_putc (stream, ZEBRA_ROUTE_ISIS); /* flags */ stream_putc (stream, flags); /* message */ stream_putc (stream, message); /* SAFI */ stream_putw (stream, SAFI_UNICAST); /* prefix information */ psize = PSIZE (prefix->prefixlen); stream_putc (stream, prefix->prefixlen); stream_write (stream, (u_char *) & prefix->u.prefix4, psize); stream_putc (stream, listcount (route_info->nexthops)); /* Nexthop, ifindex, distance and metric information */ for (ALL_LIST_ELEMENTS_RO (route_info->nexthops, node, nexthop)) { /* FIXME: can it be ? */ if (nexthop->ip.s_addr != INADDR_ANY) { stream_putc (stream, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (stream, &nexthop->ip); } else { stream_putc (stream, ZEBRA_NEXTHOP_IFINDEX); stream_putl (stream, nexthop->ifindex); } } #if 0 if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (stream, route_info->depth); #endif if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) stream_putl (stream, route_info->cost); stream_putw_at (stream, 0, stream_get_endp (stream)); zclient_send_message(zclient); SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } } static void isis_zebra_route_del_ipv4 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv4 api; struct prefix_ipv4 prefix4; if (zclient->redist[ZEBRA_ROUTE_ISIS]) { api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; prefix4.family = AF_INET; prefix4.prefixlen = prefix->prefixlen; prefix4.prefix = prefix->u.prefix4; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, &prefix4, &api); } UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); return; } #ifdef HAVE_IPV6 void isis_zebra_route_add_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; unsigned int *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; struct prefix_ipv6 prefix6; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = route_info->cost; #if 0 SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = route_info->depth; #endif api.nexthop_num = listcount (route_info->nexthops6); api.ifindex_num = listcount (route_info->nexthops6); /* allocate memory for nexthop_list */ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6); nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size); if (!nexthop_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); return; } /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_add_route_ipv6: out of memory!"); XFREE (MTYPE_ISIS_TMP, nexthop_list); return; } /* for each nexthop */ i = 0; for (ALL_LIST_ELEMENTS_RO (route_info->nexthops6, node, nexthop6)) { if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) && !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) { api.nexthop_num--; api.ifindex_num--; continue; } nexthop_list[i] = &nexthop6->ip6; ifindex_list[i] = nexthop6->ifindex; i++; } api.nexthop = nexthop_list; api.ifindex = ifindex_list; if (api.nexthop_num && api.ifindex_num) { prefix6.family = AF_INET6; prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, &prefix6, &api); SET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC); } XFREE (MTYPE_ISIS_TMP, nexthop_list); XFREE (MTYPE_ISIS_TMP, ifindex_list); return; } static void isis_zebra_route_del_ipv6 (struct prefix *prefix, struct isis_route_info *route_info) { struct zapi_ipv6 api; struct in6_addr **nexthop_list; unsigned int *ifindex_list; struct isis_nexthop6 *nexthop6; int i, size; struct listnode *node; struct prefix_ipv6 prefix6; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; api.type = ZEBRA_ROUTE_ISIS; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.nexthop_num = listcount (route_info->nexthops6); api.ifindex_num = listcount (route_info->nexthops6); /* allocate memory for nexthop_list */ size = sizeof (struct isis_nexthop6 *) * listcount (route_info->nexthops6); nexthop_list = (struct in6_addr **) XMALLOC (MTYPE_ISIS_TMP, size); if (!nexthop_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); return; } /* allocate memory for ifindex_list */ size = sizeof (unsigned int) * listcount (route_info->nexthops6); ifindex_list = (unsigned int *) XMALLOC (MTYPE_ISIS_TMP, size); if (!ifindex_list) { zlog_err ("isis_zebra_route_del_ipv6: out of memory!"); XFREE (MTYPE_ISIS_TMP, nexthop_list); return; } /* for each nexthop */ i = 0; for (ALL_LIST_ELEMENTS_RO (route_info->nexthops6, node, nexthop6)) { if (!IN6_IS_ADDR_LINKLOCAL (&nexthop6->ip6) && !IN6_IS_ADDR_UNSPECIFIED (&nexthop6->ip6)) { api.nexthop_num--; api.ifindex_num--; continue; } nexthop_list[i] = &nexthop6->ip6; ifindex_list[i] = nexthop6->ifindex; i++; } api.nexthop = nexthop_list; api.ifindex = ifindex_list; if (api.nexthop_num && api.ifindex_num) { prefix6.family = AF_INET6; prefix6.prefixlen = prefix->prefixlen; memcpy (&prefix6.prefix, &prefix->u.prefix6, sizeof (struct in6_addr)); zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, &prefix6, &api); UNSET_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); } XFREE (MTYPE_ISIS_TMP, nexthop_list); XFREE (MTYPE_ISIS_TMP, ifindex_list); } #endif /* HAVE_IPV6 */ void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info) { if (zclient->sock < 0) return; if (!zclient->redist[ZEBRA_ROUTE_ISIS]) return; if (CHECK_FLAG (route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) { if (prefix->family == AF_INET) isis_zebra_route_add_ipv4 (prefix, route_info); #ifdef HAVE_IPV6 else if (prefix->family == AF_INET6) isis_zebra_route_add_ipv6 (prefix, route_info); #endif /* HAVE_IPV6 */ } else { if (prefix->family == AF_INET) isis_zebra_route_del_ipv4 (prefix, route_info); #ifdef HAVE_IPV6 else if (prefix->family == AF_INET6) isis_zebra_route_del_ipv6 (prefix, route_info); #endif /* HAVE_IPV6 */ } return; } static int isis_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *stream; struct zapi_ipv4 api; struct prefix_ipv4 p; unsigned long ifindex; struct in_addr nexthop; stream = zclient->ibuf; memset (&p, 0, sizeof (struct prefix_ipv4)); ifindex = 0; api.type = stream_getc (stream); api.flags = stream_getc (stream); api.message = stream_getc (stream); p.family = AF_INET; p.prefixlen = stream_getc (stream); stream_get (&p.prefix, stream, PSIZE (p.prefixlen)); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (stream); nexthop.s_addr = stream_get_ipv4 (stream); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (stream); ifindex = stream_getl (stream); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (stream); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (stream); else api.metric = 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { if (isis->debugs & DEBUG_ZEBRA) zlog_debug ("IPv4 Route add from Z"); } return 0; } #ifdef HAVE_IPV6 static int isis_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { return 0; } #endif #define ISIS_TYPE_IS_REDISTRIBUTED(T) \ T == ZEBRA_ROUTE_MAX ? zclient->default_information : zclient->redist[type] int isis_distribute_list_update (int routetype) { return 0; } #if 0 /* Not yet. */ static int isis_redistribute_default_set (int routetype, int metric_type, int metric_value) { return 0; } #endif /* 0 */ void isis_zebra_init () { zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_ISIS); zclient->router_id_update = isis_router_id_update_zebra; zclient->interface_add = isis_zebra_if_add; zclient->interface_delete = isis_zebra_if_del; zclient->interface_up = isis_zebra_if_state_up; zclient->interface_down = isis_zebra_if_state_down; zclient->interface_address_add = isis_zebra_if_address_add; zclient->interface_address_delete = isis_zebra_if_address_del; zclient->ipv4_route_add = isis_zebra_read_ipv4; zclient->ipv4_route_delete = isis_zebra_read_ipv4; #ifdef HAVE_IPV6 zclient->ipv6_route_add = isis_zebra_read_ipv6; zclient->ipv6_route_delete = isis_zebra_read_ipv6; #endif /* HAVE_IPV6 */ return; } quagga-0.99.24.1/isisd/isis_misc.c0000644000175000017500000003035412476520570013502 00000000000000/* * IS-IS Rout(e)ing protocol - isis_misc.h * Miscellanous routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "stream.h" #include "vty.h" #include "hash.h" #include "if.h" #include "command.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_misc.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dynhn.h" /* staticly assigned vars for printing purposes */ struct in_addr new_prefix; /* len of xxxx.xxxx.xxxx + place for #0 termination */ char sysid[15]; /* len of xxxx.xxxx.xxxx + place for #0 termination */ char snpa[15]; /* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */ char isonet[51]; /* + place for #0 termination */ /* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */ char lspid[21]; /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */ char datestring[20]; char nlpidstring[30]; /* * This converts the isonet to its printable format */ const char * isonet_print (u_char * from, int len) { int i = 0; char *pos = isonet; if (!from) return "unknown"; while (i < len) { if (i & 1) { sprintf (pos, "%02x", *(from + i)); pos += 2; } else { if (i == (len - 1)) { /* No dot at the end of address */ sprintf (pos, "%02x", *(from + i)); pos += 2; } else { sprintf (pos, "%02x.", *(from + i)); pos += 3; } } i++; } *(pos) = '\0'; return isonet; } /* * Returns 0 on error, length of buff on ok * extract dot from the dotted str, and insert all the number in a buff */ int dotformat2buff (u_char * buff, const char * dotted) { int dotlen, len = 0; const char *pos = dotted; u_char number[3]; int nextdotpos = 2; number[2] = '\0'; dotlen = strlen(dotted); if (dotlen > 50) { /* this can't be an iso net, its too long */ return 0; } while ((pos - dotted) < dotlen && len < 20) { if (*pos == '.') { /* we expect the . at 2, and than every 5 */ if ((pos - dotted) != nextdotpos) { len = 0; break; } nextdotpos += 5; pos++; continue; } /* we must have at least two chars left here */ if (dotlen - (pos - dotted) < 2) { len = 0; break; } if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1)))) { memcpy (number, pos, 2); pos += 2; } else { len = 0; break; } *(buff + len) = (char) strtol ((char *)number, NULL, 16); len++; } return len; } /* * conversion of XXXX.XXXX.XXXX to memory */ int sysid2buff (u_char * buff, const char * dotted) { int len = 0; const char *pos = dotted; u_char number[3]; number[2] = '\0'; // surely not a sysid_string if not 14 length if (strlen (dotted) != 14) { return 0; } while (len < ISIS_SYS_ID_LEN) { if (*pos == '.') { /* the . is not positioned correctly */ if (((pos - dotted) != 4) && ((pos - dotted) != 9)) { len = 0; break; } pos++; continue; } if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1)))) { memcpy (number, pos, 2); pos += 2; } else { len = 0; break; } *(buff + len) = (char) strtol ((char *)number, NULL, 16); len++; } return len; } /* * converts the nlpids struct (filled by TLV #129) * into a string */ char * nlpid2string (struct nlpids *nlpids) { char *pos = nlpidstring; int i; for (i = 0; i < nlpids->count; i++) { switch (nlpids->nlpids[i]) { case NLPID_IP: pos += sprintf (pos, "IPv4"); break; case NLPID_IPV6: pos += sprintf (pos, "IPv6"); break; case NLPID_SNAP: pos += sprintf (pos, "SNAP"); break; case NLPID_CLNP: pos += sprintf (pos, "CLNP"); break; case NLPID_ESIS: pos += sprintf (pos, "ES-IS"); break; default: pos += sprintf (pos, "unknown"); break; } if (nlpids->count - i > 1) pos += sprintf (pos, ", "); } *(pos) = '\0'; return nlpidstring; } /* * supports the given af ? */ int speaks (struct nlpids *nlpids, int family) { int i, speaks = 0; if (nlpids == (struct nlpids *) NULL) return speaks; for (i = 0; i < nlpids->count; i++) { if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP) speaks = 1; if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6) speaks = 1; } return speaks; } /* * Returns 0 on error, IS-IS Circuit Type on ok */ int string2circuit_t (const char * str) { if (!str) return 0; if (!strcmp (str, "level-1")) return IS_LEVEL_1; if (!strcmp (str, "level-2-only") || !strcmp (str, "level-2")) return IS_LEVEL_2; if (!strcmp (str, "level-1-2")) return IS_LEVEL_1_AND_2; return 0; } const char * circuit_state2string (int state) { switch (state) { case C_STATE_INIT: return "Init"; case C_STATE_CONF: return "Config"; case C_STATE_UP: return "Up"; default: return "Unknown"; } return NULL; } const char * circuit_type2string (int type) { switch (type) { case CIRCUIT_T_P2P: return "p2p"; case CIRCUIT_T_BROADCAST: return "lan"; case CIRCUIT_T_LOOPBACK: return "loopback"; default: return "Unknown"; } return NULL; } const char * circuit_t2string (int circuit_t) { switch (circuit_t) { case IS_LEVEL_1: return "L1"; case IS_LEVEL_2: return "L2"; case IS_LEVEL_1_AND_2: return "L1L2"; default: return "??"; } return NULL; /* not reached */ } const char * syst2string (int type) { switch (type) { case ISIS_SYSTYPE_ES: return "ES"; case ISIS_SYSTYPE_IS: return "IS"; case ISIS_SYSTYPE_L1_IS: return "1"; case ISIS_SYSTYPE_L2_IS: return "2"; default: return "??"; } return NULL; /* not reached */ } /* * Print functions - we print to static vars */ const char * snpa_print (u_char * from) { int i = 0; u_char *pos = (u_char *)snpa; if (!from) return "unknown"; while (i < ETH_ALEN - 1) { if (i & 1) { sprintf ((char *)pos, "%02x.", *(from + i)); pos += 3; } else { sprintf ((char *)pos, "%02x", *(from + i)); pos += 2; } i++; } sprintf ((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); pos += 2; *(pos) = '\0'; return snpa; } const char * sysid_print (u_char * from) { int i = 0; char *pos = sysid; if (!from) return "unknown"; while (i < ISIS_SYS_ID_LEN - 1) { if (i & 1) { sprintf (pos, "%02x.", *(from + i)); pos += 3; } else { sprintf (pos, "%02x", *(from + i)); pos += 2; } i++; } sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); pos += 2; *(pos) = '\0'; return sysid; } const char * rawlspid_print (u_char * from) { char *pos = lspid; if (!from) return "unknown"; memcpy (pos, sysid_print (from), 15); pos += 14; sprintf (pos, ".%02x", LSP_PSEUDO_ID (from)); pos += 3; sprintf (pos, "-%02x", LSP_FRAGMENT (from)); pos += 3; *(pos) = '\0'; return lspid; } const char * time2string (u_int32_t time) { char *pos = datestring; u_int32_t rest; if (time == 0) return "-"; if (time / SECS_PER_YEAR) pos += sprintf (pos, "%uY", time / SECS_PER_YEAR); rest = time % SECS_PER_YEAR; if (rest / SECS_PER_MONTH) pos += sprintf (pos, "%uM", rest / SECS_PER_MONTH); rest = rest % SECS_PER_MONTH; if (rest / SECS_PER_WEEK) pos += sprintf (pos, "%uw", rest / SECS_PER_WEEK); rest = rest % SECS_PER_WEEK; if (rest / SECS_PER_DAY) pos += sprintf (pos, "%ud", rest / SECS_PER_DAY); rest = rest % SECS_PER_DAY; if (rest / SECS_PER_HOUR) pos += sprintf (pos, "%uh", rest / SECS_PER_HOUR); rest = rest % SECS_PER_HOUR; if (rest / SECS_PER_MINUTE) pos += sprintf (pos, "%um", rest / SECS_PER_MINUTE); rest = rest % SECS_PER_MINUTE; if (rest) pos += sprintf (pos, "%us", rest); *(pos) = 0; return datestring; } /* * routine to decrement a timer by a random * number * * first argument is the timer and the second is * the jitter */ unsigned long isis_jitter (unsigned long timer, unsigned long jitter) { int j, k; if (jitter >= 100) return timer; if (timer == 1) return timer; /* * randomizing just the percent value provides * no good random numbers - hence the spread * to RANDOM_SPREAD (100000), which is ok as * most IS-IS timers are no longer than 16 bit */ j = 1 + (int) ((RANDOM_SPREAD * rand ()) / (RAND_MAX + 1.0)); k = timer - (timer * (100 - jitter)) / 100; timer = timer - (k * j / RANDOM_SPREAD); return timer; } struct in_addr newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen) { memset (&new_prefix, 0, sizeof (new_prefix)); memcpy (&new_prefix, prefix_start, (prefix_masklen & 0x3F) ? ((((prefix_masklen & 0x3F) - 1) >> 3) + 1) : 0); return new_prefix; } /* * Returns host.name if any, otherwise * it returns the system hostname. */ const char * unix_hostname (void) { static struct utsname names; const char *hostname; hostname = host.name; if (!hostname) { uname (&names); hostname = names.nodename; } return hostname; } /* * Returns the dynamic hostname associated with the passed system ID. * If no dynamic hostname found then returns formatted system ID. */ const char * print_sys_hostname (u_char *sysid) { struct isis_dynhn *dyn; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0) return unix_hostname(); dyn = dynhn_find_by_id (sysid); if (dyn) return (const char *)dyn->name.name; return sysid_print (sysid); } /* * This function is a generic utility that logs data of given length. * Move this to a shared lib so that any protocol can use it. */ void zlog_dump_data (void *data, int len) { int i; unsigned char *p; unsigned char c; char bytestr[4]; char addrstr[10]; char hexstr[ 16*3 + 5]; char charstr[16*1 + 5]; p = data; memset (bytestr, 0, sizeof(bytestr)); memset (addrstr, 0, sizeof(addrstr)); memset (hexstr, 0, sizeof(hexstr)); memset (charstr, 0, sizeof(charstr)); for (i = 1; i <= len; i++) { c = *p; if (isalnum (c) == 0) c = '.'; /* store address for this line */ if ((i % 16) == 1) snprintf (addrstr, sizeof(addrstr), "%p", p); /* store hex str (for left side) */ snprintf (bytestr, sizeof (bytestr), "%02X ", *p); strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1); /* store char str (for right side) */ snprintf (bytestr, sizeof (bytestr), "%c", c); strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1); if ((i % 16) == 0) { /* line completed */ zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); hexstr[0] = 0; charstr[0] = 0; } else if ((i % 8) == 0) { /* half line: add whitespaces */ strncat (hexstr, " ", sizeof (hexstr) - strlen (hexstr) - 1); strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1); } p++; /* next byte */ } /* print rest of buffer if not empty */ if (strlen (hexstr) > 0) zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr); return; } quagga-0.99.24.1/isisd/isisd.c0000644000175000017500000025543012476520570012637 00000000000000/* * IS-IS Rout(e)ing protocol - isisd.c * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "log.h" #include "memory.h" #include "time.h" #include "linklist.h" #include "if.h" #include "hash.h" #include "stream.h" #include "prefix.h" #include "table.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_pdu.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_route.h" #include "isisd/isis_zebra.h" #include "isisd/isis_events.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" u_char DEFAULT_TOPOLOGY_BASEIS[6] = { 0xFE, 0xED, 0xFE, 0xED, 0x00, 0x00 }; #endif /* TOPOLOGY_GENERATE */ struct isis *isis = NULL; /* * Prototypes. */ int isis_area_get(struct vty *, const char *); int isis_area_destroy(struct vty *, const char *); int area_net_title(struct vty *, const char *); int area_clear_net_title(struct vty *, const char *); int show_isis_interface_common(struct vty *, const char *ifname, char); int show_isis_neighbor_common(struct vty *, const char *id, char); int clear_isis_neighbor_common(struct vty *, const char *id); int isis_config_write(struct vty *); void isis_new (unsigned long process_id) { isis = XCALLOC (MTYPE_ISIS, sizeof (struct isis)); /* * Default values */ isis->max_area_addrs = 3; isis->process_id = process_id; isis->router_id = 0; isis->area_list = list_new (); isis->init_circ_list = list_new (); isis->uptime = time (NULL); isis->nexthops = list_new (); #ifdef HAVE_IPV6 isis->nexthops6 = list_new (); #endif /* HAVE_IPV6 */ dyn_cache_init (); /* * uncomment the next line for full debugs */ /* isis->debugs = 0xFFFF; */ } struct isis_area * isis_area_create (const char *area_tag) { struct isis_area *area; area = XCALLOC (MTYPE_ISIS_AREA, sizeof (struct isis_area)); /* * The first instance is level-1-2 rest are level-1, unless otherwise * configured */ if (listcount (isis->area_list) > 0) area->is_type = IS_LEVEL_1; else area->is_type = IS_LEVEL_1_AND_2; /* * intialize the databases */ if (area->is_type & IS_LEVEL_1) { area->lspdb[0] = lsp_db_init (); area->route_table[0] = route_table_init (); #ifdef HAVE_IPV6 area->route_table6[0] = route_table_init (); #endif /* HAVE_IPV6 */ } if (area->is_type & IS_LEVEL_2) { area->lspdb[1] = lsp_db_init (); area->route_table[1] = route_table_init (); #ifdef HAVE_IPV6 area->route_table6[1] = route_table_init (); #endif /* HAVE_IPV6 */ } spftree_area_init (area); area->circuit_list = list_new (); area->area_addrs = list_new (); THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1); flags_initialize (&area->flags); /* * Default values */ area->max_lsp_lifetime[0] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->max_lsp_lifetime[1] = DEFAULT_LSP_LIFETIME; /* 1200 */ area->lsp_refresh[0] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ area->lsp_refresh[1] = DEFAULT_MAX_LSP_GEN_INTERVAL; /* 900 */ area->lsp_gen_interval[0] = DEFAULT_MIN_LSP_GEN_INTERVAL; area->lsp_gen_interval[1] = DEFAULT_MIN_LSP_GEN_INTERVAL; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; area->dynhostname = 1; area->oldmetric = 0; area->newmetric = 1; area->lsp_frag_threshold = 90; #ifdef TOPOLOGY_GENERATE memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); #endif /* TOPOLOGY_GENERATE */ /* FIXME: Think of a better way... */ area->min_bcast_mtu = 1497; area->area_tag = strdup (area_tag); listnode_add (isis->area_list, area); area->isis = isis; return area; } struct isis_area * isis_area_lookup (const char *area_tag) { struct isis_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) if ((area->area_tag == NULL && area_tag == NULL) || (area->area_tag && area_tag && strcmp (area->area_tag, area_tag) == 0)) return area; return NULL; } int isis_area_get (struct vty *vty, const char *area_tag) { struct isis_area *area; area = isis_area_lookup (area_tag); if (area) { vty->node = ISIS_NODE; vty->index = area; return CMD_SUCCESS; } area = isis_area_create (area_tag); if (isis->debugs & DEBUG_EVENTS) zlog_debug ("New IS-IS area instance %s", area->area_tag); vty->node = ISIS_NODE; vty->index = area; return CMD_SUCCESS; } int isis_area_destroy (struct vty *vty, const char *area_tag) { struct isis_area *area; struct listnode *node, *nnode; struct isis_circuit *circuit; struct area_addr *addr; area = isis_area_lookup (area_tag); if (area == NULL) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } if (area->circuit_list) { for (ALL_LIST_ELEMENTS (area->circuit_list, node, nnode, circuit)) { circuit->ip_router = 0; #ifdef HAVE_IPV6 circuit->ipv6_router = 0; #endif isis_csm_state_change (ISIS_DISABLE, circuit, area); } list_delete (area->circuit_list); area->circuit_list = NULL; } if (area->lspdb[0] != NULL) { lsp_db_destroy (area->lspdb[0]); area->lspdb[0] = NULL; } if (area->lspdb[1] != NULL) { lsp_db_destroy (area->lspdb[1]); area->lspdb[1] = NULL; } spftree_area_del (area); /* invalidate and validate would delete all routes from zebra */ isis_route_invalidate (area); isis_route_validate (area); if (area->route_table[0]) { route_table_finish (area->route_table[0]); area->route_table[0] = NULL; } if (area->route_table[1]) { route_table_finish (area->route_table[1]); area->route_table[1] = NULL; } #ifdef HAVE_IPV6 if (area->route_table6[0]) { route_table_finish (area->route_table6[0]); area->route_table6[0] = NULL; } if (area->route_table6[1]) { route_table_finish (area->route_table6[1]); area->route_table6[1] = NULL; } #endif /* HAVE_IPV6 */ for (ALL_LIST_ELEMENTS (area->area_addrs, node, nnode, addr)) { list_delete_node (area->area_addrs, node); XFREE (MTYPE_ISIS_AREA_ADDR, addr); } area->area_addrs = NULL; THREAD_TIMER_OFF (area->t_tick); THREAD_TIMER_OFF (area->t_lsp_refresh[0]); THREAD_TIMER_OFF (area->t_lsp_refresh[1]); thread_cancel_event (master, area); listnode_delete (isis->area_list, area); free (area->area_tag); XFREE (MTYPE_ISIS_AREA, area); if (listcount (isis->area_list) == 0) { memset (isis->sysid, 0, ISIS_SYS_ID_LEN); isis->sysid_set = 0; } return CMD_SUCCESS; } int area_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr *addr; struct area_addr *addrp; struct listnode *node; u_char buff[255]; area = vty->index; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } /* We check that we are not over the maximal number of addresses */ if (listcount (area->area_addrs) >= isis->max_area_addrs) { vty_out (vty, "Maximum of area addresses (%d) already reached %s", isis->max_area_addrs, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } addr = XMALLOC (MTYPE_ISIS_AREA_ADDR, sizeof (struct area_addr)); addr->addr_len = dotformat2buff (buff, net_title); memcpy (addr->area_addr, buff, addr->addr_len); #ifdef EXTREME_DEBUG zlog_debug ("added area address %s for area %s (address length %d)", net_title, area->area_tag, addr->addr_len); #endif /* EXTREME_DEBUG */ if (addr->addr_len < 8 || addr->addr_len > 20) { vty_out (vty, "area address must be at least 8..20 octets long (%d)%s", addr->addr_len, VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } if (addr->area_addr[addr->addr_len-1] != 0) { vty_out (vty, "nsel byte (last byte) in area address must be 0%s", VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } if (isis->sysid_set == 0) { /* * First area address - get the SystemID for this router */ memcpy (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN); isis->sysid_set = 1; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("Router has SystemID %s", sysid_print (isis->sysid)); } else { /* * Check that the SystemID portions match */ if (memcmp (isis->sysid, GETSYSID (addr), ISIS_SYS_ID_LEN)) { vty_out (vty, "System ID must not change when defining additional area" " addresses%s", VTY_NEWLINE); XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_ERR_AMBIGUOUS; } /* now we see that we don't already have this address */ for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) { if ((addrp->addr_len + ISIS_SYS_ID_LEN + ISIS_NSEL_LEN) != (addr->addr_len)) continue; if (!memcmp (addrp->area_addr, addr->area_addr, addr->addr_len)) { XFREE (MTYPE_ISIS_AREA_ADDR, addr); return CMD_SUCCESS; /* silent fail */ } } } /* * Forget the systemID part of the address */ addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); listnode_add (area->area_addrs, addr); /* only now we can safely generate our LSPs for this area */ if (listcount (area->area_addrs) > 0) { if (area->is_type & IS_LEVEL_1) lsp_generate (area, IS_LEVEL_1); if (area->is_type & IS_LEVEL_2) lsp_generate (area, IS_LEVEL_2); } return CMD_SUCCESS; } int area_clear_net_title (struct vty *vty, const char *net_title) { struct isis_area *area; struct area_addr addr, *addrp = NULL; struct listnode *node; u_char buff[255]; area = vty->index; if (!area) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } addr.addr_len = dotformat2buff (buff, net_title); if (addr.addr_len < 8 || addr.addr_len > 20) { vty_out (vty, "Unsupported area address length %d, should be 8...20 %s", addr.addr_len, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } memcpy (addr.area_addr, buff, (int) addr.addr_len); for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node, addrp)) if ((addrp->addr_len + ISIS_SYS_ID_LEN + 1) == addr.addr_len && !memcmp (addrp->area_addr, addr.area_addr, addr.addr_len)) break; if (!addrp) { vty_out (vty, "No area address %s for area %s %s", net_title, area->area_tag, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } listnode_delete (area->area_addrs, addrp); XFREE (MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ if (listcount (area->area_addrs) == 0) { memset (isis->sysid, 0, ISIS_SYS_ID_LEN); isis->sysid_set = 0; if (isis->debugs & DEBUG_EVENTS) zlog_debug ("Router has no SystemID"); } return CMD_SUCCESS; } /* * 'show isis interface' command */ int show_isis_interface_common (struct vty *vty, const char *ifname, char detail) { struct listnode *anode, *cnode; struct isis_area *area; struct isis_circuit *circuit; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); if (detail == ISIS_UI_LEVEL_BRIEF) vty_out (vty, " Interface CircId State Type Level%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) if (!ifname) isis_circuit_print_vty (circuit, vty, detail); else if (strcmp(circuit->interface->name, ifname) == 0) isis_circuit_print_vty (circuit, vty, detail); } return CMD_SUCCESS; } DEFUN (show_isis_interface, show_isis_interface_cmd, "show isis interface", SHOW_STR "ISIS network information\n" "ISIS interface\n") { return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_isis_interface_detail, show_isis_interface_detail_cmd, "show isis interface detail", SHOW_STR "ISIS network information\n" "ISIS interface\n" "show detailed information\n") { return show_isis_interface_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_isis_interface_arg, show_isis_interface_arg_cmd, "show isis interface WORD", SHOW_STR "ISIS network information\n" "ISIS interface\n" "ISIS interface name\n") { return show_isis_interface_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } /* * 'show isis neighbor' command */ int show_isis_neighbor_common (struct vty *vty, const char *id, char detail) { struct listnode *anode, *cnode, *node; struct isis_area *area; struct isis_circuit *circuit; struct list *adjdb; struct isis_adjacency *adj; struct isis_dynhn *dynhn; u_char sysid[ISIS_SYS_ID_LEN]; int i; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } memset (sysid, 0, ISIS_SYS_ID_LEN); if (id) { if (sysid2buff (sysid, id) == 0) { dynhn = dynhn_find_by_name (id); if (dynhn == NULL) { vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); return CMD_SUCCESS; } memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { vty_out (vty, "Area %s:%s", area->area_tag, VTY_NEWLINE); if (detail == ISIS_UI_LEVEL_BRIEF) vty_out (vty, " System Id Interface L State" " Holdtime SNPA%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (i = 0; i < 2; i++) { adjdb = circuit->u.bc.adjdb[i]; if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty (adj, vty, detail); } } } else if (circuit->circ_type == CIRCUIT_T_P2P && circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_print_vty (adj, vty, detail); } } } return CMD_SUCCESS; } /* * 'clear isis neighbor' command */ int clear_isis_neighbor_common (struct vty *vty, const char *id) { struct listnode *anode, *cnode, *cnextnode, *node, *nnode; struct isis_area *area; struct isis_circuit *circuit; struct list *adjdb; struct isis_adjacency *adj; struct isis_dynhn *dynhn; u_char sysid[ISIS_SYS_ID_LEN]; int i; if (!isis) { vty_out (vty, "IS-IS Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } memset (sysid, 0, ISIS_SYS_ID_LEN); if (id) { if (sysid2buff (sysid, id) == 0) { dynhn = dynhn_find_by_name (id); if (dynhn == NULL) { vty_out (vty, "Invalid system id %s%s", id, VTY_NEWLINE); return CMD_SUCCESS; } memcpy (sysid, dynhn->id, ISIS_SYS_ID_LEN); } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, anode, area)) { for (ALL_LIST_ELEMENTS (area->circuit_list, cnode, cnextnode, circuit)) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (i = 0; i < 2; i++) { adjdb = circuit->u.bc.adjdb[i]; if (adjdb && adjdb->count) { for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj)) if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_state_change (adj, ISIS_ADJ_DOWN, "clear user request"); } } } else if (circuit->circ_type == CIRCUIT_T_P2P && circuit->u.p2p.neighbor) { adj = circuit->u.p2p.neighbor; if (!id || !memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) isis_adj_state_change (adj, ISIS_ADJ_DOWN, "clear user request"); } } } return CMD_SUCCESS; } DEFUN (show_isis_neighbor, show_isis_neighbor_cmd, "show isis neighbor", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n") { return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_isis_neighbor_detail, show_isis_neighbor_detail_cmd, "show isis neighbor detail", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "show detailed information\n") { return show_isis_neighbor_common (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_isis_neighbor_arg, show_isis_neighbor_arg_cmd, "show isis neighbor WORD", SHOW_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") { return show_isis_neighbor_common (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } DEFUN (clear_isis_neighbor, clear_isis_neighbor_cmd, "clear isis neighbor", CLEAR_STR "Reset ISIS network information\n" "Reset ISIS neighbor adjacencies\n") { return clear_isis_neighbor_common (vty, NULL); } DEFUN (clear_isis_neighbor_arg, clear_isis_neighbor_arg_cmd, "clear isis neighbor WORD", CLEAR_STR "ISIS network information\n" "ISIS neighbor adjacencies\n" "System id\n") { return clear_isis_neighbor_common (vty, argv[0]); } /* * 'isis debug', 'show debugging' */ void print_debug (struct vty *vty, int flags, int onoff) { char onoffs[4]; if (onoff) strcpy (onoffs, "on"); else strcpy (onoffs, "off"); if (flags & DEBUG_ADJ_PACKETS) vty_out (vty, "IS-IS Adjacency related packets debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_CHECKSUM_ERRORS) vty_out (vty, "IS-IS checksum errors debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_LOCAL_UPDATES) vty_out (vty, "IS-IS local updates debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_PROTOCOL_ERRORS) vty_out (vty, "IS-IS protocol errors debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SNP_PACKETS) vty_out (vty, "IS-IS CSNP/PSNP packets debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_EVENTS) vty_out (vty, "IS-IS SPF events debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_STATS) vty_out (vty, "IS-IS SPF Timing and Statistics Data debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_SPF_TRIGGERS) vty_out (vty, "IS-IS SPF triggering events debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_UPDATE_PACKETS) vty_out (vty, "IS-IS Update related packet debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_RTE_EVENTS) vty_out (vty, "IS-IS Route related debuggin is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_EVENTS) vty_out (vty, "IS-IS Event debugging is %s%s", onoffs, VTY_NEWLINE); if (flags & DEBUG_PACKET_DUMP) vty_out (vty, "IS-IS Packet dump debugging is %s%s", onoffs, VTY_NEWLINE); } DEFUN (show_debugging, show_debugging_cmd, "show debugging", SHOW_STR "State of each debugging option\n") { vty_out (vty, "IS-IS:%s", VTY_NEWLINE); print_debug (vty, isis->debugs, 1); return CMD_SUCCESS; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", 1 }; static int config_write_debug (struct vty *vty) { int write = 0; int flags = isis->debugs; if (flags & DEBUG_ADJ_PACKETS) { vty_out (vty, "debug isis adj-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_CHECKSUM_ERRORS) { vty_out (vty, "debug isis checksum-errors%s", VTY_NEWLINE); write++; } if (flags & DEBUG_LOCAL_UPDATES) { vty_out (vty, "debug isis local-updates%s", VTY_NEWLINE); write++; } if (flags & DEBUG_PROTOCOL_ERRORS) { vty_out (vty, "debug isis protocol-errors%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SNP_PACKETS) { vty_out (vty, "debug isis snp-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_EVENTS) { vty_out (vty, "debug isis spf-events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_STATS) { vty_out (vty, "debug isis spf-statistics%s", VTY_NEWLINE); write++; } if (flags & DEBUG_SPF_TRIGGERS) { vty_out (vty, "debug isis spf-triggers%s", VTY_NEWLINE); write++; } if (flags & DEBUG_UPDATE_PACKETS) { vty_out (vty, "debug isis update-packets%s", VTY_NEWLINE); write++; } if (flags & DEBUG_RTE_EVENTS) { vty_out (vty, "debug isis route-events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_EVENTS) { vty_out (vty, "debug isis events%s", VTY_NEWLINE); write++; } if (flags & DEBUG_PACKET_DUMP) { vty_out (vty, "debug isis packet-dump%s", VTY_NEWLINE); write++; } return write; } DEFUN (debug_isis_adj, debug_isis_adj_cmd, "debug isis adj-packets", DEBUG_STR "IS-IS information\n" "IS-IS Adjacency related packets\n") { isis->debugs |= DEBUG_ADJ_PACKETS; print_debug (vty, DEBUG_ADJ_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_adj, no_debug_isis_adj_cmd, "no debug isis adj-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS Adjacency related packets\n") { isis->debugs &= ~DEBUG_ADJ_PACKETS; print_debug (vty, DEBUG_ADJ_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_csum, debug_isis_csum_cmd, "debug isis checksum-errors", DEBUG_STR "IS-IS information\n" "IS-IS LSP checksum errors\n") { isis->debugs |= DEBUG_CHECKSUM_ERRORS; print_debug (vty, DEBUG_CHECKSUM_ERRORS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_csum, no_debug_isis_csum_cmd, "no debug isis checksum-errors", UNDEBUG_STR "IS-IS information\n" "IS-IS LSP checksum errors\n") { isis->debugs &= ~DEBUG_CHECKSUM_ERRORS; print_debug (vty, DEBUG_CHECKSUM_ERRORS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_lupd, debug_isis_lupd_cmd, "debug isis local-updates", DEBUG_STR "IS-IS information\n" "IS-IS local update packets\n") { isis->debugs |= DEBUG_LOCAL_UPDATES; print_debug (vty, DEBUG_LOCAL_UPDATES, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_lupd, no_debug_isis_lupd_cmd, "no debug isis local-updates", UNDEBUG_STR "IS-IS information\n" "IS-IS local update packets\n") { isis->debugs &= ~DEBUG_LOCAL_UPDATES; print_debug (vty, DEBUG_LOCAL_UPDATES, 0); return CMD_SUCCESS; } DEFUN (debug_isis_err, debug_isis_err_cmd, "debug isis protocol-errors", DEBUG_STR "IS-IS information\n" "IS-IS LSP protocol errors\n") { isis->debugs |= DEBUG_PROTOCOL_ERRORS; print_debug (vty, DEBUG_PROTOCOL_ERRORS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_err, no_debug_isis_err_cmd, "no debug isis protocol-errors", UNDEBUG_STR "IS-IS information\n" "IS-IS LSP protocol errors\n") { isis->debugs &= ~DEBUG_PROTOCOL_ERRORS; print_debug (vty, DEBUG_PROTOCOL_ERRORS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_snp, debug_isis_snp_cmd, "debug isis snp-packets", DEBUG_STR "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") { isis->debugs |= DEBUG_SNP_PACKETS; print_debug (vty, DEBUG_SNP_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_snp, no_debug_isis_snp_cmd, "no debug isis snp-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS CSNP/PSNP packets\n") { isis->debugs &= ~DEBUG_SNP_PACKETS; print_debug (vty, DEBUG_SNP_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_upd, debug_isis_upd_cmd, "debug isis update-packets", DEBUG_STR "IS-IS information\n" "IS-IS Update related packets\n") { isis->debugs |= DEBUG_UPDATE_PACKETS; print_debug (vty, DEBUG_UPDATE_PACKETS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_upd, no_debug_isis_upd_cmd, "no debug isis update-packets", UNDEBUG_STR "IS-IS information\n" "IS-IS Update related packets\n") { isis->debugs &= ~DEBUG_UPDATE_PACKETS; print_debug (vty, DEBUG_UPDATE_PACKETS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spfevents, debug_isis_spfevents_cmd, "debug isis spf-events", DEBUG_STR "IS-IS information\n" "IS-IS Shortest Path First Events\n") { isis->debugs |= DEBUG_SPF_EVENTS; print_debug (vty, DEBUG_SPF_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spfevents, no_debug_isis_spfevents_cmd, "no debug isis spf-events", UNDEBUG_STR "IS-IS information\n" "IS-IS Shortest Path First Events\n") { isis->debugs &= ~DEBUG_SPF_EVENTS; print_debug (vty, DEBUG_SPF_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spfstats, debug_isis_spfstats_cmd, "debug isis spf-statistics ", DEBUG_STR "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") { isis->debugs |= DEBUG_SPF_STATS; print_debug (vty, DEBUG_SPF_STATS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spfstats, no_debug_isis_spfstats_cmd, "no debug isis spf-statistics", UNDEBUG_STR "IS-IS information\n" "IS-IS SPF Timing and Statistic Data\n") { isis->debugs &= ~DEBUG_SPF_STATS; print_debug (vty, DEBUG_SPF_STATS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_spftrigg, debug_isis_spftrigg_cmd, "debug isis spf-triggers", DEBUG_STR "IS-IS information\n" "IS-IS SPF triggering events\n") { isis->debugs |= DEBUG_SPF_TRIGGERS; print_debug (vty, DEBUG_SPF_TRIGGERS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_spftrigg, no_debug_isis_spftrigg_cmd, "no debug isis spf-triggers", UNDEBUG_STR "IS-IS information\n" "IS-IS SPF triggering events\n") { isis->debugs &= ~DEBUG_SPF_TRIGGERS; print_debug (vty, DEBUG_SPF_TRIGGERS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_rtevents, debug_isis_rtevents_cmd, "debug isis route-events", DEBUG_STR "IS-IS information\n" "IS-IS Route related events\n") { isis->debugs |= DEBUG_RTE_EVENTS; print_debug (vty, DEBUG_RTE_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_rtevents, no_debug_isis_rtevents_cmd, "no debug isis route-events", UNDEBUG_STR "IS-IS information\n" "IS-IS Route related events\n") { isis->debugs &= ~DEBUG_RTE_EVENTS; print_debug (vty, DEBUG_RTE_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_events, debug_isis_events_cmd, "debug isis events", DEBUG_STR "IS-IS information\n" "IS-IS Events\n") { isis->debugs |= DEBUG_EVENTS; print_debug (vty, DEBUG_EVENTS, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_events, no_debug_isis_events_cmd, "no debug isis events", UNDEBUG_STR "IS-IS information\n" "IS-IS Events\n") { isis->debugs &= ~DEBUG_EVENTS; print_debug (vty, DEBUG_EVENTS, 0); return CMD_SUCCESS; } DEFUN (debug_isis_packet_dump, debug_isis_packet_dump_cmd, "debug isis packet-dump", DEBUG_STR "IS-IS information\n" "IS-IS packet dump\n") { isis->debugs |= DEBUG_PACKET_DUMP; print_debug (vty, DEBUG_PACKET_DUMP, 1); return CMD_SUCCESS; } DEFUN (no_debug_isis_packet_dump, no_debug_isis_packet_dump_cmd, "no debug isis packet-dump", UNDEBUG_STR "IS-IS information\n" "IS-IS packet dump\n") { isis->debugs &= ~DEBUG_PACKET_DUMP; print_debug (vty, DEBUG_PACKET_DUMP, 0); return CMD_SUCCESS; } DEFUN (show_hostname, show_hostname_cmd, "show isis hostname", SHOW_STR "IS-IS information\n" "IS-IS Dynamic hostname mapping\n") { dynhn_print_all (vty); return CMD_SUCCESS; } static void vty_out_timestr(struct vty *vty, time_t uptime) { struct tm *tm; time_t difftime = time (NULL); difftime -= uptime; tm = gmtime (&difftime); #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (difftime < ONE_DAY_SECOND) vty_out (vty, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (difftime < ONE_WEEK_SECOND) vty_out (vty, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else vty_out (vty, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); vty_out (vty, " ago"); } DEFUN (show_isis_summary, show_isis_summary_cmd, "show isis summary", SHOW_STR "IS-IS information\n" "IS-IS summary\n") { struct listnode *node, *node2; struct isis_area *area; struct isis_spftree *spftree; int level; if (isis == NULL) { vty_out (vty, "ISIS is not running%s", VTY_NEWLINE); return CMD_SUCCESS; } vty_out (vty, "Process Id : %ld%s", isis->process_id, VTY_NEWLINE); if (isis->sysid_set) vty_out (vty, "System Id : %s%s", sysid_print (isis->sysid), VTY_NEWLINE); vty_out (vty, "Up time : "); vty_out_timestr(vty, isis->uptime); vty_out (vty, "%s", VTY_NEWLINE); if (isis->area_list) vty_out (vty, "Number of areas : %d%s", isis->area_list->count, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); if (listcount (area->area_addrs) > 0) { struct area_addr *area_addr; for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr)) { vty_out (vty, " Net: %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len + ISIS_SYS_ID_LEN + 1), VTY_NEWLINE); } } for (level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((area->is_type & level) == 0) continue; vty_out (vty, " Level-%d:%s", level, VTY_NEWLINE); spftree = area->spftree[level - 1]; if (spftree->pending) vty_out (vty, " IPv4 SPF: (pending)%s", VTY_NEWLINE); else vty_out (vty, " IPv4 SPF:%s", VTY_NEWLINE); vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); vty_out (vty, " last run elapsed : "); vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " last run duration : %u usec%s", (u_int32_t)spftree->last_run_duration, VTY_NEWLINE); vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); #ifdef HAVE_IPV6 spftree = area->spftree6[level - 1]; if (spftree->pending) vty_out (vty, " IPv6 SPF: (pending)%s", VTY_NEWLINE); else vty_out (vty, " IPv6 SPF:%s", VTY_NEWLINE); vty_out (vty, " minimum interval : %d%s", area->min_spf_interval[level - 1], VTY_NEWLINE); vty_out (vty, " last run elapsed : "); vty_out_timestr(vty, spftree->last_run_timestamp); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " last run duration : %u msec%s", spftree->last_run_duration, VTY_NEWLINE); vty_out (vty, " run count : %d%s", spftree->runcount, VTY_NEWLINE); #endif } } vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } /* * This function supports following display options: * [ show isis database [detail] ] * [ show isis database [detail] ] * [ show isis database [detail] ] * [ show isis database . [detail] ] * [ show isis database . [detail] ] * [ show isis database .- [detail] ] * [ show isis database .- [detail] ] * [ show isis database detail ] * [ show isis database detail ] * [ show isis database detail . ] * [ show isis database detail . ] * [ show isis database detail .- ] * [ show isis database detail .- ] */ static int show_isis_database (struct vty *vty, const char *argv, int ui_level) { struct listnode *node; struct isis_area *area; struct isis_lsp *lsp; struct isis_dynhn *dynhn; const char *pos = argv; u_char lspid[ISIS_SYS_ID_LEN+2]; char sysid[255]; u_char number[3]; int level, lsp_count; if (isis->area_list->count == 0) return CMD_SUCCESS; memset (&lspid, 0, ISIS_SYS_ID_LEN); memset (&sysid, 0, 255); /* * extract fragment and pseudo id from the string argv * in the forms: * (a) .- or * (b) . or * (c) or * Where systemid is in the form: * xxxx.xxxx.xxxx */ if (argv) strncpy (sysid, argv, 254); if (argv && strlen (argv) > 3) { pos = argv + strlen (argv) - 3; if (strncmp (pos, "-", 1) == 0) { memcpy (number, ++pos, 2); lspid[ISIS_SYS_ID_LEN+1] = (u_char) strtol ((char *)number, NULL, 16); pos -= 4; if (strncmp (pos, ".", 1) != 0) return CMD_ERR_AMBIGUOUS; } if (strncmp (pos, ".", 1) == 0) { memcpy (number, ++pos, 2); lspid[ISIS_SYS_ID_LEN] = (u_char) strtol ((char *)number, NULL, 16); sysid[pos - argv - 1] = '\0'; } } for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { vty_out (vty, "Area %s:%s", area->area_tag ? area->area_tag : "null", VTY_NEWLINE); for (level = 0; level < ISIS_LEVELS; level++) { if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) { lsp = NULL; if (argv != NULL) { /* * Try to find the lsp-id if the argv string is in * the form hostname.- */ if (sysid2buff (lspid, sysid)) { lsp = lsp_search (lspid, area->lspdb[level]); } else if ((dynhn = dynhn_find_by_name (sysid))) { memcpy (lspid, dynhn->id, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, area->lspdb[level]); } else if (strncmp(unix_hostname (), sysid, 15) == 0) { memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, area->lspdb[level]); } } if (lsp != NULL || argv == NULL) { vty_out (vty, "IS-IS Level-%d link-state database:%s", level + 1, VTY_NEWLINE); /* print the title in all cases */ vty_out (vty, "LSP ID PduLen " "SeqNumber Chksum Holdtime ATT/P/OL%s", VTY_NEWLINE); } if (lsp) { if (ui_level == ISIS_UI_LEVEL_DETAIL) lsp_print_detail (lsp, vty, area->dynhostname); else lsp_print (lsp, vty, area->dynhostname); } else if (argv == NULL) { lsp_count = lsp_print_all (vty, area->lspdb[level], ui_level, area->dynhostname); vty_out (vty, " %u LSPs%s%s", lsp_count, VTY_NEWLINE, VTY_NEWLINE); } } } } return CMD_SUCCESS; } DEFUN (show_database_brief, show_database_cmd, "show isis database", SHOW_STR "IS-IS information\n" "IS-IS link state database\n") { return show_isis_database (vty, NULL, ISIS_UI_LEVEL_BRIEF); } DEFUN (show_database_lsp_brief, show_database_arg_cmd, "show isis database WORD", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_BRIEF); } DEFUN (show_database_lsp_detail, show_database_arg_detail_cmd, "show isis database WORD detail", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "LSP ID\n" "Detailed information\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } DEFUN (show_database_detail, show_database_detail_cmd, "show isis database detail", SHOW_STR "IS-IS information\n" "IS-IS link state database\n") { return show_isis_database (vty, NULL, ISIS_UI_LEVEL_DETAIL); } DEFUN (show_database_detail_lsp, show_database_detail_arg_cmd, "show isis database detail WORD", SHOW_STR "IS-IS information\n" "IS-IS link state database\n" "Detailed information\n" "LSP ID\n") { return show_isis_database (vty, argv[0], ISIS_UI_LEVEL_DETAIL); } /* * 'router isis' command */ DEFUN (router_isis, router_isis_cmd, "router isis WORD", ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { return isis_area_get (vty, argv[0]); } /* *'no router isis' command */ DEFUN (no_router_isis, no_router_isis_cmd, "no router isis WORD", "no\n" ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag") { return isis_area_destroy (vty, argv[0]); } /* * 'net' command */ DEFUN (net, net_cmd, "net WORD", "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { return area_net_title (vty, argv[0]); } /* * 'no net' command */ DEFUN (no_net, no_net_cmd, "no net WORD", NO_STR "A Network Entity Title for this process (OSI only)\n" "XX.XXXX. ... .XXX.XX Network entity title (NET)\n") { return area_clear_net_title (vty, argv[0]); } DEFUN (area_passwd_md5, area_passwd_md5_cmd, "area-password md5 WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (area_passwd_md5, area_passwd_md5_snpauth_cmd, "area-password md5 WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n"); DEFUN (area_passwd_clear, area_passwd_clear_cmd, "area-password clear WORD", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->area_passwd.len = (u_char) len; area->area_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->area_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (area_passwd_clear, area_passwd_clear_snpauth_cmd, "area-password clear WORD authenticate snp (send-only|validate)", "Configure the authentication password for an area\n" "Authentication type\n" "Area password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n"); DEFUN (no_area_passwd, no_area_passwd_cmd, "no area-password", NO_STR "Configure the authentication password for an area\n") { struct isis_area *area; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } memset (&area->area_passwd, 0, sizeof (struct isis_passwd)); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (domain_passwd_md5, domain_passwd_md5_cmd, "domain-password md5 WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (domain_passwd_md5, domain_passwd_md5_snpauth_cmd, "domain-password md5 WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n"); DEFUN (domain_passwd_clear, domain_passwd_clear_cmd, "domain-password clear WORD", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n") { struct isis_area *area; int len; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long area password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } area->domain_passwd.len = (u_char) len; area->domain_passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)area->domain_passwd.passwd, argv[0], 255); if (argc > 1) { SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); if (strncmp(argv[1], "v", 1) == 0) SET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); else UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } else { UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND); UNSET_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV); } lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } ALIAS (domain_passwd_clear, domain_passwd_clear_snpauth_cmd, "domain-password clear WORD authenticate snp (send-only|validate)", "Set the authentication password for a routing domain\n" "Authentication type\n" "Routing domain password\n" "Authentication\n" "SNP PDUs\n" "Send but do not check PDUs on receiving\n" "Send and check PDUs on receiving\n"); DEFUN (no_domain_passwd, no_domain_passwd_cmd, "no domain-password", NO_STR "Set the authentication password for a routing domain\n") { struct isis_area *area; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } memset (&area->domain_passwd, 0, sizeof (struct isis_passwd)); lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (is_type, is_type_cmd, "is-type (level-1|level-1-2|level-2-only)", "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") { struct isis_area *area; int type; area = vty->index; if (!area) { vty_out (vty, "Can't find IS-IS instance%s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } type = string2circuit_t (argv[0]); if (!type) { vty_out (vty, "Unknown IS level %s", VTY_NEWLINE); return CMD_SUCCESS; } isis_event_system_type_change (area, type); return CMD_SUCCESS; } DEFUN (no_is_type, no_is_type_cmd, "no is-type (level-1|level-1-2|level-2-only)", NO_STR "IS Level for this routing process (OSI only)\n" "Act as a station router only\n" "Act as both a station router and an area router\n" "Act as an area router only\n") { struct isis_area *area; int type; area = vty->index; assert (area); /* * Put the is-type back to defaults: * - level-1-2 on first area * - level-1 for the rest */ if (listgetdata (listhead (isis->area_list)) == area) type = IS_LEVEL_1_AND_2; else type = IS_LEVEL_1; isis_event_system_type_change (area, type); return CMD_SUCCESS; } static int set_lsp_gen_interval (struct vty *vty, struct isis_area *area, uint16_t interval, int level) { int lvl; for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; if (interval >= area->lsp_refresh[lvl-1]) { vty_out (vty, "LSP gen interval %us must be less than " "the LSP refresh interval %us%s", interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; area->lsp_gen_interval[lvl-1] = interval; } return CMD_SUCCESS; } DEFUN (lsp_gen_interval, lsp_gen_interval_cmd, "lsp-gen-interval <1-120>", "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval, no_lsp_gen_interval_cmd, "no lsp-gen-interval", NO_STR "Minimum interval between regenerating same LSP\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval, no_lsp_gen_interval_arg_cmd, "no lsp-gen-interval <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Minimum interval in seconds\n") DEFUN (lsp_gen_interval_l1, lsp_gen_interval_l1_cmd, "lsp-gen-interval level-1 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l1, no_lsp_gen_interval_l1_cmd, "no lsp-gen-interval level-1", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_1; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l1, no_lsp_gen_interval_l1_arg_cmd, "no lsp-gen-interval level-1 <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 1 only\n" "Minimum interval in seconds\n") DEFUN (lsp_gen_interval_l2, lsp_gen_interval_l2_cmd, "lsp-gen-interval level-2 <1-120>", "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } DEFUN (no_lsp_gen_interval_l2, no_lsp_gen_interval_l2_cmd, "no lsp-gen-interval level-2", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MIN_LSP_GEN_INTERVAL; level = IS_LEVEL_2; return set_lsp_gen_interval (vty, area, interval, level); } ALIAS (no_lsp_gen_interval_l2, no_lsp_gen_interval_l2_arg_cmd, "no lsp-gen-interval level-2 <1-120>", NO_STR "Minimum interval between regenerating same LSP\n" "Set interval for level 2 only\n" "Minimum interval in seconds\n") static int validate_metric_style_narrow (struct vty *vty, struct isis_area *area) { struct isis_circuit *circuit; struct listnode *node; if (! vty) return CMD_ERR_AMBIGUOUS; if (! area) { vty_out (vty, "ISIS area is invalid%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { if ((area->is_type & IS_LEVEL_1) && (circuit->is_type & IS_LEVEL_1) && (circuit->te_metric[0] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if ((area->is_type & IS_LEVEL_2) && (circuit->is_type & IS_LEVEL_2) && (circuit->te_metric[1] > MAX_NARROW_LINK_METRIC)) { vty_out (vty, "ISIS circuit %s metric is invalid%s", circuit->interface->name, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } return CMD_SUCCESS; } DEFUN (metric_style, metric_style_cmd, "metric-style (narrow|transition|wide)", "Use old-style (ISO 10589) or new-style packet formats\n" "Use old style of TLVs with narrow metric\n" "Send and accept both styles of TLVs during transition\n" "Use new style of TLVs to carry wider metric\n") { struct isis_area *area; int ret; area = vty->index; assert (area); if (strncmp (argv[0], "w", 1) == 0) { area->newmetric = 1; area->oldmetric = 0; } else { ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; if (strncmp (argv[0], "t", 1) == 0) { area->newmetric = 1; area->oldmetric = 1; } else if (strncmp (argv[0], "n", 1) == 0) { area->newmetric = 0; area->oldmetric = 1; } } return CMD_SUCCESS; } DEFUN (no_metric_style, no_metric_style_cmd, "no metric-style", NO_STR "Use old-style (ISO 10589) or new-style packet formats\n") { struct isis_area *area; int ret; area = vty->index; assert (area); ret = validate_metric_style_narrow (vty, area); if (ret != CMD_SUCCESS) return ret; /* Default is narrow metric. */ area->newmetric = 0; area->oldmetric = 1; return CMD_SUCCESS; } DEFUN (set_overload_bit, set_overload_bit_cmd, "set-overload-bit", "Set overload bit to avoid any transit traffic\n" "Set overload bit\n") { struct isis_area *area; area = vty->index; assert (area); area->overload_bit = LSPBIT_OL; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (no_set_overload_bit, no_set_overload_bit_cmd, "no set-overload-bit", "Reset overload bit to accept transit traffic\n" "Reset overload bit\n") { struct isis_area *area; area = vty->index; assert (area); area->overload_bit = 0; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); return CMD_SUCCESS; } DEFUN (dynamic_hostname, dynamic_hostname_cmd, "hostname dynamic", "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") { struct isis_area *area; area = vty->index; assert (area); if (!area->dynhostname) { area->dynhostname = 1; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); } return CMD_SUCCESS; } DEFUN (no_dynamic_hostname, no_dynamic_hostname_cmd, "no hostname dynamic", NO_STR "Dynamic hostname for IS-IS\n" "Dynamic hostname\n") { struct isis_area *area; area = vty->index; assert (area); if (area->dynhostname) { area->dynhostname = 0; lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 0); } return CMD_SUCCESS; } DEFUN (spf_interval, spf_interval_cmd, "spf-interval <1-120>", "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[0] = interval; area->min_spf_interval[1] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval, no_spf_interval_cmd, "no spf-interval", NO_STR "Minimum interval between SPF calculations\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_arg_cmd, "no spf-interval <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Minimum interval between consecutive SPFs in seconds\n") DEFUN (spf_interval_l1, spf_interval_l1_cmd, "spf-interval level-1 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[0] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval_l1, no_spf_interval_l1_cmd, "no spf-interval level-1", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[0] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_l1_arg_cmd, "no spf-interval level-1 <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 1 only\n" "Minimum interval between consecutive SPFs in seconds\n") DEFUN (spf_interval_l2, spf_interval_l2_cmd, "spf-interval level-2 <1-120>", "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") { struct isis_area *area; u_int16_t interval; area = vty->index; interval = atoi (argv[0]); area->min_spf_interval[1] = interval; return CMD_SUCCESS; } DEFUN (no_spf_interval_l2, no_spf_interval_l2_cmd, "no spf-interval level-2", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n") { struct isis_area *area; area = vty->index; area->min_spf_interval[1] = MINIMUM_SPF_INTERVAL; return CMD_SUCCESS; } ALIAS (no_spf_interval, no_spf_interval_l2_arg_cmd, "no spf-interval level-2 <1-120>", NO_STR "Minimum interval between SPF calculations\n" "Set interval for level 2 only\n" "Minimum interval between consecutive SPFs in seconds\n") static int set_lsp_max_lifetime (struct vty *vty, struct isis_area *area, uint16_t interval, int level) { int lvl; int set_refresh_interval[ISIS_LEVELS] = {0, 0}; uint16_t refresh_interval; refresh_interval = interval - 300; for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!(lvl & level)) continue; if (refresh_interval < area->lsp_refresh[lvl-1]) { vty_out (vty, "Level %d Max LSP lifetime %us must be 300s greater than " "the configured LSP refresh interval %us%s", lvl, interval, area->lsp_refresh[lvl-1], VTY_NEWLINE); vty_out (vty, "Automatically reducing level %d LSP refresh interval " "to %us%s", lvl, refresh_interval, VTY_NEWLINE); set_refresh_interval[lvl-1] = 1; if (refresh_interval <= area->lsp_gen_interval[lvl-1]) { vty_out (vty, "LSP refresh interval %us must be greater than " "the configured LSP gen interval %us%s", refresh_interval, area->lsp_gen_interval[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!(lvl & level)) continue; area->max_lsp_lifetime[lvl-1] = interval; /* Automatically reducing lsp_refresh_interval to interval - 300 */ if (set_refresh_interval[lvl-1]) area->lsp_refresh[lvl-1] = refresh_interval; } lsp_regenerate_schedule (area, level, 1); return CMD_SUCCESS; } DEFUN (max_lsp_lifetime, max_lsp_lifetime_cmd, "max-lsp-lifetime <350-65535>", "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } DEFUN (no_max_lsp_lifetime, no_max_lsp_lifetime_cmd, "no max-lsp-lifetime", NO_STR "LSP lifetime in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } ALIAS (no_max_lsp_lifetime, no_max_lsp_lifetime_arg_cmd, "no max-lsp-lifetime <350-65535>", NO_STR "Maximum LSP lifetime\n" "LSP lifetime in seconds\n") DEFUN (max_lsp_lifetime_l1, max_lsp_lifetime_l1_cmd, "max-lsp-lifetime level-1 <350-65535>", "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_max_lifetime (vty, area, interval, level); } DEFUN (no_max_lsp_lifetime_l1, no_max_lsp_lifetime_l1_cmd, "no max-lsp-lifetime level-1", NO_STR "LSP lifetime for Level 1 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_1; return set_lsp_max_lifetime (vty, area, interval, level); } ALIAS (no_max_lsp_lifetime_l1, no_max_lsp_lifetime_l1_arg_cmd, "no max-lsp-lifetime level-1 <350-65535>", NO_STR "Maximum LSP lifetime for Level 1 only\n" "LSP lifetime for Level 1 only in seconds\n") DEFUN (max_lsp_lifetime_l2, max_lsp_lifetime_l2_cmd, "max-lsp-lifetime level-2 <350-65535>", "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } DEFUN (no_max_lsp_lifetime_l2, no_max_lsp_lifetime_l2_cmd, "no max-lsp-lifetime level-2", NO_STR "LSP lifetime for Level 2 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_LSP_LIFETIME; level = IS_LEVEL_2; return set_lsp_max_lifetime (vty, area, interval, level); } ALIAS (no_max_lsp_lifetime_l2, no_max_lsp_lifetime_l2_arg_cmd, "no max-lsp-lifetime level-2 <350-65535>", NO_STR "Maximum LSP lifetime for Level 2 only\n" "LSP lifetime for Level 2 only in seconds\n") static int set_lsp_refresh_interval (struct vty *vty, struct isis_area *area, uint16_t interval, int level) { int lvl; for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; if (interval <= area->lsp_gen_interval[lvl-1]) { vty_out (vty, "LSP refresh interval %us must be greater than " "the configured LSP gen interval %us%s", interval, area->lsp_gen_interval[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (interval > (area->max_lsp_lifetime[lvl-1] - 300)) { vty_out (vty, "LSP refresh interval %us must be less than " "the configured LSP lifetime %us less 300%s", interval, area->max_lsp_lifetime[lvl-1], VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } } for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (!(lvl & level)) continue; area->lsp_refresh[lvl-1] = interval; } lsp_regenerate_schedule (area, level, 1); return CMD_SUCCESS; } DEFUN (lsp_refresh_interval, lsp_refresh_interval_cmd, "lsp-refresh-interval <1-65235>", "LSP refresh interval\n" "LSP refresh interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } DEFUN (no_lsp_refresh_interval, no_lsp_refresh_interval_cmd, "no lsp-refresh-interval", NO_STR "LSP refresh interval in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_1 | IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } ALIAS (no_lsp_refresh_interval, no_lsp_refresh_interval_arg_cmd, "no lsp-refresh-interval <1-65235>", NO_STR "LSP refresh interval\n" "LSP refresh interval in seconds\n") DEFUN (lsp_refresh_interval_l1, lsp_refresh_interval_l1_cmd, "lsp-refresh-interval level-1 <1-65235>", "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_1; return set_lsp_refresh_interval (vty, area, interval, level); } DEFUN (no_lsp_refresh_interval_l1, no_lsp_refresh_interval_l1_cmd, "no lsp-refresh-interval level-1", NO_STR "LSP refresh interval for Level 1 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_1; return set_lsp_refresh_interval (vty, area, interval, level); } ALIAS (no_lsp_refresh_interval_l1, no_lsp_refresh_interval_l1_arg_cmd, "no lsp-refresh-interval level-1 <1-65235>", NO_STR "LSP refresh interval for Level 1 only\n" "LSP refresh interval for Level 1 only in seconds\n") DEFUN (lsp_refresh_interval_l2, lsp_refresh_interval_l2_cmd, "lsp-refresh-interval level-2 <1-65235>", "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = atoi (argv[0]); level = IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } DEFUN (no_lsp_refresh_interval_l2, no_lsp_refresh_interval_l2_cmd, "no lsp-refresh-interval level-2", NO_STR "LSP refresh interval for Level 2 only in seconds\n") { struct isis_area *area; uint16_t interval; int level; area = vty->index; interval = DEFAULT_MAX_LSP_GEN_INTERVAL; level = IS_LEVEL_2; return set_lsp_refresh_interval (vty, area, interval, level); } ALIAS (no_lsp_refresh_interval_l2, no_lsp_refresh_interval_l2_arg_cmd, "no lsp-refresh-interval level-2 <1-65235>", NO_STR "LSP refresh interval for Level 2 only\n" "LSP refresh interval for Level 2 only in seconds\n") DEFUN (log_adj_changes, log_adj_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct isis_area *area; area = vty->index; assert (area); area->log_adj_changes = 1; return CMD_SUCCESS; } DEFUN (no_log_adj_changes, no_log_adj_changes_cmd, "no log-adjacency-changes", "Stop logging changes in adjacency state\n") { struct isis_area *area; area = vty->index; assert (area); area->log_adj_changes = 0; return CMD_SUCCESS; } #ifdef TOPOLOGY_GENERATE DEFUN (topology_generate_grid, topology_generate_grid_cmd, "topology generate grid <1-100> <1-100> <1-65000> [param] [param] " "[param]", "Topology generation for IS-IS\n" "Topology generation\n" "Grid topology\n" "X parameter of the grid\n" "Y parameter of the grid\n" "Random seed\n" "Optional param 1\n" "Optional param 2\n" "Optional param 3\n" "Topology\n") { struct isis_area *area; area = vty->index; assert (area); if (!spgrid_check_params (vty, argc, argv)) { if (area->topology) list_delete (area->topology); area->topology = list_new (); memcpy (area->top_params, vty->buf, 200); gen_spgrid_topology (vty, area->topology); remove_topology_lsps (area); generate_topology_lsps (area); /* Regenerate L1 LSP to get two way connection to the generated * topology. */ lsp_regenerate_schedule (area, IS_LEVEL_1 | IS_LEVEL_2, 1); } return CMD_SUCCESS; } DEFUN (show_isis_generated_topology, show_isis_generated_topology_cmd, "show isis generated-topologies", SHOW_STR "ISIS network information\n" "Show generated topologies\n") { struct isis_area *area; struct listnode *node; struct listnode *node2; struct arc *arc; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { if (!area->topology) continue; vty_out (vty, "Topology for isis area: %s%s", area->area_tag, VTY_NEWLINE); vty_out (vty, "From node To node Distance%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (area->topology, node2, arc)) vty_out (vty, "%9ld %11ld %12ld%s", arc->from_node, arc->to_node, arc->distance, VTY_NEWLINE); } return CMD_SUCCESS; } /* Base IS for topology generation. */ DEFUN (topology_baseis, topology_baseis_cmd, "topology base-is WORD", "Topology generation for IS-IS\n" "A Network IS Base for this topology\n" "XXXX.XXXX.XXXX Network entity title (NET)\n") { struct isis_area *area; u_char buff[ISIS_SYS_ID_LEN]; area = vty->index; assert (area); if (sysid2buff (buff, argv[0])) sysid2buff (area->topology_baseis, argv[0]); return CMD_SUCCESS; } DEFUN (no_topology_baseis, no_topology_baseis_cmd, "no topology base-is WORD", NO_STR "Topology generation for IS-IS\n" "A Network IS Base for this topology\n" "XXXX.XXXX.XXXX Network entity title (NET)\n") { struct isis_area *area; area = vty->index; assert (area); memcpy (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN); return CMD_SUCCESS; } ALIAS (no_topology_baseis, no_topology_baseis_noid_cmd, "no topology base-is", NO_STR "Topology generation for IS-IS\n" "A Network IS Base for this topology\n") DEFUN (topology_basedynh, topology_basedynh_cmd, "topology base-dynh WORD", "Topology generation for IS-IS\n" "Dynamic hostname base for this topology\n" "Dynamic hostname base\n") { struct isis_area *area; area = vty->index; assert (area); /* I hope that it's enough. */ area->topology_basedynh = strndup (argv[0], 16); return CMD_SUCCESS; } #endif /* TOPOLOGY_GENERATE */ /* IS-IS configuration write function */ int isis_config_write (struct vty *vty) { int write = 0; if (isis != NULL) { struct isis_area *area; struct listnode *node, *node2; for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { /* ISIS - Area name */ vty_out (vty, "router isis %s%s", area->area_tag, VTY_NEWLINE); write++; /* ISIS - Net */ if (listcount (area->area_addrs) > 0) { struct area_addr *area_addr; for (ALL_LIST_ELEMENTS_RO (area->area_addrs, node2, area_addr)) { vty_out (vty, " net %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len + ISIS_SYS_ID_LEN + 1), VTY_NEWLINE); write++; } } /* ISIS - Dynamic hostname - Defaults to true so only display if * false. */ if (!area->dynhostname) { vty_out (vty, " no hostname dynamic%s", VTY_NEWLINE); write++; } /* ISIS - Metric-Style - when true displays wide */ if (area->newmetric) { if (!area->oldmetric) vty_out (vty, " metric-style wide%s", VTY_NEWLINE); else vty_out (vty, " metric-style transition%s", VTY_NEWLINE); write++; } else { vty_out (vty, " metric-style narrow%s", VTY_NEWLINE); write++; } /* ISIS - overload-bit */ if (area->overload_bit) { vty_out (vty, " set-overload-bit%s", VTY_NEWLINE); write++; } /* ISIS - Area is-type (level-1-2 is default) */ if (area->is_type == IS_LEVEL_1) { vty_out (vty, " is-type level-1%s", VTY_NEWLINE); write++; } else if (area->is_type == IS_LEVEL_2) { vty_out (vty, " is-type level-2-only%s", VTY_NEWLINE); write++; } /* ISIS - Lsp generation interval */ if (area->lsp_gen_interval[0] == area->lsp_gen_interval[1]) { if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); write++; } } else { if (area->lsp_gen_interval[0] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-1 %d%s", area->lsp_gen_interval[0], VTY_NEWLINE); write++; } if (area->lsp_gen_interval[1] != DEFAULT_MIN_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-gen-interval level-2 %d%s", area->lsp_gen_interval[1], VTY_NEWLINE); write++; } } /* ISIS - LSP lifetime */ if (area->max_lsp_lifetime[0] == area->max_lsp_lifetime[1]) { if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } } else { if (area->max_lsp_lifetime[0] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime level-1 %u%s", area->max_lsp_lifetime[0], VTY_NEWLINE); write++; } if (area->max_lsp_lifetime[1] != DEFAULT_LSP_LIFETIME) { vty_out (vty, " max-lsp-lifetime level-2 %u%s", area->max_lsp_lifetime[1], VTY_NEWLINE); write++; } } /* ISIS - LSP refresh interval */ if (area->lsp_refresh[0] == area->lsp_refresh[1]) { if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval %u%s", area->lsp_refresh[0], VTY_NEWLINE); write++; } } else { if (area->lsp_refresh[0] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval level-1 %u%s", area->lsp_refresh[0], VTY_NEWLINE); write++; } if (area->lsp_refresh[1] != DEFAULT_MAX_LSP_GEN_INTERVAL) { vty_out (vty, " lsp-refresh-interval level-2 %u%s", area->lsp_refresh[1], VTY_NEWLINE); write++; } } /* Minimum SPF interval. */ if (area->min_spf_interval[0] == area->min_spf_interval[1]) { if (area->min_spf_interval[0] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval %d%s", area->min_spf_interval[0], VTY_NEWLINE); write++; } } else { if (area->min_spf_interval[0] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval level-1 %d%s", area->min_spf_interval[0], VTY_NEWLINE); write++; } if (area->min_spf_interval[1] != MINIMUM_SPF_INTERVAL) { vty_out (vty, " spf-interval level-2 %d%s", area->min_spf_interval[1], VTY_NEWLINE); write++; } } /* Authentication passwords. */ if (area->area_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out(vty, " area-password md5 %s", area->area_passwd.passwd); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } else if (area->area_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out(vty, " area-password clear %s", area->area_passwd.passwd); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->area_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } if (area->domain_passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out(vty, " domain-password md5 %s", area->domain_passwd.passwd); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } else if (area->domain_passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out(vty, " domain-password clear %s", area->domain_passwd.passwd); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_SEND)) { vty_out(vty, " authenticate snp "); if (CHECK_FLAG(area->domain_passwd.snp_auth, SNP_AUTH_RECV)) vty_out(vty, "validate"); else vty_out(vty, "send-only"); } vty_out(vty, "%s", VTY_NEWLINE); write++; } if (area->log_adj_changes) { vty_out (vty, " log-adjacency-changes%s", VTY_NEWLINE); write++; } #ifdef TOPOLOGY_GENERATE if (memcmp (area->topology_baseis, DEFAULT_TOPOLOGY_BASEIS, ISIS_SYS_ID_LEN)) { vty_out (vty, " topology base-is %s%s", sysid_print ((u_char *)area->topology_baseis), VTY_NEWLINE); write++; } if (area->topology_basedynh) { vty_out (vty, " topology base-dynh %s%s", area->topology_basedynh, VTY_NEWLINE); write++; } /* We save the whole command line here. */ if (strlen(area->top_params)) { vty_out (vty, " %s%s", area->top_params, VTY_NEWLINE); write++; } #endif /* TOPOLOGY_GENERATE */ } } return write; } struct cmd_node isis_node = { ISIS_NODE, "%s(config-router)# ", 1 }; void isis_init () { /* Install IS-IS top node */ install_node (&isis_node, isis_config_write); install_element (VIEW_NODE, &show_isis_summary_cmd); install_element (VIEW_NODE, &show_isis_interface_cmd); install_element (VIEW_NODE, &show_isis_interface_detail_cmd); install_element (VIEW_NODE, &show_isis_interface_arg_cmd); install_element (VIEW_NODE, &show_isis_neighbor_cmd); install_element (VIEW_NODE, &show_isis_neighbor_detail_cmd); install_element (VIEW_NODE, &show_isis_neighbor_arg_cmd); install_element (VIEW_NODE, &clear_isis_neighbor_cmd); install_element (VIEW_NODE, &clear_isis_neighbor_arg_cmd); install_element (VIEW_NODE, &show_hostname_cmd); install_element (VIEW_NODE, &show_database_cmd); install_element (VIEW_NODE, &show_database_arg_cmd); install_element (VIEW_NODE, &show_database_arg_detail_cmd); install_element (VIEW_NODE, &show_database_detail_cmd); install_element (VIEW_NODE, &show_database_detail_arg_cmd); install_element (ENABLE_NODE, &show_isis_summary_cmd); install_element (ENABLE_NODE, &show_isis_interface_cmd); install_element (ENABLE_NODE, &show_isis_interface_detail_cmd); install_element (ENABLE_NODE, &show_isis_interface_arg_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_detail_cmd); install_element (ENABLE_NODE, &show_isis_neighbor_arg_cmd); install_element (ENABLE_NODE, &clear_isis_neighbor_cmd); install_element (ENABLE_NODE, &clear_isis_neighbor_arg_cmd); install_element (ENABLE_NODE, &show_hostname_cmd); install_element (ENABLE_NODE, &show_database_cmd); install_element (ENABLE_NODE, &show_database_arg_cmd); install_element (ENABLE_NODE, &show_database_arg_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_cmd); install_element (ENABLE_NODE, &show_database_detail_arg_cmd); install_element (ENABLE_NODE, &show_debugging_cmd); install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &debug_isis_adj_cmd); install_element (ENABLE_NODE, &no_debug_isis_adj_cmd); install_element (ENABLE_NODE, &debug_isis_csum_cmd); install_element (ENABLE_NODE, &no_debug_isis_csum_cmd); install_element (ENABLE_NODE, &debug_isis_lupd_cmd); install_element (ENABLE_NODE, &no_debug_isis_lupd_cmd); install_element (ENABLE_NODE, &debug_isis_err_cmd); install_element (ENABLE_NODE, &no_debug_isis_err_cmd); install_element (ENABLE_NODE, &debug_isis_snp_cmd); install_element (ENABLE_NODE, &no_debug_isis_snp_cmd); install_element (ENABLE_NODE, &debug_isis_upd_cmd); install_element (ENABLE_NODE, &no_debug_isis_upd_cmd); install_element (ENABLE_NODE, &debug_isis_spfevents_cmd); install_element (ENABLE_NODE, &no_debug_isis_spfevents_cmd); install_element (ENABLE_NODE, &debug_isis_spfstats_cmd); install_element (ENABLE_NODE, &no_debug_isis_spfstats_cmd); install_element (ENABLE_NODE, &debug_isis_spftrigg_cmd); install_element (ENABLE_NODE, &no_debug_isis_spftrigg_cmd); install_element (ENABLE_NODE, &debug_isis_rtevents_cmd); install_element (ENABLE_NODE, &no_debug_isis_rtevents_cmd); install_element (ENABLE_NODE, &debug_isis_events_cmd); install_element (ENABLE_NODE, &no_debug_isis_events_cmd); install_element (ENABLE_NODE, &debug_isis_packet_dump_cmd); install_element (ENABLE_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &debug_isis_adj_cmd); install_element (CONFIG_NODE, &no_debug_isis_adj_cmd); install_element (CONFIG_NODE, &debug_isis_csum_cmd); install_element (CONFIG_NODE, &no_debug_isis_csum_cmd); install_element (CONFIG_NODE, &debug_isis_lupd_cmd); install_element (CONFIG_NODE, &no_debug_isis_lupd_cmd); install_element (CONFIG_NODE, &debug_isis_err_cmd); install_element (CONFIG_NODE, &no_debug_isis_err_cmd); install_element (CONFIG_NODE, &debug_isis_snp_cmd); install_element (CONFIG_NODE, &no_debug_isis_snp_cmd); install_element (CONFIG_NODE, &debug_isis_upd_cmd); install_element (CONFIG_NODE, &no_debug_isis_upd_cmd); install_element (CONFIG_NODE, &debug_isis_spfevents_cmd); install_element (CONFIG_NODE, &no_debug_isis_spfevents_cmd); install_element (CONFIG_NODE, &debug_isis_spfstats_cmd); install_element (CONFIG_NODE, &no_debug_isis_spfstats_cmd); install_element (CONFIG_NODE, &debug_isis_spftrigg_cmd); install_element (CONFIG_NODE, &no_debug_isis_spftrigg_cmd); install_element (CONFIG_NODE, &debug_isis_rtevents_cmd); install_element (CONFIG_NODE, &no_debug_isis_rtevents_cmd); install_element (CONFIG_NODE, &debug_isis_events_cmd); install_element (CONFIG_NODE, &no_debug_isis_events_cmd); install_element (CONFIG_NODE, &debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &no_debug_isis_packet_dump_cmd); install_element (CONFIG_NODE, &router_isis_cmd); install_element (CONFIG_NODE, &no_router_isis_cmd); install_default (ISIS_NODE); install_element (ISIS_NODE, &net_cmd); install_element (ISIS_NODE, &no_net_cmd); install_element (ISIS_NODE, &is_type_cmd); install_element (ISIS_NODE, &no_is_type_cmd); install_element (ISIS_NODE, &area_passwd_md5_cmd); install_element (ISIS_NODE, &area_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &area_passwd_clear_cmd); install_element (ISIS_NODE, &area_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_area_passwd_cmd); install_element (ISIS_NODE, &domain_passwd_md5_cmd); install_element (ISIS_NODE, &domain_passwd_md5_snpauth_cmd); install_element (ISIS_NODE, &domain_passwd_clear_cmd); install_element (ISIS_NODE, &domain_passwd_clear_snpauth_cmd); install_element (ISIS_NODE, &no_domain_passwd_cmd); install_element (ISIS_NODE, &lsp_gen_interval_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_arg_cmd); install_element (ISIS_NODE, &lsp_gen_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l1_arg_cmd); install_element (ISIS_NODE, &lsp_gen_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_gen_interval_l2_arg_cmd); install_element (ISIS_NODE, &spf_interval_cmd); install_element (ISIS_NODE, &no_spf_interval_cmd); install_element (ISIS_NODE, &no_spf_interval_arg_cmd); install_element (ISIS_NODE, &spf_interval_l1_cmd); install_element (ISIS_NODE, &no_spf_interval_l1_cmd); install_element (ISIS_NODE, &no_spf_interval_l1_arg_cmd); install_element (ISIS_NODE, &spf_interval_l2_cmd); install_element (ISIS_NODE, &no_spf_interval_l2_cmd); install_element (ISIS_NODE, &no_spf_interval_l2_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_l1_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l1_arg_cmd); install_element (ISIS_NODE, &max_lsp_lifetime_l2_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_cmd); install_element (ISIS_NODE, &no_max_lsp_lifetime_l2_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l1_arg_cmd); install_element (ISIS_NODE, &lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_cmd); install_element (ISIS_NODE, &no_lsp_refresh_interval_l2_arg_cmd); install_element (ISIS_NODE, &set_overload_bit_cmd); install_element (ISIS_NODE, &no_set_overload_bit_cmd); install_element (ISIS_NODE, &dynamic_hostname_cmd); install_element (ISIS_NODE, &no_dynamic_hostname_cmd); install_element (ISIS_NODE, &metric_style_cmd); install_element (ISIS_NODE, &no_metric_style_cmd); install_element (ISIS_NODE, &log_adj_changes_cmd); install_element (ISIS_NODE, &no_log_adj_changes_cmd); #ifdef TOPOLOGY_GENERATE install_element (ISIS_NODE, &topology_generate_grid_cmd); install_element (ISIS_NODE, &topology_baseis_cmd); install_element (ISIS_NODE, &topology_basedynh_cmd); install_element (ISIS_NODE, &no_topology_baseis_cmd); install_element (ISIS_NODE, &no_topology_baseis_noid_cmd); install_element (VIEW_NODE, &show_isis_generated_topology_cmd); install_element (ENABLE_NODE, &show_isis_generated_topology_cmd); #endif /* TOPOLOGY_GENERATE */ } quagga-0.99.24.1/isisd/isis_tlv.c0000644000175000017500000010610712476520570013354 00000000000000/* * IS-IS Rout(e)ing protocol - isis_tlv.c * IS-IS TLV related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "linklist.h" #include "stream.h" #include "memory.h" #include "prefix.h" #include "vty.h" #include "if.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_pdu.h" #include "isisd/isis_lsp.h" void free_tlv (void *val) { XFREE (MTYPE_ISIS_TLV, val); return; } /* * Called after parsing of a PDU. There shouldn't be any tlv's left, so this * is only a caution to avoid memory leaks */ void free_tlvs (struct tlvs *tlvs) { if (tlvs->area_addrs) list_delete (tlvs->area_addrs); if (tlvs->is_neighs) list_delete (tlvs->is_neighs); if (tlvs->te_is_neighs) list_delete (tlvs->te_is_neighs); if (tlvs->es_neighs) list_delete (tlvs->es_neighs); if (tlvs->lsp_entries) list_delete (tlvs->lsp_entries); if (tlvs->prefix_neighs) list_delete (tlvs->prefix_neighs); if (tlvs->lan_neighs) list_delete (tlvs->lan_neighs); if (tlvs->ipv4_addrs) list_delete (tlvs->ipv4_addrs); if (tlvs->ipv4_int_reachs) list_delete (tlvs->ipv4_int_reachs); if (tlvs->ipv4_ext_reachs) list_delete (tlvs->ipv4_ext_reachs); if (tlvs->te_ipv4_reachs) list_delete (tlvs->te_ipv4_reachs); #ifdef HAVE_IPV6 if (tlvs->ipv6_addrs) list_delete (tlvs->ipv6_addrs); if (tlvs->ipv6_reachs) list_delete (tlvs->ipv6_reachs); #endif /* HAVE_IPV6 */ memset (tlvs, 0, sizeof (struct tlvs)); return; } /* * Parses the tlvs found in the variant length part of the PDU. * Caller tells with flags in "expected" which TLV's it is interested in. */ int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs, u_int32_t *auth_tlv_offset) { u_char type, length; struct lan_neigh *lan_nei; struct area_addr *area_addr; struct is_neigh *is_nei; struct te_is_neigh *te_is_nei; struct es_neigh *es_nei; struct lsp_entry *lsp_entry; struct in_addr *ipv4_addr; struct ipv4_reachability *ipv4_reach; struct te_ipv4_reachability *te_ipv4_reach; #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; struct ipv6_reachability *ipv6_reach; int prefix_octets; #endif /* HAVE_IPV6 */ u_char virtual; int value_len, retval = ISIS_OK; u_char *start = stream, *pnt = stream, *endpnt; *found = 0; memset (tlvs, 0, sizeof (struct tlvs)); while (pnt < stream + size - 2) { type = *pnt; length = *(pnt + 1); pnt += 2; value_len = 0; if (pnt + length > stream + size) { zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) exceeds packet " "boundaries", areatag, type, length); retval = ISIS_WARNING; break; } switch (type) { case AREA_ADDRESSES: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Address Length | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Area Address | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_AREA_ADDRS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("TLV Area Adresses len %d", length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_AREA_ADDRS) { while (length > value_len) { area_addr = (struct area_addr *) pnt; value_len += area_addr->addr_len + 1; pnt += area_addr->addr_len + 1; if (!tlvs->area_addrs) tlvs->area_addrs = list_new (); listnode_add (tlvs->area_addrs, area_addr); } } else { pnt += length; } break; case IS_NEIGHBOURS: *found |= TLVFLAG_IS_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IS Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_IS_NEIGHS & *expected) { /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Virtual Flag | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ virtual = *pnt; /* FIXME: what is the use for this? */ pnt++; value_len++; /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | * +---------------------------------------------------------------+ * : : */ while (length > value_len) { is_nei = (struct is_neigh *) pnt; value_len += 4 + ISIS_SYS_ID_LEN + 1; pnt += 4 + ISIS_SYS_ID_LEN + 1; if (!tlvs->is_neighs) tlvs->is_neighs = list_new (); listnode_add (tlvs->is_neighs, is_nei); } } else { pnt += length; } break; case TE_IS_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | 7 * +---------------------------------------------------------------+ * | TE Metric | 3 * +---------------------------------------------------------------+ * | SubTLVs Length | 1 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_TE_IS_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Extended IS Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_TE_IS_NEIGHS & *expected) { while (length > value_len) { te_is_nei = (struct te_is_neigh *) pnt; value_len += 11; pnt += 11; /* FIXME - subtlvs are handled here, for now we skip */ value_len += te_is_nei->sub_tlvs_length; pnt += te_is_nei->sub_tlvs_length; if (!tlvs->te_is_neighs) tlvs->te_is_neighs = list_new (); listnode_add (tlvs->te_is_neighs, te_is_nei); } } else { pnt += length; } break; case ES_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Neighbour ID | * +---------------------------------------------------------------+ * | Neighbour ID | * +---------------------------------------------------------------+ * : : */ #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): ES Neighbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ *found |= TLVFLAG_ES_NEIGHS; if (*expected & TLVFLAG_ES_NEIGHS) { es_nei = (struct es_neigh *) pnt; value_len += 4; pnt += 4; while (length > value_len) { /* FIXME FIXME FIXME - add to the list */ /* sys_id->id = pnt; */ value_len += ISIS_SYS_ID_LEN; pnt += ISIS_SYS_ID_LEN; /* if (!es_nei->neigh_ids) es_nei->neigh_ids = sysid; */ } if (!tlvs->es_neighs) tlvs->es_neighs = list_new (); listnode_add (tlvs->es_neighs, es_nei); } else { pnt += length; } break; case LAN_NEIGHBOURS: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | LAN Address | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_LAN_NEIGHS; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): LAN Neigbours length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (TLVFLAG_LAN_NEIGHS & *expected) { while (length > value_len) { lan_nei = (struct lan_neigh *) pnt; if (!tlvs->lan_neighs) tlvs->lan_neighs = list_new (); listnode_add (tlvs->lan_neighs, lan_nei); value_len += ETH_ALEN; pnt += ETH_ALEN; } } else { pnt += length; } break; case PADDING: #ifdef EXTREME_TLV_DEBUG zlog_debug ("TLV padding %d", length); #endif /* EXTREME_TLV_DEBUG */ pnt += length; break; case LSP_ENTRIES: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Remaining Lifetime | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP ID | id+2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP Sequence Number | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Checksum | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): LSP Entries length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ *found |= TLVFLAG_LSP_ENTRIES; if (TLVFLAG_LSP_ENTRIES & *expected) { while (length > value_len) { lsp_entry = (struct lsp_entry *) pnt; value_len += 10 + ISIS_SYS_ID_LEN; pnt += 10 + ISIS_SYS_ID_LEN; if (!tlvs->lsp_entries) tlvs->lsp_entries = list_new (); listnode_add (tlvs->lsp_entries, lsp_entry); } } else { pnt += length; } break; case CHECKSUM: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 16 bit fletcher CHECKSUM | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_CHECKSUM; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Checksum length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_CHECKSUM) { tlvs->checksum = (struct checksum *) pnt; } pnt += length; break; case PROTOCOLS_SUPPORTED: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | NLPID | * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_NLPID; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Protocols Supported length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_NLPID) { tlvs->nlpids = (struct nlpids *) (pnt - 1); } pnt += length; break; case IPV4_ADDR: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * + IP version 4 address + 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_IPV4_ADDR; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 Address length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_ADDR) { while (length > value_len) { ipv4_addr = (struct in_addr *) pnt; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s) : IP ADDR %s, pnt %p", areatag, inet_ntoa (*ipv4_addr), pnt); #endif /* EXTREME_TLV_DEBUG */ if (!tlvs->ipv4_addrs) tlvs->ipv4_addrs = list_new (); listnode_add (tlvs->ipv4_addrs, ipv4_addr); value_len += 4; pnt += 4; } } else { pnt += length; } break; case AUTH_INFO: *found |= TLVFLAG_AUTH_INFO; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IS-IS Authentication Information", areatag); #endif if (*expected & TLVFLAG_AUTH_INFO) { tlvs->auth_info.type = *pnt; if (length == 0) { zlog_warn ("ISIS-TLV (%s): TLV (type %d, length %d) " "incorrect.", areatag, type, length); return ISIS_WARNING; } --length; tlvs->auth_info.len = length; pnt++; memcpy (tlvs->auth_info.passwd, pnt, length); /* Return the authentication tlv pos for later computation * of MD5 (RFC 5304, 2) */ if (auth_tlv_offset) *auth_tlv_offset += (pnt - start - 3); pnt += length; } else { pnt += length; } break; case DYNAMIC_HOSTNAME: *found |= TLVFLAG_DYN_HOSTNAME; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): Dynamic Hostname length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_DYN_HOSTNAME) { /* the length is also included in the pointed struct */ tlvs->hostname = (struct hostname *) (pnt - 1); } pnt += length; break; case TE_ROUTER_ID: /* +---------------------------------------------------------------+ * + Router ID + 4 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_TE_ROUTER_ID; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): TE Router ID %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_TE_ROUTER_ID) tlvs->router_id = (struct te_router_id *) (pnt); pnt += length; break; case IPV4_INT_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | ip address | 4 * +---------------------------------------------------------------+ * | address mask | 4 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_IPV4_INT_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 internal Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_INT_REACHABILITY) { while (length > value_len) { ipv4_reach = (struct ipv4_reachability *) pnt; if (!tlvs->ipv4_int_reachs) tlvs->ipv4_int_reachs = list_new (); listnode_add (tlvs->ipv4_int_reachs, ipv4_reach); value_len += 12; pnt += 12; } } else { pnt += length; } break; case IPV4_EXT_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | I/E | Default Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Delay Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Expense Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | S | I/E | Error Metric | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | ip address | 4 * +---------------------------------------------------------------+ * | address mask | 4 * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_IPV4_EXT_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 external Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV4_EXT_REACHABILITY) { while (length > value_len) { ipv4_reach = (struct ipv4_reachability *) pnt; if (!tlvs->ipv4_ext_reachs) tlvs->ipv4_ext_reachs = list_new (); listnode_add (tlvs->ipv4_ext_reachs, ipv4_reach); value_len += 12; pnt += 12; } } else { pnt += length; } break; case TE_IPV4_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | TE Metric | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | U/D | sTLV? | Prefix Mask Len | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Prefix | 0-4 * +---------------------------------------------------------------+ * | sub tlvs | * +---------------------------------------------------------------+ * : : */ *found |= TLVFLAG_TE_IPV4_REACHABILITY; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv4 extended Reachability length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ endpnt = pnt + length; if (*expected & TLVFLAG_TE_IPV4_REACHABILITY) { while (length > value_len) { te_ipv4_reach = (struct te_ipv4_reachability *) pnt; if ((te_ipv4_reach->control & 0x3F) > IPV4_MAX_BITLEN) { zlog_warn ("ISIS-TLV (%s): invalid IPv4 extended reach" "ability prefix length %d", areatag, te_ipv4_reach->control & 0x3F); retval = ISIS_WARNING; break; } if (!tlvs->te_ipv4_reachs) tlvs->te_ipv4_reachs = list_new (); listnode_add (tlvs->te_ipv4_reachs, te_ipv4_reach); /* this trickery is permitable since no subtlvs are defined */ value_len += 5 + ((te_ipv4_reach->control & 0x3F) ? ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); pnt += 5 + ((te_ipv4_reach->control & 0x3F) ? ((((te_ipv4_reach->control & 0x3F) - 1) >> 3) + 1) : 0); } } pnt = endpnt; break; #ifdef HAVE_IPV6 case IPV6_ADDR: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * + IP version 6 address + 16 * +-------+-------+-------+-------+-------+-------+-------+-------+ * : : */ *found |= TLVFLAG_IPV6_ADDR; #ifdef EXTREME_TLV_DEBUG zlog_debug ("ISIS-TLV (%s): IPv6 Address length %d", areatag, length); #endif /* EXTREME_TLV_DEBUG */ if (*expected & TLVFLAG_IPV6_ADDR) { while (length > value_len) { ipv6_addr = (struct in6_addr *) pnt; if (!tlvs->ipv6_addrs) tlvs->ipv6_addrs = list_new (); listnode_add (tlvs->ipv6_addrs, ipv6_addr); value_len += 16; pnt += 16; } } else { pnt += length; } break; case IPV6_REACHABILITY: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Default Metric | 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Control Informantion | * +---------------------------------------------------------------+ * | IPv6 Prefix Length |--+ * +---------------------------------------------------------------+ | * | IPv6 Prefix |<-+ * +---------------------------------------------------------------+ */ *found |= TLVFLAG_IPV6_REACHABILITY; endpnt = pnt + length; if (*expected & TLVFLAG_IPV6_REACHABILITY) { while (length > value_len) { ipv6_reach = (struct ipv6_reachability *) pnt; if (ipv6_reach->prefix_len > IPV6_MAX_BITLEN) { zlog_warn ("ISIS-TLV (%s): invalid IPv6 extended reach" "ability prefix length %d", areatag, ipv6_reach->prefix_len); retval = ISIS_WARNING; break; } prefix_octets = ((ipv6_reach->prefix_len + 7) / 8); value_len += prefix_octets + 6; pnt += prefix_octets + 6; /* FIXME: sub-tlvs */ if (!tlvs->ipv6_reachs) tlvs->ipv6_reachs = list_new (); listnode_add (tlvs->ipv6_reachs, ipv6_reach); } } pnt = endpnt; break; #endif /* HAVE_IPV6 */ case WAY3_HELLO: /* +---------------------------------------------------------------+ * | Adjacency state | 1 * +---------------------------------------------------------------+ * | Extended Local Circuit ID | 4 * +---------------------------------------------------------------+ * | Neighbor System ID (If known) | 0-8 * (probably 6) * +---------------------------------------------------------------+ * | Neighbor Local Circuit ID (If known) | 4 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_3WAY_HELLO; if (*expected & TLVFLAG_3WAY_HELLO) { while (length > value_len) { /* FIXME: make this work */ /* Adjacency State (one octet): 0 = Up 1 = Initializing 2 = Down Extended Local Circuit ID (four octets) Neighbor System ID if known (zero to eight octets) Neighbor Extended Local Circuit ID (four octets, if Neighbor System ID is present) */ pnt += length; value_len += length; } } else { pnt += length; } break; case GRACEFUL_RESTART: /* +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | SA | RA | RR | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Remaining Time | 2 * +---------------------------------------------------------------+ * | Restarting Neighbor ID (If known) | 0-8 * +---------------------------------------------------------------+ */ *found |= TLVFLAG_GRACEFUL_RESTART; if (*expected & TLVFLAG_GRACEFUL_RESTART) { /* FIXME: make this work */ } pnt += length; break; default: zlog_warn ("ISIS-TLV (%s): unsupported TLV type %d, length %d", areatag, type, length); pnt += length; break; } } return retval; } int add_tlv (u_char tag, u_char len, u_char * value, struct stream *stream) { if ((stream_get_size (stream) - stream_get_endp (stream)) < (((unsigned)len) + 2)) { zlog_warn ("No room for TLV of type %d " "(total size %d available %d required %d)", tag, (int)stream_get_size (stream), (int)(stream_get_size (stream) - stream_get_endp (stream)), len+2); return ISIS_WARNING; } stream_putc (stream, tag); /* TAG */ stream_putc (stream, len); /* LENGTH */ stream_put (stream, value, (int) len); /* VALUE */ #ifdef EXTREME_DEBUG zlog_debug ("Added TLV %d len %d", tag, len); #endif /* EXTREME DEBUG */ return ISIS_OK; } int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream) { struct listnode *node; struct area_addr *area_addr; u_char value[255]; u_char *pos = value; for (ALL_LIST_ELEMENTS_RO (area_addrs, node, area_addr)) { if (pos - value + area_addr->addr_len > 255) goto err; *pos = area_addr->addr_len; pos++; memcpy (pos, area_addr->area_addr, (int) area_addr->addr_len); pos += area_addr->addr_len; } return add_tlv (AREA_ADDRESSES, pos - value, value, stream); err: zlog_warn ("tlv_add_area_addrs(): TLV longer than 255"); return ISIS_WARNING; } int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream) { struct listnode *node; struct is_neigh *is_neigh; u_char value[255]; u_char *pos = value; int retval; *pos = 0; /*is_neigh->virtual; */ pos++; for (ALL_LIST_ELEMENTS_RO (is_neighs, node, is_neigh)) { if (pos - value + IS_NEIGHBOURS_LEN > 255) { retval = add_tlv (IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *pos = is_neigh->metrics.metric_default; pos++; *pos = is_neigh->metrics.metric_delay; pos++; *pos = is_neigh->metrics.metric_expense; pos++; *pos = is_neigh->metrics.metric_error; pos++; memcpy (pos, is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); pos += ISIS_SYS_ID_LEN + 1; } return add_tlv (IS_NEIGHBOURS, pos - value, value, stream); } int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream) { struct listnode *node; struct te_is_neigh *te_is_neigh; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (te_is_neighs, node, te_is_neigh)) { /* FIXME: This will be wrong if we are going to add TE sub TLVs. */ if (pos - value + IS_NEIGHBOURS_LEN > 255) { retval = add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, te_is_neigh->neigh_id, ISIS_SYS_ID_LEN + 1); pos += ISIS_SYS_ID_LEN + 1; memcpy (pos, te_is_neigh->te_metric, 3); pos += 3; /* Sub TLVs length. */ *pos = 0; pos++; } return add_tlv (TE_IS_NEIGHBOURS, pos - value, value, stream); } int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream) { struct listnode *node; u_char *snpa; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (lan_neighs, node, snpa)) { if (pos - value + ETH_ALEN > 255) { retval = add_tlv (LAN_NEIGHBOURS, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, snpa, ETH_ALEN); pos += ETH_ALEN; } return add_tlv (LAN_NEIGHBOURS, pos - value, value, stream); } int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream) { return add_tlv (PROTOCOLS_SUPPORTED, nlpids->count, nlpids->nlpids, stream); } int tlv_add_authinfo (u_char auth_type, u_char auth_len, u_char *auth_value, struct stream *stream) { u_char value[255]; u_char *pos = value; *pos++ = auth_type; memcpy (pos, auth_value, auth_len); return add_tlv (AUTH_INFO, auth_len + 1, value, stream); } int tlv_add_checksum (struct checksum *checksum, struct stream *stream) { u_char value[255]; u_char *pos = value; return add_tlv (CHECKSUM, pos - value, value, stream); } int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream) { struct listnode *node; struct prefix_ipv4 *ipv4; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (ip_addrs, node, ipv4)) { if (pos - value + IPV4_MAX_BYTELEN > 255) { /* RFC 1195 s4.2: only one tuple of 63 allowed. */ zlog_warn ("tlv_add_ip_addrs(): cutting off at 63 IP addresses"); break; } *(u_int32_t *) pos = ipv4->prefix.s_addr; pos += IPV4_MAX_BYTELEN; } return add_tlv (IPV4_ADDR, pos - value, value, stream); } /* Used to add TLV containing just one IPv4 address - either IPv4 address TLV * (in case of LSP) or TE router ID TLV. */ int tlv_add_in_addr (struct in_addr *addr, struct stream *stream, u_char tag) { u_char value[255]; u_char *pos = value; memcpy (pos, addr, IPV4_MAX_BYTELEN); pos += IPV4_MAX_BYTELEN; return add_tlv (tag, pos - value, value, stream); } int tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream) { return add_tlv (DYNAMIC_HOSTNAME, hostname->namelen, hostname->name, stream); } int tlv_add_lsp_entries (struct list *lsps, struct stream *stream) { struct listnode *node; struct isis_lsp *lsp; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp)) { if (pos - value + LSP_ENTRIES_LEN > 255) { retval = add_tlv (LSP_ENTRIES, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *((u_int16_t *) pos) = lsp->lsp_header->rem_lifetime; pos += 2; memcpy (pos, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); pos += ISIS_SYS_ID_LEN + 2; *((u_int32_t *) pos) = lsp->lsp_header->seq_num; pos += 4; *((u_int16_t *) pos) = lsp->lsp_header->checksum; pos += 2; } return add_tlv (LSP_ENTRIES, pos - value, value, stream); } int tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream) { struct listnode *node; struct ipv4_reachability *reach; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (ipv4_reachs, node, reach)) { if (pos - value + IPV4_REACH_LEN > 255) { retval = add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *pos = reach->metrics.metric_default; pos++; *pos = reach->metrics.metric_delay; pos++; *pos = reach->metrics.metric_expense; pos++; *pos = reach->metrics.metric_error; pos++; *(u_int32_t *) pos = reach->prefix.s_addr; pos += IPV4_MAX_BYTELEN; *(u_int32_t *) pos = reach->mask.s_addr; pos += IPV4_MAX_BYTELEN; } return add_tlv (IPV4_INT_REACHABILITY, pos - value, value, stream); } int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream) { struct listnode *node; struct te_ipv4_reachability *te_reach; u_char value[255]; u_char *pos = value; u_char prefix_size; int retval; for (ALL_LIST_ELEMENTS_RO (te_ipv4_reachs, node, te_reach)) { prefix_size = ((((te_reach->control & 0x3F) - 1) >> 3) + 1); if (pos - value + (5 + prefix_size) > 255) { retval = add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *(u_int32_t *) pos = te_reach->te_metric; pos += 4; *pos = te_reach->control; pos++; memcpy (pos, &te_reach->prefix_start, prefix_size); pos += prefix_size; } return add_tlv (TE_IPV4_REACHABILITY, pos - value, value, stream); } #ifdef HAVE_IPV6 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream) { struct listnode *node; struct prefix_ipv6 *ipv6; u_char value[255]; u_char *pos = value; int retval; for (ALL_LIST_ELEMENTS_RO (ipv6_addrs, node, ipv6)) { if (pos - value + IPV6_MAX_BYTELEN > 255) { retval = add_tlv (IPV6_ADDR, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } memcpy (pos, ipv6->prefix.s6_addr, IPV6_MAX_BYTELEN); pos += IPV6_MAX_BYTELEN; } return add_tlv (IPV6_ADDR, pos - value, value, stream); } int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream) { struct listnode *node; struct ipv6_reachability *ip6reach; u_char value[255]; u_char *pos = value; int retval, prefix_octets; for (ALL_LIST_ELEMENTS_RO (ipv6_reachs, node, ip6reach)) { if (pos - value + IPV6_MAX_BYTELEN + 6 > 255) { retval = add_tlv (IPV6_REACHABILITY, pos - value, value, stream); if (retval != ISIS_OK) return retval; pos = value; } *(uint32_t *) pos = ip6reach->metric; pos += 4; *pos = ip6reach->control_info; pos++; prefix_octets = ((ip6reach->prefix_len + 7) / 8); *pos = ip6reach->prefix_len; pos++; memcpy (pos, ip6reach->prefix, prefix_octets); pos += prefix_octets; } return add_tlv (IPV6_REACHABILITY, pos - value, value, stream); } #endif /* HAVE_IPV6 */ int tlv_add_padding (struct stream *stream) { int fullpads, i, left; /* * How many times can we add full padding ? */ fullpads = (stream_get_size (stream) - stream_get_endp (stream)) / 257; for (i = 0; i < fullpads; i++) { if (!stream_putc (stream, (u_char) PADDING)) /* TAG */ goto err; if (!stream_putc (stream, (u_char) 255)) /* LENGHT */ goto err; stream_put (stream, NULL, 255); /* zero padding */ } left = stream_get_size (stream) - stream_get_endp (stream); if (left < 2) return ISIS_OK; if (left == 2) { stream_putc (stream, PADDING); stream_putc (stream, 0); return ISIS_OK; } stream_putc (stream, PADDING); stream_putc (stream, left - 2); stream_put (stream, NULL, left-2); return ISIS_OK; err: zlog_warn ("tlv_add_padding(): no room for tlv"); return ISIS_WARNING; } quagga-0.99.24.1/isisd/isis_pdu.c0000644000175000017500000026443012476520570013343 00000000000000/* * IS-IS Rout(e)ing protocol - isis_pdu.c * PDU processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "thread.h" #include "linklist.h" #include "log.h" #include "stream.h" #include "vty.h" #include "hash.h" #include "prefix.h" #include "if.h" #include "checksum.h" #include "md5.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_circuit.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" #include "isisd/isis_tlv.h" #include "isisd/isisd.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/iso_checksum.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" #define ISIS_MINIMUM_FIXED_HDR_LEN 15 #define ISIS_MIN_PDU_LEN 13 /* partial seqnum pdu with id_len=2 */ #ifndef PNBBY #define PNBBY 8 #endif /* PNBBY */ /* Utility mask array. */ static const u_char maskbit[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; /* * HELPER FUNCS */ /* * Compares two sets of area addresses */ static int area_match (struct list *left, struct list *right) { struct area_addr *addr1, *addr2; struct listnode *node1, *node2; for (ALL_LIST_ELEMENTS_RO (left, node1, addr1)) { for (ALL_LIST_ELEMENTS_RO (right, node2, addr2)) { if (addr1->addr_len == addr2->addr_len && !memcmp (addr1->area_addr, addr2->area_addr, (int) addr1->addr_len)) return 1; /* match */ } } return 0; /* mismatch */ } /* * Check if ip2 is in the ip1's network (function like Prefix.h:prefix_match() ) * param ip1 the IS interface ip address structure * param ip2 the IIH's ip address * return 0 the IIH's IP is not in the IS's subnetwork * 1 the IIH's IP is in the IS's subnetwork */ static int ip_same_subnet (struct prefix_ipv4 *ip1, struct in_addr *ip2) { u_char *addr1, *addr2; int shift, offset, offsetloop; int len; addr1 = (u_char *) & ip1->prefix.s_addr; addr2 = (u_char *) & ip2->s_addr; len = ip1->prefixlen; shift = len % PNBBY; offsetloop = offset = len / PNBBY; while (offsetloop--) if (addr1[offsetloop] != addr2[offsetloop]) return 0; if (shift) if (maskbit[shift] & (addr1[offset] ^ addr2[offset])) return 0; return 1; /* match */ } /* * Compares two set of ip addresses * param left the local interface's ip addresses * param right the iih interface's ip address * return 0 no match; * 1 match; */ static int ip_match (struct list *left, struct list *right) { struct prefix_ipv4 *ip1; struct in_addr *ip2; struct listnode *node1, *node2; if ((left == NULL) || (right == NULL)) return 0; for (ALL_LIST_ELEMENTS_RO (left, node1, ip1)) { for (ALL_LIST_ELEMENTS_RO (right, node2, ip2)) { if (ip_same_subnet (ip1, ip2)) { return 1; /* match */ } } } return 0; } /* * Checks whether we should accept a PDU of given level */ static int accept_level (int level, int circuit_t) { int retval = ((circuit_t & level) == level); /* simple approach */ return retval; } /* * Verify authentication information * Support cleartext and HMAC MD5 authentication */ static int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct stream *stream, uint32_t auth_tlv_offset) { unsigned char digest[ISIS_AUTH_MD5_SIZE]; /* Auth fail () - passwd type mismatch */ if (local->type != remote->type) return ISIS_ERROR; switch (local->type) { /* No authentication required */ case ISIS_PASSWD_TYPE_UNUSED: break; /* Cleartext (ISO 10589) */ case ISIS_PASSWD_TYPE_CLEARTXT: /* Auth fail () - passwd len mismatch */ if (remote->len != local->len) return ISIS_ERROR; return memcmp (local->passwd, remote->passwd, local->len); /* HMAC MD5 (RFC 3567) */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Auth fail () - passwd len mismatch */ if (remote->len != ISIS_AUTH_MD5_SIZE) return ISIS_ERROR; /* Set the authentication value to 0 before the check */ memset (STREAM_DATA (stream) + auth_tlv_offset + 3, 0, ISIS_AUTH_MD5_SIZE); /* Compute the digest */ hmac_md5 (STREAM_DATA (stream), stream_get_endp (stream), (unsigned char *) &(local->passwd), local->len, (caddr_t) &digest); /* Copy back the authentication value after the check */ memcpy (STREAM_DATA (stream) + auth_tlv_offset + 3, remote->passwd, ISIS_AUTH_MD5_SIZE); return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE); default: zlog_err ("Unsupported authentication type"); return ISIS_ERROR; } /* Authentication pass when no authentication is configured */ return ISIS_OK; } static int lsp_authentication_check (struct stream *stream, struct isis_area *area, int level, struct isis_passwd *passwd) { struct isis_link_state_hdr *hdr; uint32_t expected = 0, found = 0, auth_tlv_offset = 0; uint16_t checksum, rem_lifetime, pdu_len; struct tlvs tlvs; int retval = ISIS_OK; hdr = (struct isis_link_state_hdr *) (STREAM_PNT (stream)); pdu_len = ntohs (hdr->pdu_len); expected |= TLVFLAG_AUTH_INFO; auth_tlv_offset = stream_get_getp (stream) + ISIS_LSP_HDR_LEN; retval = parse_tlvs (area->area_tag, STREAM_PNT (stream) + ISIS_LSP_HDR_LEN, pdu_len - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval != ISIS_OK) { zlog_err ("ISIS-Upd (%s): Parse failed L%d LSP %s, seq 0x%08x, " "cksum 0x%04x, lifetime %us, len %u", area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), pdu_len); if ((isis->debugs & DEBUG_UPDATE_PACKETS) && (isis->debugs & DEBUG_PACKET_DUMP)) zlog_dump_data (STREAM_DATA (stream), stream_get_endp (stream)); return retval; } if (!(found & TLVFLAG_AUTH_INFO)) { zlog_err ("No authentication tlv in LSP"); return ISIS_ERROR; } if (tlvs.auth_info.type != ISIS_PASSWD_TYPE_CLEARTXT && tlvs.auth_info.type != ISIS_PASSWD_TYPE_HMAC_MD5) { zlog_err ("Unknown authentication type in LSP"); return ISIS_ERROR; } /* * RFC 5304 set checksum and remaining lifetime to zero before * verification and reset to old values after verification. */ checksum = hdr->checksum; rem_lifetime = hdr->rem_lifetime; hdr->checksum = 0; hdr->rem_lifetime = 0; retval = authentication_check (&tlvs.auth_info, passwd, stream, auth_tlv_offset); hdr->checksum = checksum; hdr->rem_lifetime = rem_lifetime; return retval; } /* * Processing helper functions */ static void del_addr (void *val) { XFREE (MTYPE_ISIS_TMP, val); } static void tlvs_to_adj_area_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct area_addr *area_addr, *malloced; if (adj->area_addrs) { adj->area_addrs->del = del_addr; list_delete (adj->area_addrs); } adj->area_addrs = list_new (); if (tlvs->area_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->area_addrs, node, area_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct area_addr)); memcpy (malloced, area_addr, sizeof (struct area_addr)); listnode_add (adj->area_addrs, malloced); } } } static int tlvs_to_adj_nlpids (struct tlvs *tlvs, struct isis_adjacency *adj) { int i; struct nlpids *tlv_nlpids; if (tlvs->nlpids) { tlv_nlpids = tlvs->nlpids; if (tlv_nlpids->count > array_size (adj->nlpids.nlpids)) return 1; adj->nlpids.count = tlv_nlpids->count; for (i = 0; i < tlv_nlpids->count; i++) { adj->nlpids.nlpids[i] = tlv_nlpids->nlpids[i]; } } return 0; } static void tlvs_to_adj_ipv4_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct in_addr *ipv4_addr, *malloced; if (adj->ipv4_addrs) { adj->ipv4_addrs->del = del_addr; list_delete (adj->ipv4_addrs); } adj->ipv4_addrs = list_new (); if (tlvs->ipv4_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->ipv4_addrs, node, ipv4_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in_addr)); memcpy (malloced, ipv4_addr, sizeof (struct in_addr)); listnode_add (adj->ipv4_addrs, malloced); } } } #ifdef HAVE_IPV6 static void tlvs_to_adj_ipv6_addrs (struct tlvs *tlvs, struct isis_adjacency *adj) { struct listnode *node; struct in6_addr *ipv6_addr, *malloced; if (adj->ipv6_addrs) { adj->ipv6_addrs->del = del_addr; list_delete (adj->ipv6_addrs); } adj->ipv6_addrs = list_new (); if (tlvs->ipv6_addrs) { for (ALL_LIST_ELEMENTS_RO (tlvs->ipv6_addrs, node, ipv6_addr)) { malloced = XMALLOC (MTYPE_ISIS_TMP, sizeof (struct in6_addr)); memcpy (malloced, ipv6_addr, sizeof (struct in6_addr)); listnode_add (adj->ipv6_addrs, malloced); } } } #endif /* HAVE_IPV6 */ /* * RECEIVE SIDE */ /* * Process P2P IIH * ISO - 10589 * Section 8.2.5 - Receiving point-to-point IIH PDUs * */ static int process_p2p_hello (struct isis_circuit *circuit) { int retval = ISIS_OK; struct isis_p2p_hello_hdr *hdr; struct isis_adjacency *adj; u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; uint16_t pdu_len; struct tlvs tlvs; int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH on %s, cirType %s, cirID %u", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if (circuit->circ_type != CIRCUIT_T_P2P) { zlog_warn ("p2p hello on non p2p circuit"); return ISIS_WARNING; } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_P2PHELLO_HDRLEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } /* 8.2.5.1 PDU acceptance tests */ /* 8.2.5.1 a) external domain untrue */ /* FIXME: not useful at all? */ /* 8.2.5.1 b) ID Length mismatch */ /* checked at the handle_pdu */ /* 8.2.5.2 IIH PDU Processing */ /* 8.2.5.2 a) 1) Maximum Area Addresses */ /* Already checked, and can also be ommited */ /* * Get the header */ hdr = (struct isis_p2p_hello_hdr *) STREAM_PNT (circuit->rcv_stream); pdu_len = ntohs (hdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_P2PHELLO_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd P2P IIH from (%s) with " "invalid pdu length %d", circuit->area->area_tag, circuit->interface->name, pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); stream_forward_getp (circuit->rcv_stream, ISIS_P2PHELLO_HDRLEN); /* * Lets get the TLVS now */ expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), pdu_len - ISIS_P2PHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("parse_tlvs() failed"); free_tlvs (&tlvs); return retval; }; if (!(found & TLVFLAG_AREA_ADDRS)) { zlog_warn ("No Area addresses TLV in P2P IS to IS hello"); free_tlvs (&tlvs); return ISIS_WARNING; } if (!(found & TLVFLAG_NLPID)) { zlog_warn ("No supported protocols TLV in P2P IS to IS hello"); free_tlvs (&tlvs); return ISIS_WARNING; } /* 8.2.5.1 c) Authentication */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, &circuit->passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "P2P hello authentication failure", hdr->source_id); free_tlvs (&tlvs); return ISIS_OK; } } /* * check if it's own interface ip match iih ip addrs */ if (found & TLVFLAG_IPV4_ADDR) { if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) v4_usable = 1; else zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " "in P2P IIH from %s\n", circuit->interface->name); } #ifndef HAVE_IPV6 else /* !(found & TLVFLAG_IPV4_ADDR) */ zlog_warn ("ISIS-Adj: no IPv4 in P2P IIH from %s " "(this isisd has no IPv6)\n", circuit->interface->name); #else if (found & TLVFLAG_IPV6_ADDR) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { v6_usable = 1; break; } if (!v6_usable) zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " "in P2P IIH from %s\n", circuit->interface->name); } if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in P2P IIH from %s\n", circuit->interface->name); #endif if (!v6_usable && !v4_usable) { free_tlvs (&tlvs); return ISIS_WARNING; } /* * My interpertation of the ISO, if no adj exists we will create one for * the circuit */ adj = circuit->u.p2p.neighbor; /* If an adjacency exists, check it is with the source of the hello * packets */ if (adj) { if (memcmp(hdr->source_id, adj->sysid, ISIS_SYS_ID_LEN)) { zlog_debug("hello source and adjacency do not match, set adj down\n"); isis_adj_state_change (adj, ISIS_ADJ_DOWN, "adj do not exist"); return 0; } } if (!adj || adj->level != hdr->circuit_t) { if (!adj) { adj = isis_new_adj (hdr->source_id, NULL, hdr->circuit_t, circuit); if (adj == NULL) return ISIS_ERROR; } else { adj->level = hdr->circuit_t; } circuit->u.p2p.neighbor = adj; isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; } /* 8.2.6 Monitoring point-to-point adjacencies */ adj->hold_time = ntohs (hdr->hold_time); adj->last_upd = time (NULL); /* we do this now because the adj may not survive till the end... */ tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ if (tlvs_to_adj_nlpids (&tlvs, adj)) { free_tlvs (&tlvs); return ISIS_WARNING; } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, (long) adj->hold_time); /* 8.2.5.2 a) a match was detected */ if (area_match (circuit->area->area_addrs, tlvs.area_addrs)) { /* 8.2.5.2 a) 2) If the system is L1 - table 5 */ if (circuit->area->is_type == IS_LEVEL_1) { switch (hdr->circuit_t) { case IS_LEVEL_1: case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (4) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (5) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { ; /* accept */ } break; case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (7) reject - wrong system type event */ zlog_warn ("wrongSystemType"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; } } /* 8.2.5.2 a) 3) If the system is L1L2 - table 6 */ if (circuit->area->is_type == IS_LEVEL_1_AND_2) { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (7) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { ; /* accept */ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (9) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL1AND2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; case IS_LEVEL_1_AND_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (10) adj usage level 1 */ adj->adj_usage = ISIS_ADJ_LEVEL1AND2; } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (8) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { ; /* Accept */ } break; } } /* 8.2.5.2 a) 4) If the system is L2 - table 7 */ if (circuit->area->is_type == IS_LEVEL_2) { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (5) reject - wrong system type event */ zlog_warn ("wrongSystemType"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (7) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (8) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { /* (6) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; } } } /* 8.2.5.2 b) if no match was detected */ else if (listcount (circuit->area->area_addrs) > 0) { if (circuit->area->is_type == IS_LEVEL_1) { /* 8.2.5.2 b) 1) is_type L1 and adj is not up */ if (adj->adj_state != ISIS_ADJ_UP) { isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); /* 8.2.5.2 b) 2)is_type L1 and adj is up */ } else { isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Down - Area Mismatch"); } } /* 8.2.5.2 b 3 If the system is L2 or L1L2 - table 8 */ else { switch (hdr->circuit_t) { case IS_LEVEL_1: if (adj->adj_state != ISIS_ADJ_UP) { /* (6) reject - Area Mismatch event */ zlog_warn ("AreaMismatch"); free_tlvs (&tlvs); return ISIS_WARNING; /* Reject */ } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } else if ((adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (adj->adj_usage == ISIS_ADJ_LEVEL2)) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } break; case IS_LEVEL_1_AND_2: case IS_LEVEL_2: if (adj->adj_state != ISIS_ADJ_UP) { /* (8) adj state up */ isis_adj_state_change (adj, ISIS_ADJ_UP, NULL); /* (9) adj usage level 2 */ adj->adj_usage = ISIS_ADJ_LEVEL2; } else if (adj->adj_usage == ISIS_ADJ_LEVEL1) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else if (adj->adj_usage == ISIS_ADJ_LEVEL1AND2) { if (hdr->circuit_t == IS_LEVEL_2) { /* (7) down - wrong system */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Wrong System"); } else { /* (7) down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } } else if (adj->adj_usage == ISIS_ADJ_LEVEL2) { ; /* Accept */ } break; } } } else { /* down - area mismatch */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "Area Mismatch"); } /* 8.2.5.2 c) if the action was up - comparing circuit IDs */ /* FIXME - Missing parts */ /* some of my own understanding of the ISO, why the heck does * it not say what should I change the system_type to... */ switch (adj->adj_usage) { case ISIS_ADJ_LEVEL1: adj->sys_type = ISIS_SYSTYPE_L1_IS; break; case ISIS_ADJ_LEVEL2: adj->sys_type = ISIS_SYSTYPE_L2_IS; break; case ISIS_ADJ_LEVEL1AND2: adj->sys_type = ISIS_SYSTYPE_L2_IS; break; case ISIS_ADJ_NONE: adj->sys_type = ISIS_SYSTYPE_UNKNOWN; break; } adj->circuit_t = hdr->circuit_t; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd P2P IIH from (%s), cir type %s," " cir id %02d, length %d", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id, pdu_len); } free_tlvs (&tlvs); return retval; } /* * Process IS-IS LAN Level 1/2 Hello PDU */ static int process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa) { int retval = ISIS_OK; struct isis_lan_hello_hdr hdr; struct isis_adjacency *adj; u_int32_t expected = 0, found = 0, auth_tlv_offset = 0; struct tlvs tlvs; u_char *snpa; struct listnode *node; int v4_usable = 0, v6_usable = 0; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH on %s, cirType %s, " "cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if (circuit->circ_type != CIRCUIT_T_BROADCAST) { zlog_warn ("lan hello on non broadcast circuit"); return ISIS_WARNING; } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LANHELLO_HDRLEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } if (circuit->ext_domain) { zlog_debug ("level %d LAN Hello received over circuit with " "externalDomain = true", level); return ISIS_WARNING; } if (!accept_level (level, circuit->is_type)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Interface level mismatch, %s", circuit->area->area_tag, circuit->interface->name); } return ISIS_WARNING; } #if 0 /* Cisco's debug message compatability */ if (!accept_level (level, circuit->area->is_type)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): is type mismatch", circuit->area->area_tag); } return ISIS_WARNING; } #endif /* * Fill the header */ hdr.circuit_t = stream_getc (circuit->rcv_stream); stream_get (hdr.source_id, circuit->rcv_stream, ISIS_SYS_ID_LEN); hdr.hold_time = stream_getw (circuit->rcv_stream); hdr.pdu_len = stream_getw (circuit->rcv_stream); hdr.prio = stream_getc (circuit->rcv_stream); stream_get (hdr.lan_id, circuit->rcv_stream, ISIS_SYS_ID_LEN + 1); if (hdr.pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LANHELLO_HDRLEN) || hdr.pdu_len > ISO_MTU(circuit) || hdr.pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("ISIS-Adj (%s): Rcvd LAN IIH from (%s) with " "invalid pdu length %d", circuit->area->area_tag, circuit->interface->name, hdr.pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (hdr.pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, hdr.pdu_len); if (hdr.circuit_t != IS_LEVEL_1 && hdr.circuit_t != IS_LEVEL_2 && hdr.circuit_t != IS_LEVEL_1_AND_2 && (level & hdr.circuit_t) == 0) { zlog_err ("Level %d LAN Hello with Circuit Type %d", level, hdr.circuit_t); return ISIS_ERROR; } /* * Then get the tlvs */ expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_LAN_NEIGHS; expected |= TLVFLAG_NLPID; expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV6_ADDR; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), hdr.pdu_len - ISIS_LANHELLO_HDRLEN - ISIS_FIXED_HDR_LEN, &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("parse_tlvs() failed"); goto out; } if (!(found & TLVFLAG_AREA_ADDRS)) { zlog_warn ("No Area addresses TLV in Level %d LAN IS to IS hello", level); retval = ISIS_WARNING; goto out; } if (!(found & TLVFLAG_NLPID)) { zlog_warn ("No supported protocols TLV in Level %d LAN IS to IS hello", level); retval = ISIS_WARNING; goto out; } /* Verify authentication, either cleartext of HMAC MD5 */ if (circuit->passwd.type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, &circuit->passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "LAN hello authentication failure", hdr.source_id); retval = ISIS_WARNING; goto out; } } if (!memcmp (hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN)) { zlog_warn ("ISIS-Adj (%s): duplicate system ID on interface %s", circuit->area->area_tag, circuit->interface->name); return ISIS_WARNING; } /* * Accept the level 1 adjacency only if a match between local and * remote area addresses is found */ if (listcount (circuit->area->area_addrs) == 0 || (level == IS_LEVEL_1 && area_match (circuit->area->area_addrs, tlvs.area_addrs) == 0)) { if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Area mismatch, level %d IIH on %s", circuit->area->area_tag, level, circuit->interface->name); } retval = ISIS_OK; goto out; } /* * it's own IIH PDU - discard silently */ if (!memcmp (circuit->u.bc.snpa, ssnpa, ETH_ALEN)) { zlog_debug ("ISIS-Adj (%s): it's own IIH PDU - discarded", circuit->area->area_tag); retval = ISIS_OK; goto out; } /* * check if it's own interface ip match iih ip addrs */ if (found & TLVFLAG_IPV4_ADDR) { if (ip_match (circuit->ip_addrs, tlvs.ipv4_addrs)) v4_usable = 1; else zlog_warn ("ISIS-Adj: IPv4 addresses present but no overlap " "in LAN IIH from %s\n", circuit->interface->name); } #ifndef HAVE_IPV6 else /* !(found & TLVFLAG_IPV4_ADDR) */ zlog_warn ("ISIS-Adj: no IPv4 in LAN IIH from %s " "(this isisd has no IPv6)\n", circuit->interface->name); #else if (found & TLVFLAG_IPV6_ADDR) { /* TBA: check that we have a linklocal ourselves? */ struct listnode *node; struct in6_addr *ip; for (ALL_LIST_ELEMENTS_RO (tlvs.ipv6_addrs, node, ip)) if (IN6_IS_ADDR_LINKLOCAL (ip)) { v6_usable = 1; break; } if (!v6_usable) zlog_warn ("ISIS-Adj: IPv6 addresses present but no link-local " "in LAN IIH from %s\n", circuit->interface->name); } if (!(found & (TLVFLAG_IPV4_ADDR | TLVFLAG_IPV6_ADDR))) zlog_warn ("ISIS-Adj: neither IPv4 nor IPv6 addr in LAN IIH from %s\n", circuit->interface->name); #endif if (!v6_usable && !v4_usable) { free_tlvs (&tlvs); return ISIS_WARNING; } adj = isis_adj_lookup (hdr.source_id, circuit->u.bc.adjdb[level - 1]); if ((adj == NULL) || (memcmp(adj->snpa, ssnpa, ETH_ALEN)) || (adj->level != level)) { if (!adj) { /* * Do as in 8.4.2.5 */ adj = isis_new_adj (hdr.source_id, ssnpa, level, circuit); if (adj == NULL) { retval = ISIS_ERROR; goto out; } } else { if (ssnpa) { memcpy (adj->snpa, ssnpa, 6); } else { memset (adj->snpa, ' ', 6); } adj->level = level; } isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); if (level == IS_LEVEL_1) adj->sys_type = ISIS_SYSTYPE_L1_IS; else adj->sys_type = ISIS_SYSTYPE_L2_IS; list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], circuit->u.bc.lan_neighs[level - 1]); } if(adj->dis_record[level-1].dis==ISIS_IS_DIS) switch (level) { case 1: if (memcmp (circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l1_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } break; case 2: if (memcmp (circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1)) { thread_add_event (master, isis_event_dis_status_change, circuit, 0); memcpy (&circuit->u.bc.l2_desig_is, hdr.lan_id, ISIS_SYS_ID_LEN + 1); } break; } adj->hold_time = hdr.hold_time; adj->last_upd = time (NULL); adj->prio[level - 1] = hdr.prio; memcpy (adj->lanid, hdr.lan_id, ISIS_SYS_ID_LEN + 1); tlvs_to_adj_area_addrs (&tlvs, adj); /* which protocol are spoken ??? */ if (tlvs_to_adj_nlpids (&tlvs, adj)) { retval = ISIS_WARNING; goto out; } /* we need to copy addresses to the adj */ if (found & TLVFLAG_IPV4_ADDR) tlvs_to_adj_ipv4_addrs (&tlvs, adj); #ifdef HAVE_IPV6 if (found & TLVFLAG_IPV6_ADDR) tlvs_to_adj_ipv6_addrs (&tlvs, adj); #endif /* HAVE_IPV6 */ adj->circuit_t = hdr.circuit_t; /* lets take care of the expiry */ THREAD_TIMER_OFF (adj->t_expire); THREAD_TIMER_ON (master, adj->t_expire, isis_adj_expire, adj, (long) adj->hold_time); /* * If the snpa for this circuit is found from LAN Neighbours TLV * we have two-way communication -> adjacency can be put to state "up" */ if (found & TLVFLAG_LAN_NEIGHS) { if (adj->adj_state != ISIS_ADJ_UP) { for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) { if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) { isis_adj_state_change (adj, ISIS_ADJ_UP, "own SNPA found in LAN Neighbours TLV"); } } } else { int found = 0; for (ALL_LIST_ELEMENTS_RO (tlvs.lan_neighs, node, snpa)) if (!memcmp (snpa, circuit->u.bc.snpa, ETH_ALEN)) { found = 1; break; } if (found == 0) isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, "own SNPA not found in LAN Neighbours TLV"); } } else if (adj->adj_state == ISIS_ADJ_UP) { isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, "no LAN Neighbours TLV found"); } out: if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd L%d LAN IIH from %s on %s, cirType %s, " "cirID %u, length %ld", circuit->area->area_tag, level, snpa_print (ssnpa), circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id, stream_get_endp (circuit->rcv_stream)); } free_tlvs (&tlvs); return retval; } /* * Process Level 1/2 Link State * ISO - 10589 * Section 7.3.15.1 - Action on receipt of a link state PDU */ static int process_lsp (int level, struct isis_circuit *circuit, u_char * ssnpa) { struct isis_link_state_hdr *hdr; struct isis_adjacency *adj = NULL; struct isis_lsp *lsp, *lsp0 = NULL; int retval = ISIS_OK, comp = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_passwd *passwd; uint16_t pdu_len; if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_LSP_HDR_LEN) { zlog_warn ("Packet too short"); return ISIS_WARNING; } /* Reference the header */ hdr = (struct isis_link_state_hdr *) STREAM_PNT (circuit->rcv_stream); pdu_len = ntohs (hdr->pdu_len); /* lsp length check */ if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP length %d", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), pdu_len); return ISIS_WARNING; } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Rcvd L%d LSP %s, seq 0x%08x, cksum 0x%04x, " "lifetime %us, len %u, on %s", circuit->area->area_tag, level, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), pdu_len, circuit->interface->name); } /* lsp is_type check */ if ((hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1 && (hdr->lsp_bits & IS_LEVEL_1_AND_2) != IS_LEVEL_1_AND_2) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP is type %x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), hdr->lsp_bits); /* continue as per RFC1122 Be liberal in what you accept, and * conservative in what you send */ } /* Checksum sanity check - FIXME: move to correct place */ /* 12 = sysid+pdu+remtime */ if (iso_csum_verify (STREAM_PNT (circuit->rcv_stream) + 4, pdu_len - 12, &hdr->checksum)) { zlog_debug ("ISIS-Upd (%s): LSP %s invalid LSP checksum 0x%04x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohs (hdr->checksum)); return ISIS_WARNING; } /* 7.3.15.1 a) 1 - external domain circuit will discard lsps */ if (circuit->ext_domain) { zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit with " "externalDomain = true", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), level); return ISIS_WARNING; } /* 7.3.15.1 a) 2,3 - manualL2OnlyMode not implemented */ if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Upd (%s): LSP %s received at level %d over circuit of" " type %s", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), level, circuit_t2string (circuit->is_type)); return ISIS_WARNING; } /* 7.3.15.1 a) 4 - need to make sure IDLength matches */ /* 7.3.15.1 a) 5 - maximum area match, can be ommited since we only use 3 */ /* 7.3.15.1 a) 7 - password check */ (level == IS_LEVEL_1) ? (passwd = &circuit->area->area_passwd) : (passwd = &circuit->area->domain_passwd); if (passwd->type) { if (lsp_authentication_check (circuit->rcv_stream, circuit->area, level, passwd)) { isis_event_auth_failure (circuit->area->area_tag, "LSP authentication failure", hdr->lsp_id); return ISIS_WARNING; } } /* Find the LSP in our database and compare it to this Link State header */ lsp = lsp_search (hdr->lsp_id, circuit->area->lspdb[level - 1]); if (lsp) comp = lsp_compare (circuit->area->area_tag, lsp, hdr->seq_num, hdr->checksum, hdr->rem_lifetime); if (lsp && (lsp->own_lsp #ifdef TOPOLOGY_GENERATE || lsp->from_topology #endif /* TOPOLOGY_GENERATE */ )) goto dontcheckadj; /* 7.3.15.1 a) 6 - Must check that we have an adjacency of the same level */ /* for broadcast circuits, snpa should be compared */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { adj = isis_adj_lookup_snpa (ssnpa, circuit->u.bc.adjdb[level - 1]); if (!adj) { zlog_debug ("(%s): DS ======= LSP %s, seq 0x%08x, cksum 0x%04x, " "lifetime %us on %s", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (hdr->seq_num), ntohs (hdr->checksum), ntohs (hdr->rem_lifetime), circuit->interface->name); return ISIS_WARNING; /* Silently discard */ } } /* for non broadcast, we just need to find same level adj */ else { /* If no adj, or no sharing of level */ if (!circuit->u.p2p.neighbor) { return ISIS_OK; /* Silently discard */ } else { if (((level == IS_LEVEL_1) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL2)) || ((level == IS_LEVEL_2) && (circuit->u.p2p.neighbor->adj_usage == ISIS_ADJ_LEVEL1))) return ISIS_WARNING; /* Silently discard */ adj = circuit->u.p2p.neighbor; } } dontcheckadj: /* 7.3.15.1 a) 7 - Passwords for level 1 - not implemented */ /* 7.3.15.1 a) 8 - Passwords for level 2 - not implemented */ /* 7.3.15.1 a) 9 - OriginatingLSPBufferSize - not implemented FIXME: do it */ /* 7.3.15.1 b) - If the remaining life time is 0, we perform 7.3.16.4 */ if (hdr->rem_lifetime == 0) { if (!lsp) { /* 7.3.16.4 a) 1) No LSP in db -> send an ack, but don't save */ /* only needed on explicit update, eg - p2p */ if (circuit->circ_type == CIRCUIT_T_P2P) ack_lsp (hdr, circuit, level); return retval; /* FIXME: do we need a purge? */ } else { if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { /* LSP by some other system -> do 7.3.16.4 b) */ /* 7.3.16.4 b) 1) */ if (comp == LSP_NEWER) { lsp_update (lsp, circuit->rcv_stream, circuit->area, level); /* ii */ lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* v */ ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); /* FIXME: OTHER than c */ /* iv */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.16.4 b) 2) */ else if (comp == LSP_EQUAL) { /* i */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* ii */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.16.4 b) 3) */ else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } else if (lsp->lsp_header->rem_lifetime != 0) { /* our own LSP -> 7.3.16.4 c) */ if (comp == LSP_NEWER) { lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); lsp_set_all_srmflags (lsp); } else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (1) re-originating LSP %s new " "seq 0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); } } return retval; } /* 7.3.15.1 c) - If this is our own lsp and we don't have it initiate a * purge */ if (memcmp (hdr->lsp_id, isis->sysid, ISIS_SYS_ID_LEN) == 0) { if (!lsp) { /* 7.3.16.4: initiate a purge */ lsp_purge_non_exist (hdr, circuit->area); return ISIS_OK; } /* 7.3.15.1 d) - If this is our own lsp and we have it */ /* In 7.3.16.1, If an Intermediate system R somewhere in the domain * has information that the current sequence number for source S is * "greater" than that held by S, ... */ if (ntohl (hdr->seq_num) > ntohl (lsp->lsp_header->seq_num)) { /* 7.3.16.1 */ lsp_inc_seqnum (lsp, ntohl (hdr->seq_num)); if (isis->debugs & DEBUG_UPDATE_PACKETS) zlog_debug ("ISIS-Upd (%s): (2) re-originating LSP %s new seq " "0x%08x", circuit->area->area_tag, rawlspid_print (hdr->lsp_id), ntohl (lsp->lsp_header->seq_num)); } /* If the received LSP is older or equal, * resend the LSP which will act as ACK */ lsp_set_all_srmflags (lsp); } else { /* 7.3.15.1 e) - This lsp originated on another system */ /* 7.3.15.1 e) 1) LSP newer than the one in db or no LSP in db */ if ((!lsp || comp == LSP_NEWER)) { /* * If this lsp is a frag, need to see if we have zero lsp present */ if (LSP_FRAGMENT (hdr->lsp_id) != 0) { memcpy (lspid, hdr->lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (lspid) = 0; lsp0 = lsp_search (lspid, circuit->area->lspdb[level - 1]); if (!lsp0) { zlog_debug ("Got lsp frag, while zero lsp not in database"); return ISIS_OK; } } /* i */ if (!lsp) { lsp = lsp_new_from_stream_ptr (circuit->rcv_stream, pdu_len, lsp0, circuit->area, level); lsp_insert (lsp, circuit->area->lspdb[level - 1]); } else /* exists, so we overwrite */ { lsp_update (lsp, circuit->rcv_stream, circuit->area, level); } /* ii */ lsp_set_all_srmflags (lsp); /* iii */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); /* iv */ if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); /* FIXME: v) */ } /* 7.3.15.1 e) 2) LSP equal to the one in db */ else if (comp == LSP_EQUAL) { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); lsp_update (lsp, circuit->rcv_stream, circuit->area, level); if (circuit->circ_type != CIRCUIT_T_BROADCAST) ISIS_SET_FLAG (lsp->SSNflags, circuit); } /* 7.3.15.1 e) 3) LSP older than the one in db */ else { ISIS_SET_FLAG (lsp->SRMflags, circuit); ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); } } return retval; } /* * Process Sequence Numbers * ISO - 10589 * Section 7.3.15.2 - Action on receipt of a sequence numbers PDU */ static int process_snp (int snp_type, int level, struct isis_circuit *circuit, u_char * ssnpa) { int retval = ISIS_OK; int cmp, own_lsp; char typechar = ' '; uint16_t pdu_len; struct isis_adjacency *adj; struct isis_complete_seqnum_hdr *chdr = NULL; struct isis_partial_seqnum_hdr *phdr = NULL; uint32_t found = 0, expected = 0, auth_tlv_offset = 0; struct isis_lsp *lsp; struct lsp_entry *entry; struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct tlvs tlvs; struct list *lsp_list = NULL; struct isis_passwd *passwd; if (snp_type == ISIS_SNP_CSNP_FLAG) { /* getting the header info */ typechar = 'C'; chdr = (struct isis_complete_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_CSNP_HDRLEN); pdu_len = ntohs (chdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_CSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("Received a CSNP with bogus length %d", pdu_len); return ISIS_WARNING; } } else { typechar = 'P'; phdr = (struct isis_partial_seqnum_hdr *) STREAM_PNT (circuit->rcv_stream); stream_forward_getp (circuit->rcv_stream, ISIS_PSNP_HDRLEN); pdu_len = ntohs (phdr->pdu_len); if (pdu_len < (ISIS_FIXED_HDR_LEN + ISIS_PSNP_HDRLEN) || pdu_len > ISO_MTU(circuit) || pdu_len > stream_get_endp (circuit->rcv_stream)) { zlog_warn ("Received a CSNP with bogus length %d", pdu_len); return ISIS_WARNING; } } /* * Set the stream endp to PDU length, ignoring additional padding * introduced by transport chips. */ if (pdu_len < stream_get_endp (circuit->rcv_stream)) stream_set_endp (circuit->rcv_stream, pdu_len); /* 7.3.15.2 a) 1 - external domain circuit will discard snp pdu */ if (circuit->ext_domain) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " "skipping: circuit externalDomain = true", circuit->area->area_tag, level, typechar, circuit->interface->name); return ISIS_OK; } /* 7.3.15.2 a) 2,3 - manualL2OnlyMode not implemented */ if (!accept_level (level, circuit->is_type)) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP on %s, " "skipping: circuit type %s does not match level %d", circuit->area->area_tag, level, typechar, circuit->interface->name, circuit_t2string (circuit->is_type), level); return ISIS_OK; } /* 7.3.15.2 a) 4 - not applicable for CSNP only PSNPs on broadcast */ if ((snp_type == ISIS_SNP_PSNP_FLAG) && (circuit->circ_type == CIRCUIT_T_BROADCAST) && (!circuit->u.bc.is_dr[level - 1])) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s, " "skipping: we are not the DIS", circuit->area->area_tag, level, typechar, snpa_print (ssnpa), circuit->interface->name); return ISIS_OK; } /* 7.3.15.2 a) 5 - need to make sure IDLength matches - already checked */ /* 7.3.15.2 a) 6 - maximum area match, can be ommited since we only use 3 * - already checked */ /* 7.3.15.2 a) 7 - Must check that we have an adjacency of the same level */ /* for broadcast circuits, snpa should be compared */ /* FIXME : Do we need to check SNPA? */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { if (snp_type == ISIS_SNP_CSNP_FLAG) { adj = isis_adj_lookup (chdr->source_id, circuit->u.bc.adjdb[level - 1]); } else { /* a psnp on a broadcast, how lovely of Juniper :) */ adj = isis_adj_lookup (phdr->source_id, circuit->u.bc.adjdb[level - 1]); } if (!adj) return ISIS_OK; /* Silently discard */ } else { if (!circuit->u.p2p.neighbor) { zlog_warn ("no p2p neighbor on circuit %s", circuit->interface->name); return ISIS_OK; /* Silently discard */ } } /* 7.3.15.2 a) 8 - Passwords for level 1 - not implemented */ /* 7.3.15.2 a) 9 - Passwords for level 2 - not implemented */ memset (&tlvs, 0, sizeof (struct tlvs)); /* parse the SNP */ expected |= TLVFLAG_LSP_ENTRIES; expected |= TLVFLAG_AUTH_INFO; auth_tlv_offset = stream_get_getp (circuit->rcv_stream); retval = parse_tlvs (circuit->area->area_tag, STREAM_PNT (circuit->rcv_stream), pdu_len - stream_get_getp (circuit->rcv_stream), &expected, &found, &tlvs, &auth_tlv_offset); if (retval > ISIS_WARNING) { zlog_warn ("something went very wrong processing SNP"); free_tlvs (&tlvs); return retval; } if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_RECV)) { if (passwd->type) { if (!(found & TLVFLAG_AUTH_INFO) || authentication_check (&tlvs.auth_info, passwd, circuit->rcv_stream, auth_tlv_offset)) { isis_event_auth_failure (circuit->area->area_tag, "SNP authentication" " failure", phdr ? phdr->source_id : chdr->source_id); free_tlvs (&tlvs); return ISIS_OK; } } } /* debug isis snp-packets */ if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d %cSNP from %s on %s", circuit->area->area_tag, level, typechar, snpa_print (ssnpa), circuit->interface->name); if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) { zlog_debug ("ISIS-Snp (%s): %cSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, typechar, rawlspid_print (entry->lsp_id), ntohl (entry->seq_num), ntohs (entry->checksum), ntohs (entry->rem_lifetime)); } } } /* 7.3.15.2 b) Actions on LSP_ENTRIES reported */ if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS_RO (tlvs.lsp_entries, node, entry)) { lsp = lsp_search (entry->lsp_id, circuit->area->lspdb[level - 1]); own_lsp = !memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN); if (lsp) { /* 7.3.15.2 b) 1) is this LSP newer */ cmp = lsp_compare (circuit->area->area_tag, lsp, entry->seq_num, entry->checksum, entry->rem_lifetime); /* 7.3.15.2 b) 2) if it equals, clear SRM on p2p */ if (cmp == LSP_EQUAL) { /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } /* 7.3.15.2 b) 3) if it is older, clear SSN and set SRM */ else if (cmp == LSP_OLDER) { ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); ISIS_SET_FLAG (lsp->SRMflags, circuit); } /* 7.3.15.2 b) 4) if it is newer, set SSN and clear SRM on p2p */ else { if (own_lsp) { lsp_inc_seqnum (lsp, ntohl (entry->seq_num)); ISIS_SET_FLAG (lsp->SRMflags, circuit); } else { ISIS_SET_FLAG (lsp->SSNflags, circuit); /* if (circuit->circ_type != CIRCUIT_T_BROADCAST) */ ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } } } else { /* 7.3.15.2 b) 5) if it was not found, and all of those are not 0, * insert it and set SSN on it */ if (entry->rem_lifetime && entry->checksum && entry->seq_num && memcmp (entry->lsp_id, isis->sysid, ISIS_SYS_ID_LEN)) { lsp = lsp_new (entry->lsp_id, ntohs (entry->rem_lifetime), 0, 0, entry->checksum, level); lsp->area = circuit->area; lsp_insert (lsp, circuit->area->lspdb[level - 1]); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); ISIS_SET_FLAG (lsp->SSNflags, circuit); } } } } /* 7.3.15.2 c) on CSNP set SRM for all in range which were not reported */ if (snp_type == ISIS_SNP_CSNP_FLAG) { /* * Build a list from our own LSP db bounded with * start_lsp_id and stop_lsp_id */ lsp_list = list_new (); lsp_build_list_nonzero_ht (chdr->start_lsp_id, chdr->stop_lsp_id, lsp_list, circuit->area->lspdb[level - 1]); /* Fixme: Find a better solution */ if (tlvs.lsp_entries) { for (ALL_LIST_ELEMENTS (tlvs.lsp_entries, node, nnode, entry)) { for (ALL_LIST_ELEMENTS (lsp_list, node2, nnode2, lsp)) { if (lsp_id_cmp (lsp->lsp_header->lsp_id, entry->lsp_id) == 0) { list_delete_node (lsp_list, node2); break; } } } } /* on remaining LSPs we set SRM (neighbor knew not of) */ for (ALL_LIST_ELEMENTS_RO (lsp_list, node, lsp)) ISIS_SET_FLAG (lsp->SRMflags, circuit); /* lets free it */ list_delete (lsp_list); } free_tlvs (&tlvs); return retval; } static int process_csnp (int level, struct isis_circuit *circuit, u_char * ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d CSNP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } /* Sanity check - FIXME: move to correct place */ if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_CSNP_HDRLEN) { zlog_warn ("Packet too short ( < %d)", ISIS_CSNP_HDRLEN); return ISIS_WARNING; } return process_snp (ISIS_SNP_CSNP_FLAG, level, circuit, ssnpa); } static int process_psnp (int level, struct isis_circuit *circuit, u_char * ssnpa) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Rcvd L%d PSNP on %s, cirType %s, cirID %u", circuit->area->area_tag, level, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } if ((stream_get_endp (circuit->rcv_stream) - stream_get_getp (circuit->rcv_stream)) < ISIS_PSNP_HDRLEN) { zlog_warn ("Packet too short ( < %d)", ISIS_PSNP_HDRLEN); return ISIS_WARNING; } return process_snp (ISIS_SNP_PSNP_FLAG, level, circuit, ssnpa); } /* * Process ISH * ISO - 10589 * Section 8.2.2 - Receiving ISH PDUs by an intermediate system * FIXME: sample packet dump, need to figure 0x81 - looks like NLPid * 0x82 0x15 0x01 0x00 0x04 0x01 0x2c 0x59 * 0x38 0x08 0x47 0x00 0x01 0x00 0x02 0x00 * 0x03 0x00 0x81 0x01 0xcc */ static int process_is_hello (struct isis_circuit *circuit) { struct isis_adjacency *adj; int retval = ISIS_OK; u_char neigh_len; u_char *sysid; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Rcvd ISH on %s, cirType %s, cirID %u", circuit->area->area_tag, circuit->interface->name, circuit_t2string (circuit->is_type), circuit->circuit_id); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->rcv_stream), stream_get_endp (circuit->rcv_stream)); } /* In this point in time we are not yet able to handle is_hellos * on lan - Sorry juniper... */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) return retval; neigh_len = stream_getc (circuit->rcv_stream); sysid = STREAM_PNT (circuit->rcv_stream) + neigh_len - 1 - ISIS_SYS_ID_LEN; adj = circuit->u.p2p.neighbor; if (!adj) { /* 8.2.2 */ adj = isis_new_adj (sysid, NULL, 0, circuit); if (adj == NULL) return ISIS_ERROR; isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); adj->sys_type = ISIS_SYSTYPE_UNKNOWN; circuit->u.p2p.neighbor = adj; } /* 8.2.2 a) */ if ((adj->adj_state == ISIS_ADJ_UP) && memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN)) { /* 8.2.2 a) 1) FIXME: adjStateChange(down) event */ /* 8.2.2 a) 2) delete the adj */ XFREE (MTYPE_ISIS_ADJACENCY, adj); /* 8.2.2 a) 3) create a new adj */ adj = isis_new_adj (sysid, NULL, 0, circuit); if (adj == NULL) return ISIS_ERROR; /* 8.2.2 a) 3) i */ isis_adj_state_change (adj, ISIS_ADJ_INITIALIZING, NULL); /* 8.2.2 a) 3) ii */ adj->sys_type = ISIS_SYSTYPE_UNKNOWN; /* 8.2.2 a) 4) quite meaningless */ } /* 8.2.2 b) ignore on condition */ if ((adj->adj_state == ISIS_ADJ_INITIALIZING) && (adj->sys_type == ISIS_SYSTYPE_IS)) { /* do nothing */ } else { /* 8.2.2 c) respond with a p2p IIH */ send_hello (circuit, 1); } /* 8.2.2 d) type is IS */ adj->sys_type = ISIS_SYSTYPE_IS; /* 8.2.2 e) FIXME: Circuit type of? */ return retval; } /* * PDU Dispatcher */ static int isis_handle_pdu (struct isis_circuit *circuit, u_char * ssnpa) { struct isis_fixed_hdr *hdr; int retval = ISIS_OK; /* * Let's first read data from stream to the header */ hdr = (struct isis_fixed_hdr *) STREAM_DATA (circuit->rcv_stream); if ((hdr->idrp != ISO10589_ISIS) && (hdr->idrp != ISO9542_ESIS)) { zlog_err ("Not an IS-IS or ES-IS packet IDRP=%02x", hdr->idrp); return ISIS_ERROR; } /* now we need to know if this is an ISO 9542 packet and * take real good care of it, waaa! */ if (hdr->idrp == ISO9542_ESIS) { zlog_err ("No support for ES-IS packet IDRP=%02x", hdr->idrp); return ISIS_ERROR; } stream_set_getp (circuit->rcv_stream, ISIS_FIXED_HDR_LEN); /* * and then process it */ if (hdr->length < ISIS_MINIMUM_FIXED_HDR_LEN) { zlog_err ("Fixed header length = %d", hdr->length); return ISIS_ERROR; } if (hdr->version1 != 1) { zlog_warn ("Unsupported ISIS version %u", hdr->version1); return ISIS_WARNING; } /* either 6 or 0 */ if ((hdr->id_len != 0) && (hdr->id_len != ISIS_SYS_ID_LEN)) { zlog_err ("IDFieldLengthMismatch: ID Length field in a received PDU %u, " "while the parameter for this IS is %u", hdr->id_len, ISIS_SYS_ID_LEN); return ISIS_ERROR; } if (hdr->version2 != 1) { zlog_warn ("Unsupported ISIS version %u", hdr->version2); return ISIS_WARNING; } if (circuit->is_passive) { zlog_warn ("Received ISIS PDU on passive circuit %s", circuit->interface->name); return ISIS_WARNING; } /* either 3 or 0 */ if ((hdr->max_area_addrs != 0) && (hdr->max_area_addrs != isis->max_area_addrs)) { zlog_err ("maximumAreaAddressesMismatch: maximumAreaAdresses in a " "received PDU %u while the parameter for this IS is %u", hdr->max_area_addrs, isis->max_area_addrs); return ISIS_ERROR; } switch (hdr->pdu_type) { case L1_LAN_HELLO: retval = process_lan_hello (ISIS_LEVEL1, circuit, ssnpa); break; case L2_LAN_HELLO: retval = process_lan_hello (ISIS_LEVEL2, circuit, ssnpa); break; case P2P_HELLO: retval = process_p2p_hello (circuit); break; case L1_LINK_STATE: retval = process_lsp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_LINK_STATE: retval = process_lsp (ISIS_LEVEL2, circuit, ssnpa); break; case L1_COMPLETE_SEQ_NUM: retval = process_csnp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_COMPLETE_SEQ_NUM: retval = process_csnp (ISIS_LEVEL2, circuit, ssnpa); break; case L1_PARTIAL_SEQ_NUM: retval = process_psnp (ISIS_LEVEL1, circuit, ssnpa); break; case L2_PARTIAL_SEQ_NUM: retval = process_psnp (ISIS_LEVEL2, circuit, ssnpa); break; default: return ISIS_ERROR; } return retval; } #ifdef GNU_LINUX int isis_receive (struct thread *thread) { struct isis_circuit *circuit; u_char ssnpa[ETH_ALEN]; int retval; /* * Get the circuit */ circuit = THREAD_ARG (thread); assert (circuit); if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); circuit->t_read = NULL; if (retval == ISIS_OK) retval = isis_handle_pdu (circuit, ssnpa); /* * prepare for next packet. */ if (!circuit->is_passive) { THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); } return retval; } #else int isis_receive (struct thread *thread) { struct isis_circuit *circuit; u_char ssnpa[ETH_ALEN]; int retval; /* * Get the circuit */ circuit = THREAD_ARG (thread); assert (circuit); circuit->t_read = NULL; if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->rcv_stream); retval = circuit->rx (circuit, ssnpa); if (retval == ISIS_OK) retval = isis_handle_pdu (circuit, ssnpa); /* * prepare for next packet. */ if (!circuit->is_passive) { circuit->t_read = thread_add_timer_msec (master, isis_receive, circuit, listcount (circuit->area->circuit_list) * 100); } return retval; } #endif /* filling of the fixed isis header */ void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type) { memset (hdr, 0, sizeof (struct isis_fixed_hdr)); hdr->idrp = ISO10589_ISIS; switch (pdu_type) { case L1_LAN_HELLO: case L2_LAN_HELLO: hdr->length = ISIS_LANHELLO_HDRLEN; break; case P2P_HELLO: hdr->length = ISIS_P2PHELLO_HDRLEN; break; case L1_LINK_STATE: case L2_LINK_STATE: hdr->length = ISIS_LSP_HDR_LEN; break; case L1_COMPLETE_SEQ_NUM: case L2_COMPLETE_SEQ_NUM: hdr->length = ISIS_CSNP_HDRLEN; break; case L1_PARTIAL_SEQ_NUM: case L2_PARTIAL_SEQ_NUM: hdr->length = ISIS_PSNP_HDRLEN; break; default: zlog_warn ("fill_fixed_hdr(): unknown pdu type %d", pdu_type); return; } hdr->length += ISIS_FIXED_HDR_LEN; hdr->pdu_type = pdu_type; hdr->version1 = 1; hdr->id_len = 0; /* ISIS_SYS_ID_LEN - 0==6 */ hdr->version2 = 1; hdr->max_area_addrs = 0; /* isis->max_area_addrs - 0==3 */ } /* * SEND SIDE */ static void fill_fixed_hdr_andstream (struct isis_fixed_hdr *hdr, u_char pdu_type, struct stream *stream) { fill_fixed_hdr (hdr, pdu_type); stream_putc (stream, hdr->idrp); stream_putc (stream, hdr->length); stream_putc (stream, hdr->version1); stream_putc (stream, hdr->id_len); stream_putc (stream, hdr->pdu_type); stream_putc (stream, hdr->version2); stream_putc (stream, hdr->reserved); stream_putc (stream, hdr->max_area_addrs); return; } int send_hello (struct isis_circuit *circuit, int level) { struct isis_fixed_hdr fixed_hdr; struct isis_lan_hello_hdr hello_hdr; struct isis_p2p_hello_hdr p2p_hello_hdr; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; unsigned long len_pointer, length, auth_tlv_offset = 0; u_int32_t interval; int retval; if (circuit->is_passive) return ISIS_OK; if (circuit->interface->mtu == 0) { zlog_warn ("circuit has zero MTU"); return ISIS_WARNING; } if (!circuit->snd_stream) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->snd_stream); if (circuit->circ_type == CIRCUIT_T_BROADCAST) if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_LAN_HELLO, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_LAN_HELLO, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, P2P_HELLO, circuit->snd_stream); /* * Fill LAN Level 1 or 2 Hello PDU header */ memset (&hello_hdr, 0, sizeof (struct isis_lan_hello_hdr)); interval = circuit->hello_multiplier[level - 1] * circuit->hello_interval[level - 1]; if (interval > USHRT_MAX) interval = USHRT_MAX; hello_hdr.circuit_t = circuit->is_type; memcpy (hello_hdr.source_id, isis->sysid, ISIS_SYS_ID_LEN); hello_hdr.hold_time = htons ((u_int16_t) interval); hello_hdr.pdu_len = 0; /* Update the PDU Length later */ len_pointer = stream_get_endp (circuit->snd_stream) + 3 + ISIS_SYS_ID_LEN; /* copy the shared part of the hello to the p2p hello if needed */ if (circuit->circ_type == CIRCUIT_T_P2P) { memcpy (&p2p_hello_hdr, &hello_hdr, 5 + ISIS_SYS_ID_LEN); p2p_hello_hdr.local_id = circuit->circuit_id; /* FIXME: need better understanding */ stream_put (circuit->snd_stream, &p2p_hello_hdr, ISIS_P2PHELLO_HDRLEN); } else { hello_hdr.prio = circuit->priority[level - 1]; if (level == IS_LEVEL_1) { memcpy (hello_hdr.lan_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); } else if (level == IS_LEVEL_2) { memcpy (hello_hdr.lan_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); } stream_put (circuit->snd_stream, &hello_hdr, ISIS_LANHELLO_HDRLEN); } /* * Then the variable length part. */ /* add circuit password */ switch (circuit->passwd.type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len, circuit->passwd.passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (circuit->passwd.type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } /* Area Addresses TLV */ if (listcount (circuit->area->area_addrs) == 0) return ISIS_WARNING; if (tlv_add_area_addrs (circuit->area->area_addrs, circuit->snd_stream)) return ISIS_WARNING; /* LAN Neighbors TLV */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) { if (level == IS_LEVEL_1 && circuit->u.bc.lan_neighs[0] && listcount (circuit->u.bc.lan_neighs[0]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[0], circuit->snd_stream)) return ISIS_WARNING; if (level == IS_LEVEL_2 && circuit->u.bc.lan_neighs[1] && listcount (circuit->u.bc.lan_neighs[1]) > 0) if (tlv_add_lan_neighs (circuit->u.bc.lan_neighs[1], circuit->snd_stream)) return ISIS_WARNING; } /* Protocols Supported TLV */ if (circuit->nlpids.count > 0) if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream)) return ISIS_WARNING; /* IP interface Address TLV */ if (circuit->ip_router && circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) if (tlv_add_ip_addrs (circuit->ip_addrs, circuit->snd_stream)) return ISIS_WARNING; #ifdef HAVE_IPV6 /* IPv6 Interface Address TLV */ if (circuit->ipv6_router && circuit->ipv6_link && listcount (circuit->ipv6_link) > 0) if (tlv_add_ipv6_addrs (circuit->ipv6_link, circuit->snd_stream)) return ISIS_WARNING; #endif /* HAVE_IPV6 */ if (circuit->pad_hellos) if (tlv_add_padding (circuit->snd_stream)) return ISIS_WARNING; length = stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (caddr_t) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } if (isis->debugs & DEBUG_ADJ_PACKETS) { if (circuit->circ_type == CIRCUIT_T_BROADCAST) { zlog_debug ("ISIS-Adj (%s): Sent L%d LAN IIH on %s, length %ld", circuit->area->area_tag, level, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ length); } else { zlog_debug ("ISIS-Adj (%s): Sent P2P IIH on %s, length %ld", circuit->area->area_tag, circuit->interface->name, /* FIXME: use %z when we stop supporting old compilers. */ length); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) zlog_err ("ISIS-Adj (%s): Send L%d IIH on %s failed", circuit->area->area_tag, level, circuit->interface->name); return retval; } int send_lan_l1_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.bc.t_send_lan_hello[0] = NULL; if (circuit->u.bc.run_dr_elect[0]) retval = isis_dr_elect (circuit, 1); retval = send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[0], send_lan_l1_hello, circuit, isis_jitter (circuit->hello_interval[0], IIH_JITTER)); return retval; } int send_lan_l2_hello (struct thread *thread) { struct isis_circuit *circuit; int retval; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.bc.t_send_lan_hello[1] = NULL; if (circuit->u.bc.run_dr_elect[1]) retval = isis_dr_elect (circuit, 2); retval = send_hello (circuit, 2); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.bc.t_send_lan_hello[1], send_lan_l2_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); return retval; } int send_p2p_hello (struct thread *thread) { struct isis_circuit *circuit; circuit = THREAD_ARG (thread); assert (circuit); circuit->u.p2p.t_send_p2p_hello = NULL; send_hello (circuit, 1); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->u.p2p.t_send_p2p_hello, send_p2p_hello, circuit, isis_jitter (circuit->hello_interval[1], IIH_JITTER)); return ISIS_OK; } static int build_csnp (int level, u_char * start, u_char * stop, struct list *lsps, struct isis_circuit *circuit) { struct isis_fixed_hdr fixed_hdr; struct isis_passwd *passwd; unsigned long lenp; u_int16_t length; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_COMPLETE_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_COMPLETE_SEQ_NUM, circuit->snd_stream); /* * Fill Level 1 or 2 Complete Sequence Numbers header */ lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ /* no need to send the source here, it is always us if we csnp */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); /* with zero circuit id - ref 9.10, 9.11 */ stream_putc (circuit->snd_stream, 0x00); stream_put (circuit->snd_stream, start, ISIS_SYS_ID_LEN + 2); stream_put (circuit->snd_stream, stop, ISIS_SYS_ID_LEN + 2); /* * And TLVs */ if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, passwd->passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } } retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); if (retval != ISIS_OK) return retval; length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PU length */ stream_putw_at (circuit->snd_stream, lenp, length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, (caddr_t) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } return retval; } /* * Count the maximum number of lsps that can be accomodated by a given size. */ static uint16_t get_max_lsp_count (uint16_t size) { uint16_t tlv_count; uint16_t lsp_count; uint16_t remaining_size; /* First count the full size TLVs */ tlv_count = size / MAX_LSP_ENTRIES_TLV_SIZE; lsp_count = tlv_count * (MAX_LSP_ENTRIES_TLV_SIZE / LSP_ENTRIES_LEN); /* The last TLV, if any */ remaining_size = size % MAX_LSP_ENTRIES_TLV_SIZE; if (remaining_size - 2 >= LSP_ENTRIES_LEN) lsp_count += (remaining_size - 2) / LSP_ENTRIES_LEN; return lsp_count; } /* * Calculate the length of Authentication Info. TLV. */ static uint16_t auth_tlv_length (int level, struct isis_circuit *circuit) { struct isis_passwd *passwd; uint16_t length; if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; /* Also include the length of TLV header */ length = AUTH_INFO_HDRLEN; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: length += passwd->len; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: length += ISIS_AUTH_MD5_SIZE; break; default: break; } } return length; } /* * Calculate the maximum number of lsps that can be accomodated in a CSNP/PSNP. */ static uint16_t max_lsps_per_snp (int snp_type, int level, struct isis_circuit *circuit) { int snp_hdr_len; int auth_tlv_len; uint16_t lsp_count; snp_hdr_len = ISIS_FIXED_HDR_LEN; if (snp_type == ISIS_SNP_CSNP_FLAG) snp_hdr_len += ISIS_CSNP_HDRLEN; else snp_hdr_len += ISIS_PSNP_HDRLEN; auth_tlv_len = auth_tlv_length (level, circuit); lsp_count = get_max_lsp_count ( stream_get_size (circuit->snd_stream) - snp_hdr_len - auth_tlv_len); return lsp_count; } /* * FIXME: support multiple CSNPs */ int send_csnp (struct isis_circuit *circuit, int level) { u_char start[ISIS_SYS_ID_LEN + 2]; u_char stop[ISIS_SYS_ID_LEN + 2]; struct list *list = NULL; struct listnode *node; struct isis_lsp *lsp; u_char num_lsps, loop = 1; int i, retval = ISIS_OK; if (circuit->area->lspdb[level - 1] == NULL || dict_count (circuit->area->lspdb[level - 1]) == 0) return retval; memset (start, 0x00, ISIS_SYS_ID_LEN + 2); memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); num_lsps = max_lsps_per_snp (ISIS_SNP_CSNP_FLAG, level, circuit); while (loop) { list = list_new (); lsp_build_list (start, stop, num_lsps, list, circuit->area->lspdb[level - 1]); /* * Update the stop lsp_id before encoding this CSNP. */ if (listcount (list) < num_lsps) { memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); } else { node = listtail (list); lsp = listgetdata (node); memcpy (stop, lsp->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 2); } retval = build_csnp (level, start, stop, list, circuit); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Build L%d CSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Sent L%d CSNP on %s, length %ld", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) { zlog_debug ("ISIS-Snp (%s): CSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Send L%d CSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } /* * Start lsp_id of the next CSNP should be one plus the * stop lsp_id in this current CSNP. */ memcpy (start, stop, ISIS_SYS_ID_LEN + 2); loop = 0; for (i = ISIS_SYS_ID_LEN + 1; i >= 0; --i) { if (start[i] < (u_char)0xff) { start[i] += 1; loop = 1; break; } } memset (stop, 0xff, ISIS_SYS_ID_LEN + 2); list_delete (list); } return retval; } int send_l1_csnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_csnp[0] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0]) { send_csnp (circuit, 1); } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit, isis_jitter (circuit->csnp_interval[0], CSNP_JITTER)); return retval; } int send_l2_csnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_csnp[1] = NULL; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1]) { send_csnp (circuit, 2); } /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit, isis_jitter (circuit->csnp_interval[1], CSNP_JITTER)); return retval; } static int build_psnp (int level, struct isis_circuit *circuit, struct list *lsps) { struct isis_fixed_hdr fixed_hdr; unsigned long lenp; u_int16_t length; struct isis_lsp *lsp; struct isis_passwd *passwd; struct listnode *node; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; unsigned long auth_tlv_offset = 0; int retval = ISIS_OK; if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->snd_stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, circuit->snd_stream); /* * Fill Level 1 or 2 Partial Sequence Numbers header */ lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length - when we know it */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); stream_putc (circuit->snd_stream, circuit->idx); /* * And TLVs */ if (level == IS_LEVEL_1) passwd = &circuit->area->area_passwd; else passwd = &circuit->area->domain_passwd; if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND)) { switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, passwd->len, passwd->passwd, circuit->snd_stream)) return ISIS_WARNING; break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later overwrite the MD5 hash */ auth_tlv_offset = stream_get_endp (circuit->snd_stream); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, circuit->snd_stream)) return ISIS_WARNING; break; default: break; } } retval = tlv_add_lsp_entries (lsps, circuit->snd_stream); if (retval != ISIS_OK) return retval; if (isis->debugs & DEBUG_SNP_PACKETS) { for (ALL_LIST_ELEMENTS_RO (lsps, node, lsp)) { zlog_debug ("ISIS-Snp (%s): PSNP entry %s, seq 0x%08x," " cksum 0x%04x, lifetime %us", circuit->area->area_tag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } } length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, lenp, length); /* For HMAC MD5 we need to compute the md5 hash and store it */ if (CHECK_FLAG(passwd->snp_auth, SNP_AUTH_SEND) && passwd->type == ISIS_PASSWD_TYPE_HMAC_MD5) { hmac_md5 (STREAM_DATA (circuit->snd_stream), stream_get_endp(circuit->snd_stream), (unsigned char *) &passwd->passwd, passwd->len, (caddr_t) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (circuit->snd_stream) + auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); } return ISIS_OK; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 1 */ static int send_psnp (int level, struct isis_circuit *circuit) { struct isis_lsp *lsp; struct list *list = NULL; struct listnode *node; u_char num_lsps; int retval = ISIS_OK; if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[level - 1]) return ISIS_OK; if (circuit->area->lspdb[level - 1] == NULL || dict_count (circuit->area->lspdb[level - 1]) == 0) return ISIS_OK; if (! circuit->snd_stream) return ISIS_ERROR; num_lsps = max_lsps_per_snp (ISIS_SNP_PSNP_FLAG, level, circuit); while (1) { list = list_new (); lsp_build_list_ssn (circuit, num_lsps, list, circuit->area->lspdb[level - 1]); if (listcount (list) == 0) { list_delete (list); return ISIS_OK; } retval = build_psnp (level, circuit, list); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Build L%d PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Sent L%d PSNP on %s, length %ld", circuit->area->area_tag, level, circuit->interface->name, stream_get_endp (circuit->snd_stream)); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, level); if (retval != ISIS_OK) { zlog_err ("ISIS-Snp (%s): Send L%d PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); list_delete (list); return retval; } /* * sending succeeded, we can clear SSN flags of this circuit * for the LSPs in list */ for (ALL_LIST_ELEMENTS_RO (list, node, lsp)) ISIS_CLEAR_FLAG (lsp->SSNflags, circuit); list_delete (list); } return retval; } int send_l1_psnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_psnp[0] = NULL; send_psnp (1, circuit); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); return retval; } /* * 7.3.15.4 action on expiration of partial SNP interval * level 2 */ int send_l2_psnp (struct thread *thread) { struct isis_circuit *circuit; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); circuit->t_send_psnp[1] = NULL; send_psnp (2, circuit); /* set next timer thread */ THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); return retval; } /* * ISO 10589 - 7.3.14.3 */ int send_lsp (struct thread *thread) { struct isis_circuit *circuit; struct isis_lsp *lsp; struct listnode *node; int retval = ISIS_OK; circuit = THREAD_ARG (thread); assert (circuit); if (circuit->state != C_STATE_UP || circuit->is_passive == 1) { return retval; } node = listhead (circuit->lsp_queue); /* * Handle case where there are no LSPs on the queue. This can * happen, for instance, if an adjacency goes down before this * thread gets a chance to run. */ if (!node) { return retval; } lsp = listgetdata(node); /* * Do not send if levels do not match */ if (!(lsp->level & circuit->is_type)) { list_delete_node (circuit->lsp_queue, node); return retval; } /* * Do not send if we do not have adjacencies in state up on the circuit */ if (circuit->upadjcount[lsp->level - 1] == 0) { list_delete_node (circuit->lsp_queue, node); return retval; } /* copy our lsp to the send buffer */ stream_copy (circuit->snd_stream, lsp->pdu); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Sent L%d LSP %s, seq 0x%08x, cksum 0x%04x," " lifetime %us on %s", circuit->area->area_tag, lsp->level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), circuit->interface->name); if (isis->debugs & DEBUG_PACKET_DUMP) zlog_dump_data (STREAM_DATA (circuit->snd_stream), stream_get_endp (circuit->snd_stream)); } retval = circuit->tx (circuit, lsp->level); if (retval != ISIS_OK) { zlog_err ("ISIS-Upd (%s): Send L%d LSP on %s failed", circuit->area->area_tag, lsp->level, circuit->interface->name); return retval; } /* * If the sending succeeded, we can del the lsp from circuits * lsp_queue */ list_delete_node (circuit->lsp_queue, node); /* Set the last-cleared time if the queue is empty. */ /* TODO: Is is possible that new lsps keep being added to the queue * that the queue is never empty? */ if (list_isempty (circuit->lsp_queue)) circuit->lsp_queue_last_cleared = time (NULL); /* * On broadcast circuits also the SRMflag can be cleared */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); return retval; } int ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, int level) { unsigned long lenp; int retval; u_int16_t length; struct isis_fixed_hdr fixed_hdr; if (!circuit->snd_stream) circuit->snd_stream = stream_new (ISO_MTU (circuit)); else stream_reset (circuit->snd_stream); // fill_llc_hdr (stream); if (level == IS_LEVEL_1) fill_fixed_hdr_andstream (&fixed_hdr, L1_PARTIAL_SEQ_NUM, circuit->snd_stream); else fill_fixed_hdr_andstream (&fixed_hdr, L2_PARTIAL_SEQ_NUM, circuit->snd_stream); lenp = stream_get_endp (circuit->snd_stream); stream_putw (circuit->snd_stream, 0); /* PDU length */ stream_put (circuit->snd_stream, isis->sysid, ISIS_SYS_ID_LEN); stream_putc (circuit->snd_stream, circuit->idx); stream_putc (circuit->snd_stream, 9); /* code */ stream_putc (circuit->snd_stream, 16); /* len */ stream_putw (circuit->snd_stream, ntohs (hdr->rem_lifetime)); stream_put (circuit->snd_stream, hdr->lsp_id, ISIS_SYS_ID_LEN + 2); stream_putl (circuit->snd_stream, ntohl (hdr->seq_num)); stream_putw (circuit->snd_stream, ntohs (hdr->checksum)); length = (u_int16_t) stream_get_endp (circuit->snd_stream); /* Update PDU length */ stream_putw_at (circuit->snd_stream, lenp, length); retval = circuit->tx (circuit, level); if (retval != ISIS_OK) zlog_err ("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed", circuit->area->area_tag, level, circuit->interface->name); return retval; } quagga-0.99.24.1/isisd/isis_circuit.c0000644000175000017500000023434212476520570014214 00000000000000/* * IS-IS Rout(e)ing protocol - isis_circuit.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #ifdef GNU_LINUX #include #else #include #endif #ifndef ETHER_ADDR_LEN #define ETHER_ADDR_LEN ETHERADDRL #endif #include "log.h" #include "memory.h" #include "if.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "hash.h" #include "prefix.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_network.h" #include "isisd/isis_misc.h" #include "isisd/isis_constants.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_dr.h" #include "isisd/isisd.h" #include "isisd/isis_csm.h" #include "isisd/isis_events.h" /* * Prototypes. */ int isis_interface_config_write(struct vty *); int isis_if_new_hook(struct interface *); int isis_if_delete_hook(struct interface *); struct isis_circuit * isis_circuit_new () { struct isis_circuit *circuit; int i; circuit = XCALLOC (MTYPE_ISIS_CIRCUIT, sizeof (struct isis_circuit)); if (circuit == NULL) { zlog_err ("Can't malloc isis circuit"); return NULL; } /* * Default values */ circuit->is_type = IS_LEVEL_1_AND_2; circuit->flags = 0; circuit->pad_hellos = 1; for (i = 0; i < 2; i++) { circuit->hello_interval[i] = DEFAULT_HELLO_INTERVAL; circuit->hello_multiplier[i] = DEFAULT_HELLO_MULTIPLIER; circuit->csnp_interval[i] = DEFAULT_CSNP_INTERVAL; circuit->psnp_interval[i] = DEFAULT_PSNP_INTERVAL; circuit->priority[i] = DEFAULT_PRIORITY; circuit->metrics[i].metric_default = DEFAULT_CIRCUIT_METRIC; circuit->metrics[i].metric_expense = METRICS_UNSUPPORTED; circuit->metrics[i].metric_error = METRICS_UNSUPPORTED; circuit->metrics[i].metric_delay = METRICS_UNSUPPORTED; circuit->te_metric[i] = DEFAULT_CIRCUIT_METRIC; } return circuit; } void isis_circuit_del (struct isis_circuit *circuit) { if (!circuit) return; isis_circuit_if_unbind (circuit, circuit->interface); /* and lastly the circuit itself */ XFREE (MTYPE_ISIS_CIRCUIT, circuit); return; } void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area) { assert (area); circuit->area = area; /* * The level for the circuit is same as for the area, unless configured * otherwise. */ if (area->is_type != IS_LEVEL_1_AND_2 && area->is_type != circuit->is_type) zlog_warn ("circut %s is_type %d mismatch with area %s is_type %d", circuit->interface->name, circuit->is_type, circuit->area->area_tag, area->is_type); /* * Add the circuit into area */ listnode_add (area->circuit_list, circuit); circuit->idx = flags_get_index (&area->flags); return; } void isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area) { /* Free the index of SRM and SSN flags */ flags_free_index (&area->flags, circuit->idx); circuit->idx = 0; /* Remove circuit from area */ assert (circuit->area == area); listnode_delete (area->circuit_list, circuit); circuit->area = NULL; return; } struct isis_circuit * circuit_lookup_by_ifp (struct interface *ifp, struct list *list) { struct isis_circuit *circuit = NULL; struct listnode *node; if (!list) return NULL; for (ALL_LIST_ELEMENTS_RO (list, node, circuit)) if (circuit->interface == ifp) { assert (ifp->info == circuit); return circuit; } return NULL; } struct isis_circuit * circuit_scan_by_ifp (struct interface *ifp) { struct isis_area *area; struct listnode *node; struct isis_circuit *circuit; if (ifp->info) return (struct isis_circuit *)ifp->info; if (isis->area_list) { for (ALL_LIST_ELEMENTS_RO (isis->area_list, node, area)) { circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (circuit) return circuit; } } return circuit_lookup_by_ifp (ifp, isis->init_circ_list); } static struct isis_circuit * isis_circuit_lookup (struct vty *vty) { struct interface *ifp; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return NULL; } circuit = circuit_scan_by_ifp (ifp); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return NULL; } return circuit; } void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *connected) { struct listnode *node; struct prefix_ipv4 *ipv4; u_char buf[BUFSIZ]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6; #endif /* HAVE_IPV6 */ memset (&buf, 0, BUFSIZ); if (connected->address->family == AF_INET) { u_int32_t addr = connected->address->u.prefix4.s_addr; addr = ntohl (addr); if (IPV4_NET0(addr) || IPV4_NET127(addr) || IN_CLASSD(addr) || IPV4_LINKLOCAL(addr)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ipv4)) if (prefix_same ((struct prefix *) ipv4, connected->address)) return; ipv4 = prefix_ipv4_new (); ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; listnode_add (circuit->ip_addrs, ipv4); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); zlog_debug ("Added IP address %s to circuit %d", buf, circuit->circuit_id); #endif /* EXTREME_DEBUG */ } #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) { if (IN6_IS_ADDR_LOOPBACK(&connected->address->u.prefix6)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ipv6)) if (prefix_same ((struct prefix *) ipv6, connected->address)) return; for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ipv6)) if (prefix_same ((struct prefix *) ipv6, connected->address)) return; ipv6 = prefix_ipv6_new (); ipv6->prefixlen = connected->address->prefixlen; ipv6->prefix = connected->address->u.prefix6; if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix)) listnode_add (circuit->ipv6_link, ipv6); else listnode_add (circuit->ipv6_non_link, ipv6); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); #ifdef EXTREME_DEBUG prefix2str (connected->address, buf, BUFSIZ); zlog_debug ("Added IPv6 address %s to circuit %d", buf, circuit->circuit_id); #endif /* EXTREME_DEBUG */ } #endif /* HAVE_IPV6 */ return; } void isis_circuit_del_addr (struct isis_circuit *circuit, struct connected *connected) { struct prefix_ipv4 *ipv4, *ip = NULL; struct listnode *node; u_char buf[BUFSIZ]; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6, *ip6 = NULL; int found = 0; #endif /* HAVE_IPV6 */ memset (&buf, 0, BUFSIZ); if (connected->address->family == AF_INET) { ipv4 = prefix_ipv4_new (); ipv4->prefixlen = connected->address->prefixlen; ipv4->prefix = connected->address->u.prefix4; for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip)) if (prefix_same ((struct prefix *) ip, (struct prefix *) ipv4)) break; if (ip) { listnode_delete (circuit->ip_addrs, ip); if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); } else { prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); } prefix_ipv4_free (ipv4); } #ifdef HAVE_IPV6 if (connected->address->family == AF_INET6) { ipv6 = prefix_ipv6_new (); ipv6->prefixlen = connected->address->prefixlen; ipv6->prefix = connected->address->u.prefix6; if (IN6_IS_ADDR_LINKLOCAL (&ipv6->prefix)) { for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_link, node, ip6)) { if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6)) break; } if (ip6) { listnode_delete (circuit->ipv6_link, ip6); found = 1; } } else { for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, node, ip6)) { if (prefix_same ((struct prefix *) ip6, (struct prefix *) ipv6)) break; } if (ip6) { listnode_delete (circuit->ipv6_non_link, ip6); found = 1; } } if (!found) { prefix2str (connected->address, (char *)buf, BUFSIZ); zlog_warn ("Nonexitant ip address %s removal attempt from \ circuit %d", buf, circuit->circuit_id); } else if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); prefix_ipv6_free (ipv6); } #endif /* HAVE_IPV6 */ return; } static u_char isis_circuit_id_gen (struct interface *ifp) { u_char id = 0; char ifname[16]; unsigned int i; int start = -1, end = -1; /* * Get a stable circuit id from ifname. This makes * the ifindex from flapping when netdevs are created * and deleted on the fly. Note that this circuit id * is used in pseudo lsps so it is better to be stable. * The following code works on any reasonanle ifname * like: eth1 or trk-1.1 etc. */ for (i = 0; i < strlen (ifp->name); i++) { if (isdigit(ifp->name[i])) { if (start < 0) { start = i; end = i + 1; } else { end = i + 1; } } else if (start >= 0) break; } if ((start >= 0) && (end >= start) && (end - start) < 16) { memset (ifname, 0, 16); strncpy (ifname, &ifp->name[start], end - start); id = (u_char)atoi(ifname); } /* Try to be unique. */ if (!id) id = (u_char)((ifp->ifindex & 0xff) | 0x80); return id; } void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp) { struct listnode *node, *nnode; struct connected *conn; circuit->circuit_id = isis_circuit_id_gen (ifp); isis_circuit_if_bind (circuit, ifp); /* isis_circuit_update_addrs (circuit, ifp); */ if (if_is_broadcast (ifp)) { if (circuit->circ_type_config == CIRCUIT_T_P2P) circuit->circ_type = CIRCUIT_T_P2P; else circuit->circ_type = CIRCUIT_T_BROADCAST; } else if (if_is_pointopoint (ifp)) { circuit->circ_type = CIRCUIT_T_P2P; } else if (if_is_loopback (ifp)) { circuit->circ_type = CIRCUIT_T_LOOPBACK; circuit->is_passive = 1; } else { /* It's normal in case of loopback etc. */ if (isis->debugs & DEBUG_EVENTS) zlog_debug ("isis_circuit_if_add: unsupported media"); circuit->circ_type = CIRCUIT_T_UNKNOWN; } circuit->ip_addrs = list_new (); #ifdef HAVE_IPV6 circuit->ipv6_link = list_new (); circuit->ipv6_non_link = list_new (); #endif /* HAVE_IPV6 */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_add_addr (circuit, conn); return; } void isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp) { struct listnode *node, *nnode; struct connected *conn; assert (circuit->interface == ifp); /* destroy addresses */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, conn)) isis_circuit_del_addr (circuit, conn); if (circuit->ip_addrs) { assert (listcount(circuit->ip_addrs) == 0); list_delete (circuit->ip_addrs); circuit->ip_addrs = NULL; } #ifdef HAVE_IPV6 if (circuit->ipv6_link) { assert (listcount(circuit->ipv6_link) == 0); list_delete (circuit->ipv6_link); circuit->ipv6_link = NULL; } if (circuit->ipv6_non_link) { assert (listcount(circuit->ipv6_non_link) == 0); list_delete (circuit->ipv6_non_link); circuit->ipv6_non_link = NULL; } #endif /* HAVE_IPV6 */ circuit->circ_type = CIRCUIT_T_UNKNOWN; circuit->circuit_id = 0; return; } void isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp) { assert (circuit != NULL); assert (ifp != NULL); if (circuit->interface) assert (circuit->interface == ifp); else circuit->interface = ifp; if (ifp->info) assert (ifp->info == circuit); else ifp->info = circuit; } void isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp) { assert (circuit != NULL); assert (ifp != NULL); assert (circuit->interface == ifp); assert (ifp->info == circuit); circuit->interface = NULL; ifp->info = NULL; } static void isis_circuit_update_all_srmflags (struct isis_circuit *circuit, int is_set) { struct isis_area *area; struct isis_lsp *lsp; dnode_t *dnode, *dnode_next; int level; assert (circuit); area = circuit->area; assert (area); for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) { if (level & circuit->is_type) { if (area->lspdb[level - 1] && dict_count (area->lspdb[level - 1]) > 0) { for (dnode = dict_first (area->lspdb[level - 1]); dnode != NULL; dnode = dnode_next) { dnode_next = dict_next (area->lspdb[level - 1], dnode); lsp = dnode_get (dnode); if (is_set) { ISIS_SET_FLAG (lsp->SRMflags, circuit); } else { ISIS_CLEAR_FLAG (lsp->SRMflags, circuit); } } } } } } int isis_circuit_up (struct isis_circuit *circuit) { int retv; /* Set the flags for all the lsps of the circuit. */ isis_circuit_update_all_srmflags (circuit, 1); if (circuit->state == C_STATE_UP) return ISIS_OK; if (circuit->is_passive) return ISIS_OK; if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* * Get the Hardware Address */ #ifdef HAVE_STRUCT_SOCKADDR_DL #ifndef SUNOS_5 if (circuit->interface->sdl.sdl_alen != ETHER_ADDR_LEN) zlog_warn ("unsupported link layer"); else memcpy (circuit->u.bc.snpa, LLADDR (&circuit->interface->sdl), ETH_ALEN); #endif #else if (circuit->interface->hw_addr_len != ETH_ALEN) { zlog_warn ("unsupported link layer"); } else { memcpy (circuit->u.bc.snpa, circuit->interface->hw_addr, ETH_ALEN); } #ifdef EXTREME_DEGUG zlog_debug ("isis_circuit_if_add: if_id %d, isomtu %d snpa %s", circuit->interface->ifindex, ISO_MTU (circuit), snpa_print (circuit->u.bc.snpa)); #endif /* EXTREME_DEBUG */ #endif /* HAVE_STRUCT_SOCKADDR_DL */ circuit->u.bc.adjdb[0] = list_new (); circuit->u.bc.adjdb[1] = list_new (); if (circuit->area->min_bcast_mtu == 0 || ISO_MTU (circuit) < circuit->area->min_bcast_mtu) circuit->area->min_bcast_mtu = ISO_MTU (circuit); /* * ISO 10589 - 8.4.1 Enabling of broadcast circuits */ /* initilizing the hello sending threads * for a broadcast IF */ /* 8.4.1 a) commence sending of IIH PDUs */ if (circuit->is_type & IS_LEVEL_1) { thread_add_event (master, send_lan_l1_hello, circuit, 0); circuit->u.bc.lan_neighs[0] = list_new (); } if (circuit->is_type & IS_LEVEL_2) { thread_add_event (master, send_lan_l2_hello, circuit, 0); circuit->u.bc.lan_neighs[1] = list_new (); } /* 8.4.1 b) FIXME: solicit ES - 8.4.6 */ /* 8.4.1 c) FIXME: listen for ESH PDUs */ /* 8.4.1 d) */ /* dr election will commence in... */ if (circuit->is_type & IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[0], isis_run_dr_l1, circuit, 2 * circuit->hello_interval[0]); if (circuit->is_type & IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_run_dr[1], isis_run_dr_l2, circuit, 2 * circuit->hello_interval[1]); } else { /* initializing the hello send threads * for a ptp IF */ circuit->u.p2p.neighbor = NULL; thread_add_event (master, send_p2p_hello, circuit, 0); } /* initializing PSNP timers */ if (circuit->is_type & IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->t_send_psnp[0], send_l1_psnp, circuit, isis_jitter (circuit->psnp_interval[0], PSNP_JITTER)); if (circuit->is_type & IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->t_send_psnp[1], send_l2_psnp, circuit, isis_jitter (circuit->psnp_interval[1], PSNP_JITTER)); /* unified init for circuits; ignore warnings below this level */ retv = isis_sock_init (circuit); if (retv != ISIS_OK) { isis_circuit_down (circuit); return retv; } /* initialize the circuit streams after opening connection */ if (circuit->rcv_stream == NULL) circuit->rcv_stream = stream_new (ISO_MTU (circuit)); if (circuit->snd_stream == NULL) circuit->snd_stream = stream_new (ISO_MTU (circuit)); #ifdef GNU_LINUX THREAD_READ_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); #else THREAD_TIMER_ON (master, circuit->t_read, isis_receive, circuit, circuit->fd); #endif circuit->lsp_queue = list_new (); circuit->lsp_queue_last_cleared = time (NULL); return ISIS_OK; } void isis_circuit_down (struct isis_circuit *circuit) { if (circuit->state != C_STATE_UP) return; /* Clear the flags for all the lsps of the circuit. */ isis_circuit_update_all_srmflags (circuit, 0); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { /* destroy neighbour lists */ if (circuit->u.bc.lan_neighs[0]) { list_delete (circuit->u.bc.lan_neighs[0]); circuit->u.bc.lan_neighs[0] = NULL; } if (circuit->u.bc.lan_neighs[1]) { list_delete (circuit->u.bc.lan_neighs[1]); circuit->u.bc.lan_neighs[1] = NULL; } /* destroy adjacency databases */ if (circuit->u.bc.adjdb[0]) { circuit->u.bc.adjdb[0]->del = isis_delete_adj; list_delete (circuit->u.bc.adjdb[0]); circuit->u.bc.adjdb[0] = NULL; } if (circuit->u.bc.adjdb[1]) { circuit->u.bc.adjdb[1]->del = isis_delete_adj; list_delete (circuit->u.bc.adjdb[1]); circuit->u.bc.adjdb[1] = NULL; } if (circuit->u.bc.is_dr[0]) { isis_dr_resign (circuit, 1); circuit->u.bc.is_dr[0] = 0; } memset (circuit->u.bc.l1_desig_is, 0, ISIS_SYS_ID_LEN + 1); if (circuit->u.bc.is_dr[1]) { isis_dr_resign (circuit, 2); circuit->u.bc.is_dr[1] = 0; } memset (circuit->u.bc.l2_desig_is, 0, ISIS_SYS_ID_LEN + 1); memset (circuit->u.bc.snpa, 0, ETH_ALEN); THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[0]); THREAD_TIMER_OFF (circuit->u.bc.t_send_lan_hello[1]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[0]); THREAD_TIMER_OFF (circuit->u.bc.t_run_dr[1]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[0]); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[1]); } else if (circuit->circ_type == CIRCUIT_T_P2P) { isis_delete_adj (circuit->u.p2p.neighbor); circuit->u.p2p.neighbor = NULL; THREAD_TIMER_OFF (circuit->u.p2p.t_send_p2p_hello); } /* Cancel all active threads */ THREAD_TIMER_OFF (circuit->t_send_csnp[0]); THREAD_TIMER_OFF (circuit->t_send_csnp[1]); THREAD_TIMER_OFF (circuit->t_send_psnp[0]); THREAD_TIMER_OFF (circuit->t_send_psnp[1]); THREAD_OFF (circuit->t_read); if (circuit->lsp_queue) { circuit->lsp_queue->del = NULL; list_delete (circuit->lsp_queue); circuit->lsp_queue = NULL; } /* send one gratuitous hello to spead up convergence */ if (circuit->is_type & IS_LEVEL_1) send_hello (circuit, IS_LEVEL_1); if (circuit->is_type & IS_LEVEL_2) send_hello (circuit, IS_LEVEL_2); circuit->upadjcount[0] = 0; circuit->upadjcount[1] = 0; /* close the socket */ if (circuit->fd) { close (circuit->fd); circuit->fd = 0; } if (circuit->rcv_stream != NULL) { stream_free (circuit->rcv_stream); circuit->rcv_stream = NULL; } if (circuit->snd_stream != NULL) { stream_free (circuit->snd_stream); circuit->snd_stream = NULL; } thread_cancel_event (master, circuit); return; } void circuit_update_nlpids (struct isis_circuit *circuit) { circuit->nlpids.count = 0; if (circuit->ip_router) { circuit->nlpids.nlpids[0] = NLPID_IP; circuit->nlpids.count++; } #ifdef HAVE_IPV6 if (circuit->ipv6_router) { circuit->nlpids.nlpids[circuit->nlpids.count] = NLPID_IPV6; circuit->nlpids.count++; } #endif /* HAVE_IPV6 */ return; } void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, char detail) { if (detail == ISIS_UI_LEVEL_BRIEF) { vty_out (vty, " %-12s", circuit->interface->name); vty_out (vty, "0x%-7x", circuit->circuit_id); vty_out (vty, "%-9s", circuit_state2string (circuit->state)); vty_out (vty, "%-9s", circuit_type2string (circuit->circ_type)); vty_out (vty, "%-9s", circuit_t2string (circuit->is_type)); vty_out (vty, "%s", VTY_NEWLINE); } if (detail == ISIS_UI_LEVEL_DETAIL) { vty_out (vty, " Interface: %s", circuit->interface->name); vty_out (vty, ", State: %s", circuit_state2string (circuit->state)); if (circuit->is_passive) vty_out (vty, ", Passive"); else vty_out (vty, ", Active"); vty_out (vty, ", Circuit Id: 0x%x", circuit->circuit_id); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Type: %s", circuit_type2string (circuit->circ_type)); vty_out (vty, ", Level: %s", circuit_t2string (circuit->is_type)); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, ", SNPA: %-10s", snpa_print (circuit->u.bc.snpa)); vty_out (vty, "%s", VTY_NEWLINE); if (circuit->is_type & IS_LEVEL_1) { vty_out (vty, " Level-1 Information:%s", VTY_NEWLINE); if (circuit->area->newmetric) vty_out (vty, " Metric: %d", circuit->te_metric[0]); else vty_out (vty, " Metric: %d", circuit->metrics[0].metric_default); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", circuit->upadjcount[0], VTY_NEWLINE); vty_out (vty, " Hello interval: %u, " "Holddown count: %u %s%s", circuit->hello_interval[0], circuit->hello_multiplier[0], (circuit->pad_hellos ? "(pad)" : "(no-pad)"), VTY_NEWLINE); vty_out (vty, " CNSP interval: %u, " "PSNP interval: %u%s", circuit->csnp_interval[0], circuit->psnp_interval[0], VTY_NEWLINE); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, " LAN Priority: %u, %s%s", circuit->priority[0], (circuit->u.bc.is_dr[0] ? \ "is DIS" : "is not DIS"), VTY_NEWLINE); } else { vty_out (vty, "%s", VTY_NEWLINE); } } if (circuit->is_type & IS_LEVEL_2) { vty_out (vty, " Level-2 Information:%s", VTY_NEWLINE); if (circuit->area->newmetric) vty_out (vty, " Metric: %d", circuit->te_metric[1]); else vty_out (vty, " Metric: %d", circuit->metrics[1].metric_default); if (!circuit->is_passive) { vty_out (vty, ", Active neighbors: %u%s", circuit->upadjcount[1], VTY_NEWLINE); vty_out (vty, " Hello interval: %u, " "Holddown count: %u %s%s", circuit->hello_interval[1], circuit->hello_multiplier[1], (circuit->pad_hellos ? "(pad)" : "(no-pad)"), VTY_NEWLINE); vty_out (vty, " CNSP interval: %u, " "PSNP interval: %u%s", circuit->csnp_interval[1], circuit->psnp_interval[1], VTY_NEWLINE); if (circuit->circ_type == CIRCUIT_T_BROADCAST) vty_out (vty, " LAN Priority: %u, %s%s", circuit->priority[1], (circuit->u.bc.is_dr[1] ? \ "is DIS" : "is not DIS"), VTY_NEWLINE); } else { vty_out (vty, "%s", VTY_NEWLINE); } } if (circuit->ip_addrs && listcount (circuit->ip_addrs) > 0) { struct listnode *node; struct prefix *ip_addr; u_char buf[BUFSIZ]; vty_out (vty, " IP Prefix(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, node, ip_addr)) { prefix2str (ip_addr, (char*)buf, BUFSIZ), vty_out (vty, " %s%s", buf, VTY_NEWLINE); } } vty_out (vty, "%s", VTY_NEWLINE); } return; } int isis_interface_config_write (struct vty *vty) { int write = 0; struct listnode *node, *node2; struct interface *ifp; struct isis_area *area; struct isis_circuit *circuit; int i; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { /* IF name */ vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); write++; /* IF desc */ if (ifp->desc) { vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); write++; } /* ISIS Circuit */ for (ALL_LIST_ELEMENTS_RO (isis->area_list, node2, area)) { circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (circuit == NULL) continue; if (circuit->ip_router) { vty_out (vty, " ip router isis %s%s", area->area_tag, VTY_NEWLINE); write++; } if (circuit->is_passive) { vty_out (vty, " isis passive%s", VTY_NEWLINE); write++; } if (circuit->circ_type_config == CIRCUIT_T_P2P) { vty_out (vty, " isis network point-to-point%s", VTY_NEWLINE); write++; } #ifdef HAVE_IPV6 if (circuit->ipv6_router) { vty_out (vty, " ipv6 router isis %s%s", area->area_tag, VTY_NEWLINE); write++; } #endif /* HAVE_IPV6 */ /* ISIS - circuit type */ if (circuit->is_type == IS_LEVEL_1) { vty_out (vty, " isis circuit-type level-1%s", VTY_NEWLINE); write++; } else { if (circuit->is_type == IS_LEVEL_2) { vty_out (vty, " isis circuit-type level-2-only%s", VTY_NEWLINE); write++; } } /* ISIS - CSNP interval */ if (circuit->csnp_interval[0] == circuit->csnp_interval[1]) { if (circuit->csnp_interval[0] != DEFAULT_CSNP_INTERVAL) { vty_out (vty, " isis csnp-interval %d%s", circuit->csnp_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->csnp_interval[i] != DEFAULT_CSNP_INTERVAL) { vty_out (vty, " isis csnp-interval %d level-%d%s", circuit->csnp_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - PSNP interval */ if (circuit->psnp_interval[0] == circuit->psnp_interval[1]) { if (circuit->psnp_interval[0] != DEFAULT_PSNP_INTERVAL) { vty_out (vty, " isis psnp-interval %d%s", circuit->psnp_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->psnp_interval[i] != DEFAULT_PSNP_INTERVAL) { vty_out (vty, " isis psnp-interval %d level-%d%s", circuit->psnp_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Hello padding - Defaults to true so only display if false */ if (circuit->pad_hellos == 0) { vty_out (vty, " no isis hello padding%s", VTY_NEWLINE); write++; } /* ISIS - Hello interval */ if (circuit->hello_interval[0] == circuit->hello_interval[1]) { if (circuit->hello_interval[0] != DEFAULT_HELLO_INTERVAL) { vty_out (vty, " isis hello-interval %d%s", circuit->hello_interval[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->hello_interval[i] != DEFAULT_HELLO_INTERVAL) { vty_out (vty, " isis hello-interval %d level-%d%s", circuit->hello_interval[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Hello Multiplier */ if (circuit->hello_multiplier[0] == circuit->hello_multiplier[1]) { if (circuit->hello_multiplier[0] != DEFAULT_HELLO_MULTIPLIER) { vty_out (vty, " isis hello-multiplier %d%s", circuit->hello_multiplier[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->hello_multiplier[i] != DEFAULT_HELLO_MULTIPLIER) { vty_out (vty, " isis hello-multiplier %d level-%d%s", circuit->hello_multiplier[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Priority */ if (circuit->priority[0] == circuit->priority[1]) { if (circuit->priority[0] != DEFAULT_PRIORITY) { vty_out (vty, " isis priority %d%s", circuit->priority[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->priority[i] != DEFAULT_PRIORITY) { vty_out (vty, " isis priority %d level-%d%s", circuit->priority[i], i + 1, VTY_NEWLINE); write++; } } } /* ISIS - Metric */ if (circuit->te_metric[0] == circuit->te_metric[1]) { if (circuit->te_metric[0] != DEFAULT_CIRCUIT_METRIC) { vty_out (vty, " isis metric %d%s", circuit->te_metric[0], VTY_NEWLINE); write++; } } else { for (i = 0; i < 2; i++) { if (circuit->te_metric[i] != DEFAULT_CIRCUIT_METRIC) { vty_out (vty, " isis metric %d level-%d%s", circuit->te_metric[i], i + 1, VTY_NEWLINE); write++; } } } if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5) { vty_out (vty, " isis password md5 %s%s", circuit->passwd.passwd, VTY_NEWLINE); write++; } else if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT) { vty_out (vty, " isis password clear %s%s", circuit->passwd.passwd, VTY_NEWLINE); write++; } } vty_out (vty, "!%s", VTY_NEWLINE); } return write; } DEFUN (ip_router_isis, ip_router_isis_cmd, "ip router isis WORD", "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") { struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; ifp = (struct interface *) vty->index; assert (ifp); /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); if (circuit) { if (circuit->ip_router == 1) { if (strcmp (circuit->area->area_tag, argv[0])) { vty_out (vty, "ISIS circuit is already defined on %s%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } return CMD_SUCCESS; } } if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); isis_circuit_if_bind (circuit, ifp); circuit->ip_router = 1; area->ip_circuits++; circuit_update_nlpids (circuit); vty->node = INTERFACE_NODE; vty->index = ifp; return CMD_SUCCESS; } DEFUN (no_ip_router_isis, no_ip_router_isis_cmd, "no ip router isis WORD", NO_STR "Interface Internet Protocol config commands\n" "IP router interface commands\n" "IS-IS Routing for IP\n" "Routing process tag\n") { struct interface *ifp; struct isis_area *area; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = isis_area_lookup (argv[0]); if (!area) { vty_out (vty, "Can't find ISIS instance %s%s", argv[0], VTY_NEWLINE); return CMD_ERR_NO_MATCH; } circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } circuit->ip_router = 0; area->ip_circuits--; #ifdef HAVE_IPV6 if (circuit->ipv6_router == 0) #endif isis_csm_state_change (ISIS_DISABLE, circuit, area); return CMD_SUCCESS; } #ifdef HAVE_IPV6 DEFUN (ipv6_router_isis, ipv6_router_isis_cmd, "ipv6 router isis WORD", "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") { struct isis_circuit *circuit; struct interface *ifp; struct isis_area *area; ifp = (struct interface *) vty->index; assert (ifp); /* Prevent more than one area per circuit */ circuit = circuit_scan_by_ifp (ifp); if (circuit) { if (circuit->ipv6_router == 1) { if (strcmp (circuit->area->area_tag, argv[0])) { vty_out (vty, "ISIS circuit is already defined for IPv6 on %s%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_NOTHING_TODO; } return CMD_SUCCESS; } } if (isis_area_get (vty, argv[0]) != CMD_SUCCESS) { vty_out (vty, "Can't find ISIS instance %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = vty->index; circuit = isis_csm_state_change (ISIS_ENABLE, circuit, area); isis_circuit_if_bind (circuit, ifp); circuit->ipv6_router = 1; area->ipv6_circuits++; circuit_update_nlpids (circuit); vty->node = INTERFACE_NODE; vty->index = ifp; return CMD_SUCCESS; } DEFUN (no_ipv6_router_isis, no_ipv6_router_isis_cmd, "no ipv6 router isis WORD", NO_STR "IPv6 interface subcommands\n" "IPv6 Router interface commands\n" "IS-IS Routing for IPv6\n" "Routing process tag\n") { struct interface *ifp; struct isis_area *area; struct listnode *node; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } area = isis_area_lookup (argv[0]); if (!area) { vty_out (vty, "Can't find ISIS instance %s%s", argv[0], VTY_NEWLINE); return CMD_ERR_NO_MATCH; } circuit = circuit_lookup_by_ifp (ifp, area->circuit_list); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } circuit->ipv6_router = 0; area->ipv6_circuits--; if (circuit->ip_router == 0) isis_csm_state_change (ISIS_DISABLE, circuit, area); return CMD_SUCCESS; } #endif /* HAVE_IPV6 */ DEFUN (isis_passive, isis_passive_cmd, "isis passive", "IS-IS commands\n" "Configure the passive mode for interface\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; if (circuit->is_passive == 1) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->is_passive = 1; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->is_passive = 1; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } DEFUN (no_isis_passive, no_isis_passive_cmd, "no isis passive", NO_STR "IS-IS commands\n" "Configure the passive mode for interface\n") { struct interface *ifp; struct isis_circuit *circuit; ifp = (struct interface *) vty->index; if (!ifp) { vty_out (vty, "Invalid interface %s", VTY_NEWLINE); return CMD_ERR_NO_MATCH; } /* FIXME: what is wrong with circuit = ifp->info ? */ circuit = circuit_scan_by_ifp (ifp); if (!circuit) { vty_out (vty, "ISIS is not enabled on circuit %s%s", ifp->name, VTY_NEWLINE); return CMD_ERR_NO_MATCH; } if (if_is_loopback(ifp)) { vty_out (vty, "Can't set no passive for loopback interface%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (circuit->is_passive == 0) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->is_passive = 0; } else { struct isis_area *area = circuit->area; isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->is_passive = 0; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } DEFUN (isis_circuit_type, isis_circuit_type_cmd, "isis circuit-type (level-1|level-1-2|level-2-only)", "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { int circuit_type; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit_type = string2circuit_t (argv[0]); if (!circuit_type) { vty_out (vty, "Unknown circuit-type %s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } if (circuit->state == C_STATE_UP && circuit->area->is_type != IS_LEVEL_1_AND_2 && circuit->area->is_type != circuit_type) { vty_out (vty, "Invalid circuit level for area %s.%s", circuit->area->area_tag, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_event_circuit_type_change (circuit, circuit_type); return CMD_SUCCESS; } DEFUN (no_isis_circuit_type, no_isis_circuit_type_cmd, "no isis circuit-type (level-1|level-1-2|level-2-only)", NO_STR "IS-IS commands\n" "Configure circuit type for interface\n" "Level-1 only adjacencies are formed\n" "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { int circuit_type; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; /* * Set the circuits level to its default value */ if (circuit->state == C_STATE_UP) circuit_type = circuit->area->is_type; else circuit_type = IS_LEVEL_1_AND_2; isis_event_circuit_type_change (circuit, circuit_type); return CMD_SUCCESS; } DEFUN (isis_passwd_md5, isis_passwd_md5_cmd, "isis password md5 WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") { int len; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5; strncpy ((char *)circuit->passwd.passwd, argv[0], 255); return CMD_SUCCESS; } DEFUN (isis_passwd_clear, isis_passwd_clear_cmd, "isis password clear WORD", "IS-IS commands\n" "Configure the authentication password for a circuit\n" "Authentication type\n" "Circuit password\n") { int len; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; len = strlen (argv[0]); if (len > 254) { vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->passwd.len = len; circuit->passwd.type = ISIS_PASSWD_TYPE_CLEARTXT; strncpy ((char *)circuit->passwd.passwd, argv[0], 255); return CMD_SUCCESS; } DEFUN (no_isis_passwd, no_isis_passwd_cmd, "no isis password", NO_STR "IS-IS commands\n" "Configure the authentication password for a circuit\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; memset (&circuit->passwd, 0, sizeof (struct isis_passwd)); return CMD_SUCCESS; } DEFUN (isis_priority, isis_priority_cmd, "isis priority <0-127>", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[0] = prio; circuit->priority[1] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority, no_isis_priority_cmd, "no isis priority", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[0] = DEFAULT_PRIORITY; circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority, no_isis_priority_arg_cmd, "no isis priority <0-127>", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n") DEFUN (isis_priority_l1, isis_priority_l1_cmd, "isis priority <0-127> level-1", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[0] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority_l1, no_isis_priority_l1_cmd, "no isis priority level-1", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-1 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[0] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority_l1, no_isis_priority_l1_arg_cmd, "no isis priority <0-127> level-1", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-1 routing\n") DEFUN (isis_priority_l2, isis_priority_l2_cmd, "isis priority <0-127> level-2", "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") { int prio; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; prio = atoi (argv[0]); if (prio < MIN_PRIORITY || prio > MAX_PRIORITY) { vty_out (vty, "Invalid priority %d - should be <0-127>%s", prio, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->priority[1] = prio; return CMD_SUCCESS; } DEFUN (no_isis_priority_l2, no_isis_priority_l2_cmd, "no isis priority level-2", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Specify priority for level-2 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->priority[1] = DEFAULT_PRIORITY; return CMD_SUCCESS; } ALIAS (no_isis_priority_l2, no_isis_priority_l2_arg_cmd, "no isis priority <0-127> level-2", NO_STR "IS-IS commands\n" "Set priority for Designated Router election\n" "Priority value\n" "Specify priority for level-2 routing\n") /* Metric command */ DEFUN (isis_metric, isis_metric_cmd, "isis metric <0-16777215>", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->te_metric[0] = met; circuit->te_metric[1] = met; circuit->metrics[0].metric_default = met; circuit->metrics[1].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); return CMD_SUCCESS; } DEFUN (no_isis_metric, no_isis_metric_cmd, "no isis metric", NO_STR "IS-IS commands\n" "Set default metric for circuit\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, circuit->is_type, 0); return CMD_SUCCESS; } ALIAS (no_isis_metric, no_isis_metric_arg_cmd, "no isis metric <0-16777215>", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n") DEFUN (isis_metric_l1, isis_metric_l1_cmd, "isis metric <0-16777215> level-1", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->te_metric[0] = met; circuit->metrics[0].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); return CMD_SUCCESS; } DEFUN (no_isis_metric_l1, no_isis_metric_l1_cmd, "no isis metric level-1", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-1 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->te_metric[0] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[0].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_1, 0); return CMD_SUCCESS; } ALIAS (no_isis_metric_l1, no_isis_metric_l1_arg_cmd, "no isis metric <0-16777215> level-1", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-1 routing\n") DEFUN (isis_metric_l2, isis_metric_l2_cmd, "isis metric <0-16777215> level-2", "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") { int met; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; met = atoi (argv[0]); /* RFC3787 section 5.1 */ if (circuit->area && circuit->area->oldmetric == 1 && met > MAX_NARROW_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-63> " "when narrow metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } /* RFC4444 */ if (circuit->area && circuit->area->newmetric == 1 && met > MAX_WIDE_LINK_METRIC) { vty_out (vty, "Invalid metric %d - should be <0-16777215> " "when wide metric type enabled%s", met, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->te_metric[1] = met; circuit->metrics[1].metric_default = met; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); return CMD_SUCCESS; } DEFUN (no_isis_metric_l2, no_isis_metric_l2_cmd, "no isis metric level-2", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Specify metric for level-2 routing\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->te_metric[1] = DEFAULT_CIRCUIT_METRIC; circuit->metrics[1].metric_default = DEFAULT_CIRCUIT_METRIC; if (circuit->area) lsp_regenerate_schedule (circuit->area, IS_LEVEL_2, 0); return CMD_SUCCESS; } ALIAS (no_isis_metric_l2, no_isis_metric_l2_arg_cmd, "no isis metric <0-16777215> level-2", NO_STR "IS-IS commands\n" "Set default metric for circuit\n" "Default metric value\n" "Specify metric for level-2 routing\n") /* end of metrics */ DEFUN (isis_hello_interval, isis_hello_interval_cmd, "isis hello-interval <1-600>", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 seconds, interval depends on multiplier\n") { int interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %d - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[0] = (u_int16_t) interval; circuit->hello_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval, no_isis_hello_interval_cmd, "no isis hello-interval", NO_STR "IS-IS commands\n" "Set Hello interval\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval, no_isis_hello_interval_arg_cmd, "no isis hello-interval <1-600>", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n") DEFUN (isis_hello_interval_l1, isis_hello_interval_l1_cmd, "isis hello-interval <1-600> level-1", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") { long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval_l1, no_isis_hello_interval_l1_cmd, "no isis hello-interval level-1", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-1 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[0] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l1, no_isis_hello_interval_l1_arg_cmd, "no isis hello-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-1 IIHs\n") DEFUN (isis_hello_interval_l2, isis_hello_interval_l2_cmd, "isis hello-interval <1-600> level-2", "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") { long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atoi (argv[0]); if (interval < MIN_HELLO_INTERVAL || interval > MAX_HELLO_INTERVAL) { vty_out (vty, "Invalid hello-interval %ld - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_isis_hello_interval_l2, no_isis_hello_interval_l2_cmd, "no isis hello-interval level-2", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Specify hello-interval for level-2 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_interval[1] = DEFAULT_HELLO_INTERVAL; return CMD_SUCCESS; } ALIAS (no_isis_hello_interval_l2, no_isis_hello_interval_l2_arg_cmd, "no isis hello-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set Hello interval\n" "Hello interval value\n" "Holdtime 1 second, interval depends on multiplier\n" "Specify hello-interval for level-2 IIHs\n") DEFUN (isis_hello_multiplier, isis_hello_multiplier_cmd, "isis hello-multiplier <2-100>", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[0] = (u_int16_t) mult; circuit->hello_multiplier[1] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier, no_isis_hello_multiplier_cmd, "no isis hello-multiplier", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier, no_isis_hello_multiplier_arg_cmd, "no isis hello-multiplier <2-100>", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n") DEFUN (isis_hello_multiplier_l1, isis_hello_multiplier_l1_cmd, "isis hello-multiplier <2-100> level-1", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[0] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier_l1, no_isis_hello_multiplier_l1_cmd, "no isis hello-multiplier level-1", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-1 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[0] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l1, no_isis_hello_multiplier_l1_arg_cmd, "no isis hello-multiplier <2-100> level-1", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-1 IIHs\n") DEFUN (isis_hello_multiplier_l2, isis_hello_multiplier_l2_cmd, "isis hello-multiplier <2-100> level-2", "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") { int mult; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; mult = atoi (argv[0]); if (mult < MIN_HELLO_MULTIPLIER || mult > MAX_HELLO_MULTIPLIER) { vty_out (vty, "Invalid hello-multiplier %d - should be <2-100>%s", mult, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->hello_multiplier[1] = (u_int16_t) mult; return CMD_SUCCESS; } DEFUN (no_isis_hello_multiplier_l2, no_isis_hello_multiplier_l2_cmd, "no isis hello-multiplier level-2", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Specify hello multiplier for level-2 IIHs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->hello_multiplier[1] = DEFAULT_HELLO_MULTIPLIER; return CMD_SUCCESS; } ALIAS (no_isis_hello_multiplier_l2, no_isis_hello_multiplier_l2_arg_cmd, "no isis hello-multiplier <2-100> level-2", NO_STR "IS-IS commands\n" "Set multiplier for Hello holding time\n" "Hello multiplier value\n" "Specify hello multiplier for level-2 IIHs\n") DEFUN (isis_hello_padding, isis_hello_padding_cmd, "isis hello padding", "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->pad_hellos = 1; return CMD_SUCCESS; } DEFUN (no_isis_hello_padding, no_isis_hello_padding_cmd, "no isis hello padding", NO_STR "IS-IS commands\n" "Add padding to IS-IS hello packets\n" "Pad hello packets\n" "\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->pad_hellos = 0; return CMD_SUCCESS; } DEFUN (csnp_interval, csnp_interval_cmd, "isis csnp-interval <1-600>", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[0] = (u_int16_t) interval; circuit->csnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval, no_csnp_interval_cmd, "no isis csnp-interval", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval, no_csnp_interval_arg_cmd, "no isis csnp-interval <1-600>", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n") DEFUN (csnp_interval_l1, csnp_interval_l1_cmd, "isis csnp-interval <1-600> level-1", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval_l1, no_csnp_interval_l1_cmd, "no isis csnp-interval level-1", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-1 CSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[0] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l1, no_csnp_interval_l1_arg_cmd, "no isis csnp-interval <1-600> level-1", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-1 CSNPs\n") DEFUN (csnp_interval_l2, csnp_interval_l2_cmd, "isis csnp-interval <1-600> level-2", "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_CSNP_INTERVAL || interval > MAX_CSNP_INTERVAL) { vty_out (vty, "Invalid csnp-interval %lu - should be <1-600>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->csnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_csnp_interval_l2, no_csnp_interval_l2_cmd, "no isis csnp-interval level-2", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "Specify interval for level-2 CSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->csnp_interval[1] = DEFAULT_CSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_csnp_interval_l2, no_csnp_interval_l2_arg_cmd, "no isis csnp-interval <1-600> level-2", NO_STR "IS-IS commands\n" "Set CSNP interval in seconds\n" "CSNP interval value\n" "Specify interval for level-2 CSNPs\n") DEFUN (psnp_interval, psnp_interval_cmd, "isis psnp-interval <1-120>", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[0] = (u_int16_t) interval; circuit->psnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval, no_psnp_interval_cmd, "no isis psnp-interval", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval, no_psnp_interval_arg_cmd, "no isis psnp-interval <1-120>", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n") DEFUN (psnp_interval_l1, psnp_interval_l1_cmd, "isis psnp-interval <1-120> level-1", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[0] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval_l1, no_psnp_interval_l1_cmd, "no isis psnp-interval level-1", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-1 PSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[0] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval_l1, no_psnp_interval_l1_arg_cmd, "no isis psnp-interval <1-120> level-1", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-1 PSNPs\n") DEFUN (psnp_interval_l2, psnp_interval_l2_cmd, "isis psnp-interval <1-120> level-2", "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") { unsigned long interval; struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; interval = atol (argv[0]); if (interval < MIN_PSNP_INTERVAL || interval > MAX_PSNP_INTERVAL) { vty_out (vty, "Invalid psnp-interval %lu - should be <1-120>%s", interval, VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } circuit->psnp_interval[1] = (u_int16_t) interval; return CMD_SUCCESS; } DEFUN (no_psnp_interval_l2, no_psnp_interval_l2_cmd, "no isis psnp-interval level-2", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "Specify interval for level-2 PSNPs\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; circuit->psnp_interval[1] = DEFAULT_PSNP_INTERVAL; return CMD_SUCCESS; } ALIAS (no_psnp_interval_l2, no_psnp_interval_l2_arg_cmd, "no isis psnp-interval <1-120> level-2", NO_STR "IS-IS commands\n" "Set PSNP interval in seconds\n" "PSNP interval value\n" "Specify interval for level-2 PSNPs\n") struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; DEFUN (isis_network, isis_network_cmd, "isis network point-to-point", "IS-IS commands\n" "Set network type\n" "point-to-point network type\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; /* RFC5309 section 4 */ if (circuit->circ_type == CIRCUIT_T_P2P) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->circ_type = CIRCUIT_T_P2P; circuit->circ_type_config = CIRCUIT_T_P2P; } else { struct isis_area *area = circuit->area; if (!if_is_broadcast (circuit->interface)) { vty_out (vty, "isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->circ_type = CIRCUIT_T_P2P; circuit->circ_type_config = CIRCUIT_T_P2P; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } DEFUN (no_isis_network, no_isis_network_cmd, "no isis network point-to-point", NO_STR "IS-IS commands\n" "Set network type for circuit\n" "point-to-point network type\n") { struct isis_circuit *circuit = isis_circuit_lookup (vty); if (!circuit) return CMD_ERR_NO_MATCH; /* RFC5309 section 4 */ if (circuit->circ_type == CIRCUIT_T_BROADCAST) return CMD_SUCCESS; if (circuit->state != C_STATE_UP) { circuit->circ_type = CIRCUIT_T_BROADCAST; circuit->circ_type_config = CIRCUIT_T_BROADCAST; } else { struct isis_area *area = circuit->area; if (circuit->interface && !if_is_broadcast (circuit->interface)) { vty_out (vty, "no isis network point-to-point " "is valid only on broadcast interfaces%s", VTY_NEWLINE); return CMD_ERR_AMBIGUOUS; } isis_csm_state_change (ISIS_DISABLE, circuit, area); circuit->circ_type = CIRCUIT_T_BROADCAST; circuit->circ_type_config = CIRCUIT_T_BROADCAST; isis_csm_state_change (ISIS_ENABLE, circuit, area); } return CMD_SUCCESS; } int isis_if_new_hook (struct interface *ifp) { return 0; } int isis_if_delete_hook (struct interface *ifp) { struct isis_circuit *circuit; /* Clean up the circuit data */ if (ifp && ifp->info) { circuit = ifp->info; isis_csm_state_change (IF_DOWN_FROM_Z, circuit, circuit->area); isis_csm_state_change (ISIS_DISABLE, circuit, circuit->area); } return 0; } void isis_circuit_init () { /* Initialize Zebra interface data structure */ if_init (); if_add_hook (IF_NEW_HOOK, isis_if_new_hook); if_add_hook (IF_DELETE_HOOK, isis_if_delete_hook); /* Install interface node */ install_node (&interface_node, isis_interface_config_write); install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &ip_router_isis_cmd); install_element (INTERFACE_NODE, &no_ip_router_isis_cmd); install_element (INTERFACE_NODE, &isis_passive_cmd); install_element (INTERFACE_NODE, &no_isis_passive_cmd); install_element (INTERFACE_NODE, &isis_circuit_type_cmd); install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd); install_element (INTERFACE_NODE, &isis_passwd_clear_cmd); install_element (INTERFACE_NODE, &isis_passwd_md5_cmd); install_element (INTERFACE_NODE, &no_isis_passwd_cmd); install_element (INTERFACE_NODE, &isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_cmd); install_element (INTERFACE_NODE, &no_isis_priority_arg_cmd); install_element (INTERFACE_NODE, &isis_priority_l1_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l1_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_priority_l2_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l2_cmd); install_element (INTERFACE_NODE, &no_isis_priority_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_cmd); install_element (INTERFACE_NODE, &no_isis_metric_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_l1_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l1_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_cmd); install_element (INTERFACE_NODE, &no_isis_metric_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_interval_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_interval_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l1_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_multiplier_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_cmd); install_element (INTERFACE_NODE, &no_isis_hello_multiplier_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_hello_padding_cmd); install_element (INTERFACE_NODE, &no_isis_hello_padding_cmd); install_element (INTERFACE_NODE, &csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_arg_cmd); install_element (INTERFACE_NODE, &csnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &csnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_csnp_interval_l2_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l1_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l1_arg_cmd); install_element (INTERFACE_NODE, &psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_cmd); install_element (INTERFACE_NODE, &no_psnp_interval_l2_arg_cmd); install_element (INTERFACE_NODE, &isis_network_cmd); install_element (INTERFACE_NODE, &no_isis_network_cmd); #ifdef HAVE_IPV6 install_element (INTERFACE_NODE, &ipv6_router_isis_cmd); install_element (INTERFACE_NODE, &no_ipv6_router_isis_cmd); #endif } quagga-0.99.24.1/isisd/dict.c0000644000175000017500000010473212476520570012445 00000000000000/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. */ #include "zebra.h" #include "zassert.h" #include "memory.h" #include "dict.h" /* * These macros provide short convenient names for structure members, * which are embellished with dict_ prefixes so that they are * properly confined to the documented namespace. It's legal for a * program which uses dict to define, for instance, a macro called ``parent''. * Such a macro would interfere with the dnode_t struct definition. * In general, highly portable and reusable C modules which expose their * structures need to confine structure member names to well-defined spaces. * The resulting identifiers aren't necessarily convenient to use, nor * readable, in the implementation, however! */ #define left dict_left #define right dict_right #define parent dict_parent #define color dict_color #define key dict_key #define data dict_data #define nilnode dict_nilnode #define nodecount dict_nodecount #define maxcount dict_maxcount #define compare dict_compare #define allocnode dict_allocnode #define freenode dict_freenode #define context dict_context #define dupes dict_dupes #define dictptr dict_dictptr #define dict_root(D) ((D)->nilnode.left) #define dict_nil(D) (&(D)->nilnode) #define DICT_DEPTH_MAX 64 static dnode_t *dnode_alloc(void *context); static void dnode_free(dnode_t *node, void *context); /* * Perform a ``left rotation'' adjustment on the tree. The given node P and * its right child C are rearranged so that the P instead becomes the left * child of C. The left subtree of C is inherited as the new right subtree * for P. The ordering of the keys within the tree is thus preserved. */ static void rotate_left(dnode_t *upper) { dnode_t *lower, *lowleft, *upparent; lower = upper->right; upper->right = lowleft = lower->left; lowleft->parent = upper; lower->parent = upparent = upper->parent; /* don't need to check for root node here because root->parent is the sentinel nil node, and root->parent->left points back to root */ if (upper == upparent->left) { upparent->left = lower; } else { assert (upper == upparent->right); upparent->right = lower; } lower->left = upper; upper->parent = lower; } /* * This operation is the ``mirror'' image of rotate_left. It is * the same procedure, but with left and right interchanged. */ static void rotate_right(dnode_t *upper) { dnode_t *lower, *lowright, *upparent; lower = upper->left; upper->left = lowright = lower->right; lowright->parent = upper; lower->parent = upparent = upper->parent; if (upper == upparent->right) { upparent->right = lower; } else { assert (upper == upparent->left); upparent->left = lower; } lower->right = upper; upper->parent = lower; } /* * Do a postorder traversal of the tree rooted at the specified * node and free everything under it. Used by dict_free(). */ static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) { if (node == nil) return; free_nodes(dict, node->left, nil); free_nodes(dict, node->right, nil); dict->freenode(node, dict->context); } /* * This procedure performs a verification that the given subtree is a binary * search tree. It performs an inorder traversal of the tree using the * dict_next() successor function, verifying that the key of each node is * strictly lower than that of its successor, if duplicates are not allowed, * or lower or equal if duplicates are allowed. This function is used for * debugging purposes. */ static int verify_bintree(dict_t *dict) { dnode_t *first, *next; first = dict_first(dict); if (dict->dupes) { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key) > 0) return 0; first = next; } } else { while (first && (next = dict_next(dict, first))) { if (dict->compare(first->key, next->key) >= 0) return 0; first = next; } } return 1; } /* * This function recursively verifies that the given binary subtree satisfies * three of the red black properties. It checks that every red node has only * black children. It makes sure that each node is either red or black. And it * checks that every path has the same count of black nodes from root to leaf. * It returns the blackheight of the given subtree; this allows blackheights to * be computed recursively and compared for left and right siblings for * mismatches. It does not check for every nil node being black, because there * is only one sentinel nil node. The return value of this function is the * black height of the subtree rooted at the node ``root'', or zero if the * subtree is not red-black. */ static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) { unsigned height_left, height_right; if (root != nil) { height_left = verify_redblack(nil, root->left); height_right = verify_redblack(nil, root->right); if (height_left == 0 || height_right == 0) return 0; if (height_left != height_right) return 0; if (root->color == dnode_red) { if (root->left->color != dnode_black) return 0; if (root->right->color != dnode_black) return 0; return height_left; } if (root->color != dnode_black) return 0; return height_left + 1; } return 1; } /* * Compute the actual count of nodes by traversing the tree and * return it. This could be compared against the stored count to * detect a mismatch. */ static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) { if (root == nil) return 0; else return 1 + verify_node_count(nil, root->left) + verify_node_count(nil, root->right); } /* * Verify that the tree contains the given node. This is done by * traversing all of the nodes and comparing their pointers to the * given pointer. Returns 1 if the node is found, otherwise * returns zero. It is intended for debugging purposes. */ static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) { if (root != nil) { return root == node || verify_dict_has_node(nil, root->left, node) || verify_dict_has_node(nil, root->right, node); } return 0; } /* * Dynamically allocate and initialize a dictionary object. */ dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) { dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t)); if (new) { new->compare = comp; new->allocnode = dnode_alloc; new->freenode = dnode_free; new->context = NULL; new->nodecount = 0; new->maxcount = maxcount; new->nilnode.left = &new->nilnode; new->nilnode.right = &new->nilnode; new->nilnode.parent = &new->nilnode; new->nilnode.color = dnode_black; new->dupes = 0; } return new; } /* * Select a different set of node allocator routines. */ void dict_set_allocator(dict_t *dict, dnode_alloc_t al, dnode_free_t fr, void *context) { assert (dict_count(dict) == 0); assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); dict->allocnode = al ? al : dnode_alloc; dict->freenode = fr ? fr : dnode_free; dict->context = context; } /* * Free a dynamically allocated dictionary object. Removing the nodes * from the tree before deleting it is required. */ void dict_destroy(dict_t *dict) { assert (dict_isempty(dict)); XFREE(MTYPE_ISIS_DICT, dict); } /* * Free all the nodes in the dictionary by using the dictionary's * installed free routine. The dictionary is emptied. */ void dict_free_nodes(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); free_nodes(dict, root, nil); dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; } /* * Obsolescent function, equivalent to dict_free_nodes */ void dict_free(dict_t *dict) { dict_free_nodes(dict); } /* * Initialize a user-supplied dictionary object. */ dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) { dict->compare = comp; dict->allocnode = dnode_alloc; dict->freenode = dnode_free; dict->context = NULL; dict->nodecount = 0; dict->maxcount = maxcount; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = 0; return dict; } /* * Initialize a dictionary in the likeness of another dictionary */ void dict_init_like(dict_t *dict, const dict_t *template) { dict->compare = template->compare; dict->allocnode = template->allocnode; dict->freenode = template->freenode; dict->context = template->context; dict->nodecount = 0; dict->maxcount = template->maxcount; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; dict->nilnode.color = dnode_black; dict->dupes = template->dupes; assert (dict_similar(dict, template)); } /* * Remove all nodes from the dictionary (without freeing them in any way). */ static void dict_clear(dict_t *dict) { dict->nodecount = 0; dict->nilnode.left = &dict->nilnode; dict->nilnode.right = &dict->nilnode; dict->nilnode.parent = &dict->nilnode; assert (dict->nilnode.color == dnode_black); } /* * Verify the integrity of the dictionary structure. This is provided for * debugging purposes, and should be placed in assert statements. Just because * this function succeeds doesn't mean that the tree is not corrupt. Certain * corruptions in the tree may simply cause undefined behavior. */ int dict_verify(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict); /* check that the sentinel node and root node are black */ if (root->color != dnode_black) return 0; if (nil->color != dnode_black) return 0; if (nil->right != nil) return 0; /* nil->left is the root node; check that its parent pointer is nil */ if (nil->left->parent != nil) return 0; /* perform a weak test that the tree is a binary search tree */ if (!verify_bintree(dict)) return 0; /* verify that the tree is a red-black tree */ if (!verify_redblack(nil, root)) return 0; if (verify_node_count(nil, root) != dict_count(dict)) return 0; return 1; } /* * Determine whether two dictionaries are similar: have the same comparison and * allocator functions, and same status as to whether duplicates are allowed. */ int dict_similar(const dict_t *left, const dict_t *right) { if (left->compare != right->compare) return 0; if (left->allocnode != right->allocnode) return 0; if (left->freenode != right->freenode) return 0; if (left->context != right->context) return 0; if (left->dupes != right->dupes) return 0; return 1; } /* * Locate a node in the dictionary having the given key. * If the node is not found, a null a pointer is returned (rather than * a pointer that dictionary's nil sentinel node), otherwise a pointer to the * located node is returned. */ dnode_t *dict_lookup(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *saved; int result; /* simple binary search adapted for trees that contain duplicate keys */ while (root != nil) { result = dict->compare(key, root->key); if (result < 0) root = root->left; else if (result > 0) root = root->right; else { if (!dict->dupes) { /* no duplicates, return match */ return root; } else { /* could be dupes, find leftmost one */ do { saved = root; root = root->left; while (root != nil && dict->compare(key, root->key)) root = root->right; } while (root != nil); return saved; } } } return NULL; } /* * Look for the node corresponding to the lowest key that is equal to or * greater than the given key. If there is no such node, return null. */ dnode_t *dict_lower_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key); if (result > 0) { root = root->right; } else if (result < 0) { tentative = root; root = root->left; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->left; } } } return tentative; } /* * Look for the node corresponding to the greatest key that is equal to or * lower than the given key. If there is no such node, return null. */ dnode_t *dict_upper_bound(dict_t *dict, const void *key) { dnode_t *root = dict_root(dict); dnode_t *nil = dict_nil(dict); dnode_t *tentative = 0; while (root != nil) { int result = dict->compare(key, root->key); if (result < 0) { root = root->left; } else if (result > 0) { tentative = root; root = root->right; } else { if (!dict->dupes) { return root; } else { tentative = root; root = root->right; } } } return tentative; } /* * Insert a node into the dictionary. The node should have been * initialized with a data field. All other fields are ignored. * The behavior is undefined if the user attempts to insert into * a dictionary that is already full (for which the dict_isfull() * function returns true). */ void dict_insert(dict_t *dict, dnode_t *node, const void *key) { dnode_t *where = dict_root(dict), *nil = dict_nil(dict); dnode_t *parent = nil, *uncle, *grandpa; int result = -1; node->key = key; assert (!dict_isfull(dict)); assert (!dict_contains(dict, node)); assert (!dnode_is_in_a_dict(node)); /* basic binary tree insert */ while (where != nil) { parent = where; result = dict->compare(key, where->key); /* trap attempts at duplicate key insertion unless it's explicitly allowed */ assert (dict->dupes || result != 0); if (result < 0) where = where->left; else where = where->right; } assert (where == nil); if (result < 0) parent->left = node; else parent->right = node; node->parent = parent; node->left = nil; node->right = nil; dict->nodecount++; /* red black adjustments */ node->color = dnode_red; while (parent->color == dnode_red) { grandpa = parent->parent; if (parent == grandpa->left) { uncle = grandpa->right; if (uncle->color == dnode_red) { /* red parent, red uncle */ parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { /* red parent, black uncle */ if (node == parent->right) { rotate_left(parent); parent = node; assert (grandpa == parent->parent); /* rotation between parent and child preserves grandpa */ } parent->color = dnode_black; grandpa->color = dnode_red; rotate_right(grandpa); break; } } else { /* symmetric cases: parent == parent->parent->right */ uncle = grandpa->left; if (uncle->color == dnode_red) { parent->color = dnode_black; uncle->color = dnode_black; grandpa->color = dnode_red; node = grandpa; parent = grandpa->parent; } else { if (node == parent->left) { rotate_right(parent); parent = node; assert (grandpa == parent->parent); } parent->color = dnode_black; grandpa->color = dnode_red; rotate_left(grandpa); break; } } } dict_root(dict)->color = dnode_black; assert (dict_verify(dict)); } /* * Delete the given node from the dictionary. If the given node does not belong * to the given dictionary, undefined behavior results. A pointer to the * deleted node is returned. */ dnode_t *dict_delete(dict_t *dict, dnode_t *delete) { dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; /* basic deletion */ assert (!dict_isempty(dict)); assert (dict_contains(dict, delete)); /* * If the node being deleted has two children, then we replace it with its * successor (i.e. the leftmost node in the right subtree.) By doing this, * we avoid the traditional algorithm under which the successor's key and * value *only* move to the deleted node and the successor is spliced out * from the tree. We cannot use this approach because the user may hold * pointers to the successor, or nodes may be inextricably tied to some * other structures by way of embedding, etc. So we must splice out the * node we are given, not some other node, and must not move contents from * one node to another behind the user's back. */ if (delete->left != nil && delete->right != nil) { dnode_t *next = dict_next(dict, delete); dnode_t *nextparent = next->parent; dnode_color_t nextcolor = next->color; assert (next != nil); assert (next->parent != nil); assert (next->left == nil); /* * First, splice out the successor from the tree completely, by * moving up its right child into its place. */ child = next->right; child->parent = nextparent; if (nextparent->left == next) { nextparent->left = child; } else { assert (nextparent->right == next); nextparent->right = child; } /* * Now that the successor has been extricated from the tree, install it * in place of the node that we want deleted. */ next->parent = delparent; next->left = delete->left; next->right = delete->right; next->left->parent = next; next->right->parent = next; next->color = delete->color; delete->color = nextcolor; if (delparent->left == delete) { delparent->left = next; } else { assert (delparent->right == delete); delparent->right = next; } } else { assert (delete != nil); assert (delete->left == nil || delete->right == nil); child = (delete->left != nil) ? delete->left : delete->right; child->parent = delparent = delete->parent; if (delete == delparent->left) { delparent->left = child; } else { assert (delete == delparent->right); delparent->right = child; } } delete->parent = NULL; delete->right = NULL; delete->left = NULL; dict->nodecount--; assert (verify_bintree(dict)); /* red-black adjustments */ if (delete->color == dnode_black) { dnode_t *parent, *sister; dict_root(dict)->color = dnode_red; while (child->color == dnode_black) { parent = child->parent; if (child == parent->left) { sister = parent->right; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_left(parent); sister = parent->right; assert (sister != nil); } if (sister->left->color == dnode_black && sister->right->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->right->color == dnode_black) { assert (sister->left->color == dnode_red); sister->left->color = dnode_black; sister->color = dnode_red; rotate_right(sister); sister = parent->right; assert (sister != nil); } sister->color = parent->color; sister->right->color = dnode_black; parent->color = dnode_black; rotate_left(parent); break; } } else { /* symmetric case: child == child->parent->right */ assert (child == parent->right); sister = parent->left; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_right(parent); sister = parent->left; assert (sister != nil); } if (sister->right->color == dnode_black && sister->left->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->left->color == dnode_black) { assert (sister->right->color == dnode_red); sister->right->color = dnode_black; sister->color = dnode_red; rotate_left(sister); sister = parent->left; assert (sister != nil); } sister->color = parent->color; sister->left->color = dnode_black; parent->color = dnode_black; rotate_right(parent); break; } } } child->color = dnode_black; dict_root(dict)->color = dnode_black; } assert (dict_verify(dict)); return delete; } /* * Allocate a node using the dictionary's allocator routine, give it * the data item. */ int dict_alloc_insert(dict_t *dict, const void *key, void *data) { dnode_t *node = dict->allocnode (dict->context); if (node) { dnode_init(node, data); dict_insert(dict, node, key); return 1; } return 0; } void dict_delete_free(dict_t *dict, dnode_t *node) { dict_delete(dict, node); dict->freenode(node, dict->context); } /* * Return the node with the lowest (leftmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_first(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; if (root != nil) while ((left = root->left) != nil) root = left; return (root == nil) ? NULL : root; } /* * Return the node with the highest (rightmost) key. If the dictionary is empty * (that is, dict_isempty(dict) returns 1) a null pointer is returned. */ dnode_t *dict_last(dict_t *dict) { dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; if (root != nil) while ((right = root->right) != nil) root = right; return (root == nil) ? NULL : root; } /* * Return the given node's successor node---the node which has the * next key in the the left to right ordering. If the node has * no successor, a null pointer is returned rather than a pointer to * the nil node. */ dnode_t *dict_next(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *left; if (curr->right != nil) { curr = curr->right; while ((left = curr->left) != nil) curr = left; return curr; } parent = curr->parent; while (parent != nil && curr == parent->right) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } /* * Return the given node's predecessor, in the key order. * The nil sentinel node is returned if there is no predecessor. */ dnode_t *dict_prev(dict_t *dict, dnode_t *curr) { dnode_t *nil = dict_nil(dict), *parent, *right; if (curr->left != nil) { curr = curr->left; while ((right = curr->right) != nil) curr = right; return curr; } parent = curr->parent; while (parent != nil && curr == parent->left) { curr = parent; parent = curr->parent; } return (parent == nil) ? NULL : parent; } void dict_allow_dupes(dict_t *dict) { dict->dupes = 1; } #undef dict_count #undef dict_isempty #undef dict_isfull #undef dnode_get #undef dnode_put #undef dnode_getkey dictcount_t dict_count(dict_t *dict) { return dict->nodecount; } int dict_isempty(dict_t *dict) { return dict->nodecount == 0; } int dict_isfull(dict_t *dict) { return dict->nodecount == dict->maxcount; } int dict_contains(dict_t *dict, dnode_t *node) { return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); } static dnode_t *dnode_alloc(void *context) { return XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); } static void dnode_free(dnode_t *node, void *context) { XFREE(MTYPE_ISIS_DICT_NODE, node); } dnode_t *dnode_create(void *data) { dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t)); if (new) { new->data = data; new->parent = NULL; new->left = NULL; new->right = NULL; } return new; } dnode_t *dnode_init(dnode_t *dnode, void *data) { dnode->data = data; dnode->parent = NULL; dnode->left = NULL; dnode->right = NULL; return dnode; } void dnode_destroy(dnode_t *dnode) { assert (!dnode_is_in_a_dict(dnode)); XFREE(MTYPE_ISIS_DICT_NODE, dnode); } void *dnode_get(dnode_t *dnode) { return dnode->data; } const void *dnode_getkey(dnode_t *dnode) { return dnode->key; } void dnode_put(dnode_t *dnode, void *data) { dnode->data = data; } int dnode_is_in_a_dict(dnode_t *dnode) { return (dnode->parent && dnode->left && dnode->right); } void dict_process(dict_t *dict, void *context, dnode_process_t function) { dnode_t *node = dict_first(dict), *next; while (node != NULL) { /* check for callback function deleting */ /* the next node from under us */ assert (dict_contains(dict, node)); next = dict_next(dict, node); function(dict, node, context); node = next; } } static void load_begin_internal(dict_load_t *load, dict_t *dict) { load->dictptr = dict; load->nilnode.left = &load->nilnode; load->nilnode.right = &load->nilnode; } void dict_load_begin(dict_load_t *load, dict_t *dict) { assert (dict_isempty(dict)); load_begin_internal(load, dict); } void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) { dict_t *dict = load->dictptr; dnode_t *nil = &load->nilnode; assert (!dnode_is_in_a_dict(newnode)); assert (dict->nodecount < dict->maxcount); #ifndef NDEBUG if (dict->nodecount > 0) { if (dict->dupes) assert (dict->compare(nil->left->key, key) <= 0); else assert (dict->compare(nil->left->key, key) < 0); } #endif newnode->key = key; nil->right->left = newnode; nil->right = newnode; newnode->left = nil; dict->nodecount++; } void dict_load_end(dict_load_t *load) { dict_t *dict = load->dictptr; dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; dnode_t *complete = 0; dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; dictcount_t botrowcount; unsigned baselevel = 0, level = 0, i; assert (dnode_red == 0 && dnode_black == 1); while (fullcount >= nodecount && fullcount) fullcount >>= 1; botrowcount = nodecount - fullcount; for (curr = loadnil->left; curr != loadnil; curr = next) { next = curr->left; if (complete == NULL && botrowcount-- == 0) { assert (baselevel == 0); assert (level == 0); baselevel = level = 1; complete = tree[0]; if (complete != 0) { tree[0] = 0; complete->right = dictnil; while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } } if (complete == NULL) { curr->left = dictnil; curr->right = dictnil; curr->color = level % 2; complete = curr; assert (level == baselevel); while (tree[level] != 0) { tree[level]->right = complete; complete->parent = tree[level]; complete = tree[level]; tree[level++] = 0; } } else { curr->left = complete; curr->color = (level + 1) % 2; complete->parent = curr; tree[level] = curr; complete = 0; level = baselevel; } } if (complete == NULL) complete = dictnil; for (i = 0; i < DICT_DEPTH_MAX; i++) { if (tree[i] != 0) { tree[i]->right = complete; complete->parent = tree[i]; complete = tree[i]; } } dictnil->color = dnode_black; dictnil->right = dictnil; complete->parent = dictnil; complete->color = dnode_black; dict_root(dict) = complete; assert (dict_verify(dict)); } void dict_merge(dict_t *dest, dict_t *source) { dict_load_t load; dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); assert (dict_similar(dest, source)); if (source == dest) return; dest->nodecount = 0; load_begin_internal(&load, dest); for (;;) { if (leftnode != NULL && rightnode != NULL) { if (dest->compare(leftnode->key, rightnode->key) < 0) goto copyleft; else goto copyright; } else if (leftnode != NULL) { goto copyleft; } else if (rightnode != NULL) { goto copyright; } else { assert (leftnode == NULL && rightnode == NULL); break; } copyleft: { dnode_t *next = dict_next(dest, leftnode); #ifndef NDEBUG leftnode->left = NULL; /* suppress assertion in dict_load_next */ #endif dict_load_next(&load, leftnode, leftnode->key); leftnode = next; continue; } copyright: { dnode_t *next = dict_next(source, rightnode); #ifndef NDEBUG rightnode->left = NULL; #endif dict_load_next(&load, rightnode, rightnode->key); rightnode = next; continue; } } dict_clear(source); dict_load_end(&load); } #ifdef KAZLIB_TEST_MAIN #include #include #include #include typedef char input_t[256]; static int tokenize(char *string, ...) { char **tokptr; va_list arglist; int tokcount = 0; va_start(arglist, string); tokptr = va_arg(arglist, char **); while (tokptr) { while (*string && isspace((unsigned char) *string)) string++; if (!*string) break; *tokptr = string; while (*string && !isspace((unsigned char) *string)) string++; tokptr = va_arg(arglist, char **); tokcount++; if (!*string) break; *string++ = 0; } va_end(arglist); return tokcount; } static int comparef(const void *key1, const void *key2) { return strcmp(key1, key2); } static char *dupstring(char *str) { int sz = strlen(str) + 1; char *new = XCALLOC(MTYPE_ISIS_TMP, sz); if (new) memcpy(new, str, sz); return new; } static dnode_t *new_node(void *c) { static dnode_t few[5]; static int count; if (count < 5) return few + count++; return NULL; } static void del_node(dnode_t *n, void *c) { } static int prompt = 0; static void construct(dict_t *d) { input_t in; int done = 0; dict_load_t dl; dnode_t *dn; char *tok1, *tok2, *val; const char *key; char *help = "p turn prompt on\n" "q finish construction\n" "a add new entry\n"; if (!dict_isempty(d)) puts("warning: dictionary not empty!"); dict_load_begin(&dl, d); while (!done) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch (in[0]) { case '?': puts(help); break; case 'p': prompt = 1; break; case 'q': done = 1; break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); dn = dnode_create(val); if (!key || !val || !dn) { puts("out of memory"); free((void *) key); free(val); if (dn) dnode_destroy(dn); } dict_load_next(&dl, dn, key); break; default: putchar('?'); putchar('\n'); break; } } dict_load_end(&dl); } int main(void) { input_t in; dict_t darray[10]; dict_t *d = &darray[0]; dnode_t *dn; int i; char *tok1, *tok2, *val; const char *key; char *help = "a add value to dictionary\n" "d delete value from dictionary\n" "l lookup value in dictionary\n" "( lookup lower bound\n" ") lookup upper bound\n" "# switch to alternate dictionary (0-9)\n" "j merge two dictionaries\n" "f free the whole dictionary\n" "k allow duplicate keys\n" "c show number of entries\n" "t dump whole dictionary in sort order\n" "m make dictionary out of sorted items\n" "p turn prompt on\n" "s switch to non-functioning allocator\n" "q quit"; for (i = 0; i < 10; i++) dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); for (;;) { if (prompt) putchar('>'); fflush(stdout); if (!fgets(in, sizeof(input_t), stdin)) break; switch(in[0]) { case '?': puts(help); break; case 'a': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } key = dupstring(tok1); val = dupstring(tok2); if (!key || !val) { puts("out of memory"); free((void *) key); free(val); } if (!dict_alloc_insert(d, key, val)) { puts("dict_alloc_insert failed"); free((void *) key); free(val); break; } break; case 'd': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = dict_lookup(d, tok1); if (!dn) { puts("dict_lookup failed"); break; } val = dnode_get(dn); key = dnode_getkey(dn); dict_delete_free(d, dn); free(val); free((void *) key); break; case 'f': dict_free(d); break; case 'l': case '(': case ')': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } dn = 0; switch (in[0]) { case 'l': dn = dict_lookup(d, tok1); break; case '(': dn = dict_lower_bound(d, tok1); break; case ')': dn = dict_upper_bound(d, tok1); break; } if (!dn) { puts("lookup failed"); break; } val = dnode_get(dn); puts(val); break; case 'm': construct(d); break; case 'k': dict_allow_dupes(d); break; case 'c': printf("%lu\n", (unsigned long) dict_count(d)); break; case 't': for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { printf("%s\t%s\n", (char *) dnode_getkey(dn), (char *) dnode_get(dn)); } break; case 'q': exit(0); break; case '\0': break; case 'p': prompt = 1; break; case 's': dict_set_allocator(d, new_node, del_node, NULL); break; case '#': if (tokenize(in+1, &tok1, (char **) 0) != 1) { puts("what?"); break; } else { int dictnum = atoi(tok1); if (dictnum < 0 || dictnum > 9) { puts("invalid number"); break; } d = &darray[dictnum]; } break; case 'j': if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { puts("what?"); break; } else { int dict1 = atoi(tok1), dict2 = atoi(tok2); if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { puts("invalid number"); break; } dict_merge(&darray[dict1], &darray[dict2]); } break; default: putchar('?'); putchar('\n'); break; } } return 0; } #endif quagga-0.99.24.1/isisd/isis_lsp.c0000644000175000017500000023116512476520570013350 00000000000000/* * IS-IS Rout(e)ing protocol - isis_lsp.c * LSP processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "thread.h" #include "vty.h" #include "stream.h" #include "memory.h" #include "log.h" #include "prefix.h" #include "command.h" #include "hash.h" #include "if.h" #include "checksum.h" #include "md5.h" #include "isisd/dict.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isis_circuit.h" #include "isisd/isisd.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_pdu.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_misc.h" #include "isisd/isis_csm.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_spf.h" #ifdef TOPOLOGY_GENERATE #include "spgrid.h" #endif /* staticly assigned vars for printing purposes */ char lsp_bits_string[200]; /* FIXME: enough ? */ static int lsp_l1_refresh (struct thread *thread); static int lsp_l2_refresh (struct thread *thread); static int lsp_l1_refresh_pseudo (struct thread *thread); static int lsp_l2_refresh_pseudo (struct thread *thread); int lsp_id_cmp (u_char * id1, u_char * id2) { return memcmp (id1, id2, ISIS_SYS_ID_LEN + 2); } dict_t * lsp_db_init (void) { dict_t *dict; dict = dict_create (DICTCOUNT_T_MAX, (dict_comp_t) lsp_id_cmp); return dict; } struct isis_lsp * lsp_search (u_char * id, dict_t * lspdb) { dnode_t *node; #ifdef EXTREME_DEBUG dnode_t *dn; zlog_debug ("searching db"); for (dn = dict_first (lspdb); dn; dn = dict_next (lspdb, dn)) { zlog_debug ("%s\t%pX", rawlspid_print ((u_char *) dnode_getkey (dn)), dnode_get (dn)); } #endif /* EXTREME DEBUG */ node = dict_lookup (lspdb, id); if (node) return (struct isis_lsp *) dnode_get (node); return NULL; } static void lsp_clear_data (struct isis_lsp *lsp) { if (!lsp) return; if (lsp->tlv_data.hostname) isis_dynhn_remove (lsp->lsp_header->lsp_id); if (lsp->own_lsp) { if (lsp->tlv_data.nlpids) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.nlpids); if (lsp->tlv_data.hostname) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.hostname); if (lsp->tlv_data.router_id) XFREE (MTYPE_ISIS_TLV, lsp->tlv_data.router_id); } free_tlvs (&lsp->tlv_data); } static void lsp_destroy (struct isis_lsp *lsp) { struct listnode *cnode, *lnode, *lnnode; struct isis_lsp *lsp_in_list; struct isis_circuit *circuit; if (!lsp) return; for (ALL_LIST_ELEMENTS_RO (lsp->area->circuit_list, cnode, circuit)) { if (circuit->lsp_queue == NULL) continue; for (ALL_LIST_ELEMENTS (circuit->lsp_queue, lnode, lnnode, lsp_in_list)) if (lsp_in_list == lsp) list_delete_node(circuit->lsp_queue, lnode); } ISIS_FLAGS_CLEAR_ALL (lsp->SSNflags); ISIS_FLAGS_CLEAR_ALL (lsp->SRMflags); lsp_clear_data (lsp); if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0 && lsp->lspu.frags) { list_delete (lsp->lspu.frags); lsp->lspu.frags = NULL; } isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif if (lsp->pdu) stream_free (lsp->pdu); XFREE (MTYPE_ISIS_LSP, lsp); } void lsp_db_destroy (dict_t * lspdb) { dnode_t *dnode, *next; struct isis_lsp *lsp; dnode = dict_first (lspdb); while (dnode) { next = dict_next (lspdb, dnode); lsp = dnode_get (dnode); lsp_destroy (lsp); dict_delete_free (lspdb, dnode); dnode = next; } dict_free (lspdb); return; } /* * Remove all the frags belonging to the given lsp */ static void lsp_remove_frags (struct list *frags, dict_t * lspdb) { dnode_t *dnode; struct listnode *lnode, *lnnode; struct isis_lsp *lsp; for (ALL_LIST_ELEMENTS (frags, lnode, lnnode, lsp)) { dnode = dict_lookup (lspdb, lsp->lsp_header->lsp_id); lsp_destroy (lsp); dnode_destroy (dict_delete (lspdb, dnode)); } list_delete_all_node (frags); return; } void lsp_search_and_destroy (u_char * id, dict_t * lspdb) { dnode_t *node; struct isis_lsp *lsp; node = dict_lookup (lspdb, id); if (node) { node = dict_delete (lspdb, node); lsp = dnode_get (node); /* * If this is a zero lsp, remove all the frags now */ if (LSP_FRAGMENT (lsp->lsp_header->lsp_id) == 0) { if (lsp->lspu.frags) lsp_remove_frags (lsp->lspu.frags, lspdb); } else { /* * else just remove this frag, from the zero lsps' frag list */ if (lsp->lspu.zero_lsp && lsp->lspu.zero_lsp->lspu.frags) listnode_delete (lsp->lspu.zero_lsp->lspu.frags, lsp); } lsp_destroy (lsp); dnode_destroy (node); } } /* * Compares a LSP to given values * Params are given in net order */ int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, u_int16_t checksum, u_int16_t rem_lifetime) { /* no point in double ntohl on seqnum */ if (lsp->lsp_header->seq_num == seq_num && lsp->lsp_header->checksum == checksum && /*comparing with 0, no need to do ntohl */ ((lsp->lsp_header->rem_lifetime == 0 && rem_lifetime == 0) || (lsp->lsp_header->rem_lifetime != 0 && rem_lifetime != 0))) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is equal to ours seq 0x%08x," " cksum 0x%04x, lifetime %us", areatag, ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); } return LSP_EQUAL; } if (ntohl (seq_num) >= ntohl (lsp->lsp_header->seq_num)) { if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x," " lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is newer than ours seq 0x%08x, " "cksum 0x%04x, lifetime %us", areatag, ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } return LSP_NEWER; } if (isis->debugs & DEBUG_SNP_PACKETS) { zlog_debug ("ISIS-Snp (%s): Compare LSP %s seq 0x%08x, cksum 0x%04x, lifetime %us", areatag, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (seq_num), ntohs (checksum), ntohs (rem_lifetime)); zlog_debug ("ISIS-Snp (%s): is older than ours seq 0x%08x," " cksum 0x%04x, lifetime %us", areatag, ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime)); } return LSP_OLDER; } static void lsp_auth_add (struct isis_lsp *lsp) { struct isis_passwd *passwd; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; /* * Add the authentication info if its present */ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : (passwd = &lsp->area->domain_passwd); switch (passwd->type) { /* Cleartext */ case ISIS_PASSWD_TYPE_CLEARTXT: memcpy (&lsp->tlv_data.auth_info, passwd, sizeof (struct isis_passwd)); tlv_add_authinfo (passwd->type, passwd->len, passwd->passwd, lsp->pdu); break; /* HMAC MD5 */ case ISIS_PASSWD_TYPE_HMAC_MD5: /* Remember where TLV is written so we can later * overwrite the MD5 hash */ lsp->auth_tlv_offset = stream_get_endp (lsp->pdu); memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE); lsp->tlv_data.auth_info.type = ISIS_PASSWD_TYPE_HMAC_MD5; lsp->tlv_data.auth_info.len = ISIS_AUTH_MD5_SIZE; memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); tlv_add_authinfo (passwd->type, ISIS_AUTH_MD5_SIZE, hmac_md5_hash, lsp->pdu); break; default: break; } } static void lsp_auth_update (struct isis_lsp *lsp) { struct isis_passwd *passwd; unsigned char hmac_md5_hash[ISIS_AUTH_MD5_SIZE]; uint16_t checksum, rem_lifetime; /* For HMAC MD5 we need to recompute the md5 hash and store it */ (lsp->level == IS_LEVEL_1) ? (passwd = &lsp->area->area_passwd) : (passwd = &lsp->area->domain_passwd); if (passwd->type != ISIS_PASSWD_TYPE_HMAC_MD5) return; /* * In transient conditions (when net is configured where authentication * config and lsp regenerate schedule is not yet run), there could be * an own_lsp with auth_tlv_offset set to 0. In such a case, simply * return, when lsp_regenerate is run, lsp will have auth tlv. */ if (lsp->auth_tlv_offset == 0) return; /* * RFC 5304 set auth value, checksum and remaining lifetime to zero * before computation and reset to old values after computation. */ checksum = lsp->lsp_header->checksum; rem_lifetime = lsp->lsp_header->rem_lifetime; lsp->lsp_header->checksum = 0; lsp->lsp_header->rem_lifetime = 0; /* Set the authentication value as well to zero */ memset (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, 0, ISIS_AUTH_MD5_SIZE); /* Compute autentication value */ hmac_md5 (STREAM_DATA (lsp->pdu), stream_get_endp(lsp->pdu), (unsigned char *) &passwd->passwd, passwd->len, (caddr_t) &hmac_md5_hash); /* Copy the hash into the stream */ memcpy (STREAM_DATA (lsp->pdu) + lsp->auth_tlv_offset + 3, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); memcpy (&lsp->tlv_data.auth_info.passwd, hmac_md5_hash, ISIS_AUTH_MD5_SIZE); /* Copy back the checksum and remaining lifetime */ lsp->lsp_header->checksum = checksum; lsp->lsp_header->rem_lifetime = rem_lifetime; } void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num) { u_int32_t newseq; if (seq_num == 0 || ntohl (lsp->lsp_header->seq_num) > seq_num) newseq = ntohl (lsp->lsp_header->seq_num) + 1; else newseq = seq_num + 1; lsp->lsp_header->seq_num = htonl (newseq); /* Recompute authentication and checksum information */ lsp_auth_update (lsp); /* ISO 10589 - 7.3.11 Generation of the checksum * The checksum shall be computed over all fields in the LSP which appear * after the Remaining Lifetime field. This field (and those appearing * before it) are excluded so that the LSP may be aged by systems without * requiring recomputation. */ fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif return; } /* * Genetates checksum for LSP and its frags */ static void lsp_seqnum_update (struct isis_lsp *lsp0) { struct isis_lsp *lsp; struct listnode *node; lsp_inc_seqnum (lsp0, 0); if (!lsp0->lspu.frags) return; for (ALL_LIST_ELEMENTS_RO (lsp0->lspu.frags, node, lsp)) lsp_inc_seqnum (lsp, 0); return; } static u_int8_t lsp_bits_generate (int level, int overload_bit) { u_int8_t lsp_bits = 0; if (level == IS_LEVEL_1) lsp_bits = IS_LEVEL_1; else lsp_bits = IS_LEVEL_1_AND_2; if (overload_bit) lsp_bits |= overload_bit; return lsp_bits; } static void lsp_update_data (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level) { uint32_t expected = 0, found; int retval; /* free the old lsp data */ lsp_clear_data (lsp); /* copying only the relevant part of our stream */ if (lsp->pdu != NULL) stream_free (lsp->pdu); lsp->pdu = stream_dup (stream); /* setting pointers to the correct place */ lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); lsp->area = area; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; lsp->installed = time (NULL); /* * Get LSP data i.e. TLVs */ expected |= TLVFLAG_AUTH_INFO; expected |= TLVFLAG_AREA_ADDRS; expected |= TLVFLAG_IS_NEIGHS; expected |= TLVFLAG_NLPID; if (area->dynhostname) expected |= TLVFLAG_DYN_HOSTNAME; if (area->newmetric) { expected |= TLVFLAG_TE_IS_NEIGHS; expected |= TLVFLAG_TE_IPV4_REACHABILITY; expected |= TLVFLAG_TE_ROUTER_ID; } expected |= TLVFLAG_IPV4_ADDR; expected |= TLVFLAG_IPV4_INT_REACHABILITY; expected |= TLVFLAG_IPV4_EXT_REACHABILITY; #ifdef HAVE_IPV6 expected |= TLVFLAG_IPV6_ADDR; expected |= TLVFLAG_IPV6_REACHABILITY; #endif /* HAVE_IPV6 */ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, ntohs (lsp->lsp_header->pdu_len) - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &lsp->tlv_data, NULL); if (retval != ISIS_OK) { zlog_warn ("Could not parse LSP"); return; } if ((found & TLVFLAG_DYN_HOSTNAME) && (area->dynhostname)) { isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, (lsp->lsp_header->lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 ? IS_LEVEL_2 : IS_LEVEL_1); } return; } void lsp_update (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level) { dnode_t *dnode = NULL; /* Remove old LSP from database. This is required since the * lsp_update_data will free the lsp->pdu (which has the key, lsp_id) * and will update it with the new data in the stream. */ dnode = dict_lookup (area->lspdb[level - 1], lsp->lsp_header->lsp_id); if (dnode) dnode_destroy (dict_delete (area->lspdb[level - 1], dnode)); /* rebuild the lsp data */ lsp_update_data (lsp, stream, area, level); /* insert the lsp back into the database */ lsp_insert (lsp, area->lspdb[level - 1]); } /* creation of LSP directly from what we received */ struct isis_lsp * lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, struct isis_area *area, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp_update_data (lsp, stream, area, level); if (lsp0 == NULL) { /* * zero lsp -> create the list for fragments */ lsp->lspu.frags = list_new (); } else { /* * a fragment -> set the backpointer and add this to zero lsps frag list */ lsp->lspu.zero_lsp = lsp0; listnode_add (lsp0->lspu.frags, lsp); } return lsp; } struct isis_lsp * lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level) { struct isis_lsp *lsp; lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); if (!lsp) { /* FIXME: set lspdbol bit */ zlog_warn ("lsp_new(): out of memory"); return NULL; } /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); if (LSP_FRAGMENT (lsp_id) == 0) lsp->lspu.frags = list_new (); lsp->isis_header = (struct isis_fixed_hdr *) (STREAM_DATA (lsp->pdu)); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); /* at first we fill the FIXED HEADER */ (level == IS_LEVEL_1) ? fill_fixed_hdr (lsp->isis_header, L1_LINK_STATE) : fill_fixed_hdr (lsp->isis_header, L2_LINK_STATE); /* now for the LSP HEADER */ /* Minimal LSP PDU size */ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); memcpy (lsp->lsp_header->lsp_id, lsp_id, ISIS_SYS_ID_LEN + 2); lsp->lsp_header->checksum = checksum; /* Provided in network order */ lsp->lsp_header->seq_num = htonl (seq_num); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp->lsp_header->lsp_bits = lsp_bits; lsp->level = level; lsp->age_out = ZERO_AGE_LIFETIME; stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); if (isis->debugs & DEBUG_EVENTS) zlog_debug ("New LSP with ID %s-%02x-%02x len %d seqnum %08x", sysid_print (lsp_id), LSP_PSEUDO_ID (lsp->lsp_header->lsp_id), LSP_FRAGMENT (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num)); return lsp; } void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb) { dict_alloc_insert (lspdb, lsp->lsp_header->lsp_id, lsp); if (lsp->lsp_header->seq_num != 0) { isis_spf_schedule (lsp->area, lsp->level); #ifdef HAVE_IPV6 isis_spf_schedule6 (lsp->area, lsp->level); #endif } } /* * Build a list of LSPs with non-zero ht bounded by start and stop ids */ void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, struct list *list, dict_t * lspdb) { dnode_t *first, *last, *curr; first = dict_lower_bound (lspdb, start_id); if (!first) return; last = dict_upper_bound (lspdb, stop_id); curr = first; if (((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime) listnode_add (list, first->dict_data); while (curr) { curr = dict_next (lspdb, curr); if (curr && ((struct isis_lsp *) (curr->dict_data))->lsp_header->rem_lifetime) listnode_add (list, curr->dict_data); if (curr == last) break; } return; } /* * Build a list of num_lsps LSPs bounded by start_id and stop_id. */ void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb) { u_char count; dnode_t *first, *last, *curr; first = dict_lower_bound (lspdb, start_id); if (!first) return; last = dict_upper_bound (lspdb, stop_id); curr = first; listnode_add (list, first->dict_data); count = 1; while (curr) { curr = dict_next (lspdb, curr); if (curr) { listnode_add (list, curr->dict_data); count++; } if (count == num_lsps || curr == last) break; } return; } /* * Build a list of LSPs with SSN flag set for the given circuit */ void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, struct list *list, dict_t * lspdb) { dnode_t *dnode, *next; struct isis_lsp *lsp; u_char count = 0; dnode = dict_first (lspdb); while (dnode != NULL) { next = dict_next (lspdb, dnode); lsp = dnode_get (dnode); if (ISIS_CHECK_FLAG (lsp->SSNflags, circuit)) { listnode_add (list, lsp); ++count; } if (count == num_lsps) break; dnode = next; } return; } static void lsp_set_time (struct isis_lsp *lsp) { assert (lsp); if (lsp->lsp_header->rem_lifetime == 0) { if (lsp->age_out > 0) lsp->age_out--; return; } lsp->lsp_header->rem_lifetime = htons (ntohs (lsp->lsp_header->rem_lifetime) - 1); } static void lspid_print (u_char * lsp_id, u_char * trg, char dynhost, char frag) { struct isis_dynhn *dyn = NULL; u_char id[SYSID_STRLEN]; if (dynhost) dyn = dynhn_find_by_id (lsp_id); else dyn = NULL; if (dyn) sprintf ((char *)id, "%.14s", dyn->name.name); else if (!memcmp (isis->sysid, lsp_id, ISIS_SYS_ID_LEN) && dynhost) sprintf ((char *)id, "%.14s", unix_hostname ()); else memcpy (id, sysid_print (lsp_id), 15); if (frag) sprintf ((char *)trg, "%s.%02x-%02x", id, LSP_PSEUDO_ID (lsp_id), LSP_FRAGMENT (lsp_id)); else sprintf ((char *)trg, "%s.%02x", id, LSP_PSEUDO_ID (lsp_id)); } /* Convert the lsp attribute bits to attribute string */ const char * lsp_bits2string (u_char * lsp_bits) { char *pos = lsp_bits_string; if (!*lsp_bits) return " none"; /* we only focus on the default metric */ pos += sprintf (pos, "%d/", ISIS_MASK_LSP_ATT_DEFAULT_BIT (*lsp_bits) ? 1 : 0); pos += sprintf (pos, "%d/", ISIS_MASK_LSP_PARTITION_BIT (*lsp_bits) ? 1 : 0); pos += sprintf (pos, "%d", ISIS_MASK_LSP_OL_BIT (*lsp_bits) ? 1 : 0); *(pos) = '\0'; return lsp_bits_string; } /* this function prints the lsp on show isis database */ void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost) { u_char LSPid[255]; char age_out[8]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); vty_out (vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); vty_out (vty, "%5u ", ntohs (lsp->lsp_header->pdu_len)); vty_out (vty, "0x%08x ", ntohl (lsp->lsp_header->seq_num)); vty_out (vty, "0x%04x ", ntohs (lsp->lsp_header->checksum)); if (ntohs (lsp->lsp_header->rem_lifetime) == 0) { snprintf (age_out, 8, "(%u)", lsp->age_out); age_out[7] = '\0'; vty_out (vty, "%7s ", age_out); } else vty_out (vty, " %5u ", ntohs (lsp->lsp_header->rem_lifetime)); vty_out (vty, "%s%s", lsp_bits2string (&lsp->lsp_header->lsp_bits), VTY_NEWLINE); } void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost) { struct area_addr *area_addr; int i; struct listnode *lnode; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct ipv4_reachability *ipv4_reach; struct in_addr *ipv4_addr; struct te_ipv4_reachability *te_ipv4_reach; #ifdef HAVE_IPV6 struct ipv6_reachability *ipv6_reach; struct in6_addr in6; u_char buff[BUFSIZ]; #endif u_char LSPid[255]; u_char hostname[255]; u_char ipv4_reach_prefix[20]; u_char ipv4_reach_mask[20]; u_char ipv4_address[20]; lspid_print (lsp->lsp_header->lsp_id, LSPid, dynhost, 1); lsp_print (lsp, vty, dynhost); /* for all area address */ if (lsp->tlv_data.area_addrs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.area_addrs, lnode, area_addr)) { vty_out (vty, " Area Address: %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len), VTY_NEWLINE); } /* for the nlpid tlv */ if (lsp->tlv_data.nlpids) { for (i = 0; i < lsp->tlv_data.nlpids->count; i++) { switch (lsp->tlv_data.nlpids->nlpids[i]) { case NLPID_IP: case NLPID_IPV6: vty_out (vty, " NLPID : 0x%X%s", lsp->tlv_data.nlpids->nlpids[i], VTY_NEWLINE); break; default: vty_out (vty, " NLPID : %s%s", "unknown", VTY_NEWLINE); break; } } } /* for the hostname tlv */ if (lsp->tlv_data.hostname) { bzero (hostname, sizeof (hostname)); memcpy (hostname, lsp->tlv_data.hostname->name, lsp->tlv_data.hostname->namelen); vty_out (vty, " Hostname : %s%s", hostname, VTY_NEWLINE); } /* authentication tlv */ if (lsp->tlv_data.auth_info.type != ISIS_PASSWD_TYPE_UNUSED) { if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_HMAC_MD5) vty_out (vty, " Auth type : md5%s", VTY_NEWLINE); else if (lsp->tlv_data.auth_info.type == ISIS_PASSWD_TYPE_CLEARTXT) vty_out (vty, " Auth type : clear text%s", VTY_NEWLINE); } /* TE router id */ if (lsp->tlv_data.router_id) { memcpy (ipv4_address, inet_ntoa (lsp->tlv_data.router_id->id), sizeof (ipv4_address)); vty_out (vty, " Router ID : %s%s", ipv4_address, VTY_NEWLINE); } if (lsp->tlv_data.ipv4_addrs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_addrs, lnode, ipv4_addr)) { memcpy (ipv4_address, inet_ntoa (*ipv4_addr), sizeof (ipv4_address)); vty_out (vty, " IPv4 Address: %s%s", ipv4_address, VTY_NEWLINE); } /* for the IS neighbor tlv */ if (lsp->tlv_data.is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.is_neighs, lnode, is_neigh)) { lspid_print (is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS : %s%s", is_neigh->metrics.metric_default, LSPid, VTY_NEWLINE); } /* for the internal reachable tlv */ if (lsp->tlv_data.ipv4_int_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_int_reachs, lnode, ipv4_reach)) { memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix), sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); vty_out (vty, " Metric : %-8d IPv4-Internal : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } /* for the external reachable tlv */ if (lsp->tlv_data.ipv4_ext_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv4_ext_reachs, lnode, ipv4_reach)) { memcpy (ipv4_reach_prefix, inet_ntoa (ipv4_reach->prefix), sizeof (ipv4_reach_prefix)); memcpy (ipv4_reach_mask, inet_ntoa (ipv4_reach->mask), sizeof (ipv4_reach_mask)); vty_out (vty, " Metric : %-8d IPv4-External : %s %s%s", ipv4_reach->metrics.metric_default, ipv4_reach_prefix, ipv4_reach_mask, VTY_NEWLINE); } /* IPv6 tlv */ #ifdef HAVE_IPV6 if (lsp->tlv_data.ipv6_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.ipv6_reachs, lnode, ipv6_reach)) { memset (&in6, 0, sizeof (in6)); memcpy (in6.s6_addr, ipv6_reach->prefix, PSIZE (ipv6_reach->prefix_len)); inet_ntop (AF_INET6, &in6, (char *)buff, BUFSIZ); if ((ipv6_reach->control_info && CTRL_INFO_DISTRIBUTION) == DISTRIBUTION_INTERNAL) vty_out (vty, " Metric : %-8d IPv6-Internal : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); else vty_out (vty, " Metric : %-8d IPv6-External : %s/%d%s", ntohl (ipv6_reach->metric), buff, ipv6_reach->prefix_len, VTY_NEWLINE); } #endif /* TE IS neighbor tlv */ if (lsp->tlv_data.te_is_neighs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_is_neighs, lnode, te_is_neigh)) { lspid_print (te_is_neigh->neigh_id, LSPid, dynhost, 0); vty_out (vty, " Metric : %-8d IS-Extended : %s%s", GET_TE_METRIC(te_is_neigh), LSPid, VTY_NEWLINE); } /* TE IPv4 tlv */ if (lsp->tlv_data.te_ipv4_reachs) for (ALL_LIST_ELEMENTS_RO (lsp->tlv_data.te_ipv4_reachs, lnode, te_ipv4_reach)) { /* FIXME: There should be better way to output this stuff. */ vty_out (vty, " Metric : %-8d IPv4-Extended : %s/%d%s", ntohl (te_ipv4_reach->te_metric), inet_ntoa (newprefix2inaddr (&te_ipv4_reach->prefix_start, te_ipv4_reach->control)), te_ipv4_reach->control & 0x3F, VTY_NEWLINE); } vty_out (vty, "%s", VTY_NEWLINE); return; } /* print all the lsps info in the local lspdb */ int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost) { dnode_t *node = dict_first (lspdb), *next; int lsp_count = 0; if (detail == ISIS_UI_LEVEL_BRIEF) { while (node != NULL) { /* I think it is unnecessary, so I comment it out */ /* dict_contains (lspdb, node); */ next = dict_next (lspdb, node); lsp_print (dnode_get (node), vty, dynhost); node = next; lsp_count++; } } else if (detail == ISIS_UI_LEVEL_DETAIL) { while (node != NULL) { next = dict_next (lspdb, node); lsp_print_detail (dnode_get (node), vty, dynhost); node = next; lsp_count++; } } return lsp_count; } #define FRAG_THOLD(S,T) \ ((STREAM_SIZE(S)*T)/100) /* stream*, area->lsp_frag_threshold, increment */ #define FRAG_NEEDED(S,T,I) \ (STREAM_SIZE(S)-STREAM_REMAIN(S)+(I) > FRAG_THOLD(S,T)) /* FIXME: It shouldn't be necessary to pass tlvsize here, TLVs can have * variable length (TE TLVs, sub TLVs). */ static void lsp_tlv_fit (struct isis_lsp *lsp, struct list **from, struct list **to, int tlvsize, int frag_thold, int tlv_build_func (struct list *, struct stream *)) { int count, i; /* can we fit all ? */ if (!FRAG_NEEDED (lsp->pdu, frag_thold, listcount (*from) * tlvsize + 2)) { tlv_build_func (*from, lsp->pdu); if (listcount (*to) != 0) { struct listnode *node, *nextnode; void *elem; for (ALL_LIST_ELEMENTS (*from, node, nextnode, elem)) { listnode_add (*to, elem); list_delete_node (*from, node); } } else { list_free (*to); *to = *from; *from = NULL; } } else if (!FRAG_NEEDED (lsp->pdu, frag_thold, tlvsize + 2)) { /* fit all we can */ count = FRAG_THOLD (lsp->pdu, frag_thold) - 2 - (STREAM_SIZE (lsp->pdu) - STREAM_REMAIN (lsp->pdu)); count = count / tlvsize; if (count > (int)listcount (*from)) count = listcount (*from); for (i = 0; i < count; i++) { listnode_add (*to, listgetdata (listhead (*from))); listnode_delete (*from, listgetdata (listhead (*from))); } tlv_build_func (*to, lsp->pdu); } lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); return; } static u_int16_t lsp_rem_lifetime (struct isis_area *area, int level) { u_int16_t rem_lifetime; /* Add jitter to configured LSP lifetime */ rem_lifetime = isis_jitter (area->max_lsp_lifetime[level - 1], MAX_AGE_JITTER); /* No jitter if the max refresh will be less than configure gen interval */ if (area->lsp_gen_interval[level - 1] > (rem_lifetime - 300)) rem_lifetime = area->max_lsp_lifetime[level - 1]; return rem_lifetime; } static u_int16_t lsp_refresh_time (struct isis_lsp *lsp, u_int16_t rem_lifetime) { struct isis_area *area = lsp->area; int level = lsp->level; u_int16_t refresh_time; /* Add jitter to LSP refresh time */ refresh_time = isis_jitter (area->lsp_refresh[level - 1], MAX_LSP_GEN_JITTER); /* RFC 4444 : make sure the refresh time is at least less than 300 * of the remaining lifetime and more than gen interval */ if (refresh_time <= area->lsp_gen_interval[level - 1] || refresh_time > (rem_lifetime - 300)) refresh_time = rem_lifetime - 300; assert (area->lsp_gen_interval[level - 1] < refresh_time); return refresh_time; } static struct isis_lsp * lsp_next_frag (u_char frag_num, struct isis_lsp *lsp0, struct isis_area *area, int level) { struct isis_lsp *lsp; u_char frag_id[ISIS_SYS_ID_LEN + 2]; memcpy (frag_id, lsp0->lsp_header->lsp_id, ISIS_SYS_ID_LEN + 1); LSP_FRAGMENT (frag_id) = frag_num; /* FIXME add authentication TLV for fragment LSPs */ lsp = lsp_search (frag_id, area->lspdb[level - 1]); if (lsp) { /* Clear the TLVs */ lsp_clear_data (lsp); return lsp; } lsp = lsp_new (frag_id, ntohs(lsp0->lsp_header->rem_lifetime), 0, lsp_bits_generate (level, area->overload_bit), 0, level); lsp->area = area; lsp->own_lsp = 1; lsp_insert (lsp, area->lspdb[level - 1]); listnode_add (lsp0->lspu.frags, lsp); lsp->lspu.zero_lsp = lsp0; return lsp; } /* * Builds the LSP data part. This func creates a new frag whenever * area->lsp_frag_threshold is exceeded. */ static void lsp_build (struct isis_lsp *lsp, struct isis_area *area) { struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct listnode *node, *ipnode; int level = lsp->level; struct isis_circuit *circuit; struct prefix_ipv4 *ipv4; struct ipv4_reachability *ipreach; struct te_ipv4_reachability *te_ipreach; struct isis_adjacency *nei; #ifdef HAVE_IPV6 struct prefix_ipv6 *ipv6, *ip6prefix; struct ipv6_reachability *ip6reach; #endif /* HAVE_IPV6 */ struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; struct in_addr *routerid; uint32_t expected = 0, found = 0; uint32_t metric; u_char zero_id[ISIS_SYS_ID_LEN + 1]; int retval = ISIS_OK; /* * Building the zero lsp */ memset (zero_id, 0, ISIS_SYS_ID_LEN + 1); /* Reset stream endp. Stream is always there and on every LSP refresh only * TLV part of it is overwritten. So we must seek past header we will not * touch. */ stream_reset (lsp->pdu); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add the authentication info if its present */ lsp_auth_add (lsp); /* * First add the tlvs related to area */ /* Area addresses */ if (lsp->tlv_data.area_addrs == NULL) lsp->tlv_data.area_addrs = list_new (); list_add_list (lsp->tlv_data.area_addrs, area->area_addrs); if (listcount (lsp->tlv_data.area_addrs) > 0) tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); /* Protocols Supported */ if (area->ip_circuits > 0 #ifdef HAVE_IPV6 || area->ipv6_circuits > 0 #endif /* HAVE_IPV6 */ ) { lsp->tlv_data.nlpids = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids)); lsp->tlv_data.nlpids->count = 0; if (area->ip_circuits > 0) { lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; } #ifdef HAVE_IPV6 if (area->ipv6_circuits > 0) { lsp->tlv_data.nlpids->count++; lsp->tlv_data.nlpids->nlpids[lsp->tlv_data.nlpids->count - 1] = NLPID_IPV6; } #endif /* HAVE_IPV6 */ tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); } /* Dynamic Hostname */ if (area->dynhostname) { lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); memcpy (lsp->tlv_data.hostname->name, unix_hostname (), strlen (unix_hostname ())); lsp->tlv_data.hostname->namelen = strlen (unix_hostname ()); tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); } /* IPv4 address and TE router ID TLVs. In case of the first one we don't * follow "C" vendor, but "J" vendor behavior - one IPv4 address is put into * LSP and this address is same as router id. */ if (isis->router_id != 0) { if (lsp->tlv_data.ipv4_addrs == NULL) { lsp->tlv_data.ipv4_addrs = list_new (); lsp->tlv_data.ipv4_addrs->del = free_tlv; } routerid = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); routerid->s_addr = isis->router_id; listnode_add (lsp->tlv_data.ipv4_addrs, routerid); tlv_add_in_addr (routerid, lsp->pdu, IPV4_ADDR); /* Exactly same data is put into TE router ID TLV, but only if new style * TLV's are in use. */ if (area->newmetric) { lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct in_addr)); lsp->tlv_data.router_id->id.s_addr = isis->router_id; tlv_add_in_addr (&lsp->tlv_data.router_id->id, lsp->pdu, TE_ROUTER_ID); } } memset (&tlv_data, 0, sizeof (struct tlvs)); #ifdef TOPOLOGY_GENERATE /* If topology exists (and we create topology for level 1 only), create * (hardcoded) link to topology. */ if (area->topology && level == IS_LEVEL_1) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (1 & 0xFF); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((1 >> 8) & 0xFF); is_neigh->metrics.metric_default = 0x01; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } #endif /* TOPOLOGY_GENERATE */ /* * Then build lists of tlvs related to circuits */ for (ALL_LIST_ELEMENTS_RO (area->circuit_list, node, circuit)) { if (circuit->state != C_STATE_UP) continue; /* * Add IPv4 internal reachability of this circuit */ if (circuit->ip_router && circuit->ip_addrs && circuit->ip_addrs->count > 0) { if (area->oldmetric) { if (tlv_data.ipv4_int_reachs == NULL) { tlv_data.ipv4_int_reachs = list_new (); tlv_data.ipv4_int_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { ipreach = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv4_reachability)); ipreach->metrics = circuit->metrics[level - 1]; masklen2ip (ipv4->prefixlen, &ipreach->mask); ipreach->prefix.s_addr = ((ipreach->mask.s_addr) & (ipv4->prefix.s_addr)); listnode_add (tlv_data.ipv4_int_reachs, ipreach); } } if (area->newmetric) { if (tlv_data.te_ipv4_reachs == NULL) { tlv_data.te_ipv4_reachs = list_new (); tlv_data.te_ipv4_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ip_addrs, ipnode, ipv4)) { /* FIXME All this assumes that we have no sub TLVs. */ te_ipreach = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_ipv4_reachability) + ((ipv4->prefixlen + 7)/8) - 1); if (area->oldmetric) te_ipreach->te_metric = htonl (circuit->metrics[level - 1].metric_default); else te_ipreach->te_metric = htonl (circuit->te_metric[level - 1]); te_ipreach->control = (ipv4->prefixlen & 0x3F); memcpy (&te_ipreach->prefix_start, &ipv4->prefix.s_addr, (ipv4->prefixlen + 7)/8); listnode_add (tlv_data.te_ipv4_reachs, te_ipreach); } } } #ifdef HAVE_IPV6 /* * Add IPv6 reachability of this circuit */ if (circuit->ipv6_router && circuit->ipv6_non_link && circuit->ipv6_non_link->count > 0) { if (tlv_data.ipv6_reachs == NULL) { tlv_data.ipv6_reachs = list_new (); tlv_data.ipv6_reachs->del = free_tlv; } for (ALL_LIST_ELEMENTS_RO (circuit->ipv6_non_link, ipnode, ipv6)) { ip6reach = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct ipv6_reachability)); if (area->oldmetric) ip6reach->metric = htonl (circuit->metrics[level - 1].metric_default); else ip6reach->metric = htonl (circuit->te_metric[level - 1]); ip6reach->control_info = 0; ip6reach->prefix_len = ipv6->prefixlen; memcpy (&ip6prefix, &ipv6, sizeof(ip6prefix)); apply_mask_ipv6 (ip6prefix); memcpy (ip6reach->prefix, ip6prefix->prefix.s6_addr, sizeof (ip6reach->prefix)); listnode_add (tlv_data.ipv6_reachs, ip6reach); } } #endif /* HAVE_IPV6 */ switch (circuit->circ_type) { case CIRCUIT_T_BROADCAST: if (level & circuit->is_type) { if (area->oldmetric) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); if (level == IS_LEVEL_1) memcpy (is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); is_neigh->metrics = circuit->metrics[level - 1]; if (!memcmp (is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) XFREE (MTYPE_ISIS_TLV, is_neigh); else listnode_add (tlv_data.is_neighs, is_neigh); } if (area->newmetric) { if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); if (level == IS_LEVEL_1) memcpy (te_is_neigh->neigh_id, circuit->u.bc.l1_desig_is, ISIS_SYS_ID_LEN + 1); else memcpy (te_is_neigh->neigh_id, circuit->u.bc.l2_desig_is, ISIS_SYS_ID_LEN + 1); if (area->oldmetric) metric = circuit->metrics[level - 1].metric_default; else metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); if (!memcmp (te_is_neigh->neigh_id, zero_id, ISIS_SYS_ID_LEN + 1)) XFREE (MTYPE_ISIS_TLV, te_is_neigh); else listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } break; case CIRCUIT_T_P2P: nei = circuit->u.p2p.neighbor; if (nei && (level & nei->circuit_t)) { if (area->oldmetric) { if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); is_neigh->metrics = circuit->metrics[level - 1]; listnode_add (tlv_data.is_neighs, is_neigh); } if (area->newmetric) { uint32_t metric; if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (te_is_neigh->neigh_id, nei->sysid, ISIS_SYS_ID_LEN); metric = circuit->te_metric[level - 1]; SET_TE_METRIC(te_is_neigh, metric); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } break; case CIRCUIT_T_LOOPBACK: break; default: zlog_warn ("lsp_area_create: unknown circuit type"); } } while (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) { if (lsp->tlv_data.ipv4_int_reachs == NULL) lsp->tlv_data.ipv4_int_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.ipv4_int_reachs, &lsp->tlv_data.ipv4_int_reachs, IPV4_REACH_LEN, area->lsp_frag_threshold, tlv_add_ipv4_reachs); if (tlv_data.ipv4_int_reachs && listcount (tlv_data.ipv4_int_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } /* FIXME: We pass maximum te_ipv4_reachability length to the lsp_tlv_fit() * for now. lsp_tlv_fit() needs to be fixed to deal with variable length * TLVs (sub TLVs!). */ while (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) { if (lsp->tlv_data.te_ipv4_reachs == NULL) lsp->tlv_data.te_ipv4_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_ipv4_reachs, &lsp->tlv_data.te_ipv4_reachs, TE_IPV4_REACH_LEN, area->lsp_frag_threshold, tlv_add_te_ipv4_reachs); if (tlv_data.te_ipv4_reachs && listcount (tlv_data.te_ipv4_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } #ifdef HAVE_IPV6 while (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) { if (lsp->tlv_data.ipv6_reachs == NULL) lsp->tlv_data.ipv6_reachs = list_new (); lsp_tlv_fit (lsp, &tlv_data.ipv6_reachs, &lsp->tlv_data.ipv6_reachs, IPV6_REACH_LEN, area->lsp_frag_threshold, tlv_add_ipv6_reachs); if (tlv_data.ipv6_reachs && listcount (tlv_data.ipv6_reachs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } #endif /* HAVE_IPV6 */ while (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) { if (lsp->tlv_data.is_neighs == NULL) lsp->tlv_data.is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_is_neighs); if (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) { if (lsp->tlv_data.te_is_neighs == NULL) lsp->tlv_data.te_is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_te_is_neighs); if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, level); } lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); free_tlvs (&tlv_data); /* Validate the LSP */ retval = parse_tlvs (area->area_tag, STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN, stream_get_endp (lsp->pdu) - ISIS_FIXED_HDR_LEN - ISIS_LSP_HDR_LEN, &expected, &found, &tlv_data, NULL); assert (retval == ISIS_OK); return; } /* * 7.3.7 and 7.3.9 Generation on non-pseudonode LSPs */ int lsp_generate (struct isis_area *area, int level) { struct isis_lsp *oldlsp, *newlsp; u_int32_t seq_num = 0; u_char lspid[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; memset (&lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (&lspid, isis->sysid, ISIS_SYS_ID_LEN); /* only builds the lsp if the area shares the level */ oldlsp = lsp_search (lspid, area->lspdb[level - 1]); if (oldlsp) { /* FIXME: we should actually initiate a purge */ seq_num = ntohl (oldlsp->lsp_header->seq_num); lsp_search_and_destroy (oldlsp->lsp_header->lsp_id, area->lspdb[level - 1]); } rem_lifetime = lsp_rem_lifetime (area, level); newlsp = lsp_new (lspid, rem_lifetime, seq_num, area->is_type | area->overload_bit, 0, level); newlsp->area = area; newlsp->own_lsp = 1; lsp_insert (newlsp, area->lspdb[level - 1]); /* build_lsp_data (newlsp, area); */ lsp_build (newlsp, area); /* time to calculate our checksum */ lsp_seqnum_update (newlsp); lsp_set_all_srmflags (newlsp); refresh_time = lsp_refresh_time (newlsp, rem_lifetime); THREAD_TIMER_OFF (area->t_lsp_refresh[level - 1]); if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l1_refresh, area, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l2_refresh, area, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Building L%d LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", area->area_tag, level, rawlspid_print (newlsp->lsp_header->lsp_id), ntohl (newlsp->lsp_header->pdu_len), ntohl (newlsp->lsp_header->seq_num), ntohs (newlsp->lsp_header->checksum), ntohs (newlsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } /* * Search own LSPs, update holding time and set SRM */ static int lsp_regenerate (struct isis_area *area, int level) { dict_t *lspdb; struct isis_lsp *lsp, *frag; struct listnode *node; u_char lspid[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; lspdb = area->lspdb[level - 1]; memset (lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy (lspid, isis->sysid, ISIS_SYS_ID_LEN); lsp = lsp_search (lspid, lspdb); if (!lsp) { zlog_err ("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!", area->area_tag, level); return ISIS_ERROR; } lsp_clear_data (lsp); lsp_build (lsp, area); lsp->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit); rem_lifetime = lsp_rem_lifetime (area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_seqnum_update (lsp); lsp->last_generated = time (NULL); lsp_set_all_srmflags (lsp); for (ALL_LIST_ELEMENTS_RO (lsp->lspu.frags, node, frag)) { frag->lsp_header->lsp_bits = lsp_bits_generate (level, area->overload_bit); /* Set the lifetime values of all the fragments to the same value, * so that no fragment expires before the lsp is refreshed. */ frag->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_set_all_srmflags (frag); } refresh_time = lsp_refresh_time (lsp, rem_lifetime); if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l1_refresh, area, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[level - 1], lsp_l2_refresh, area, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Refreshing our L%d LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us refresh %us", area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } /* * Something has changed or periodic refresh -> regenerate LSP */ static int lsp_l1_refresh (struct thread *thread) { struct isis_area *area; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[0] = NULL; area->lsp_regenerate_pending[0] = 0; if ((area->is_type & IS_LEVEL_1) == 0) return ISIS_ERROR; return lsp_regenerate (area, IS_LEVEL_1); } static int lsp_l2_refresh (struct thread *thread) { struct isis_area *area; area = THREAD_ARG (thread); assert (area); area->t_lsp_refresh[1] = NULL; area->lsp_regenerate_pending[1] = 0; if ((area->is_type & IS_LEVEL_2) == 0) return ISIS_ERROR; return lsp_regenerate (area, IS_LEVEL_2); } int lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo) { struct isis_lsp *lsp; u_char id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; struct listnode *cnode; struct isis_circuit *circuit; int lvl; if (area == NULL) return ISIS_ERROR; memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = LSP_FRAGMENT (id) = 0; now = time (NULL); for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!((level & lvl) && (area->is_type & lvl))) continue; if (area->lsp_regenerate_pending[lvl - 1]) continue; lsp = lsp_search (id, area->lspdb[lvl - 1]); if (!lsp) continue; /* * Throttle avoidance */ THREAD_TIMER_OFF (area->t_lsp_refresh[lvl - 1]); diff = now - lsp->last_generated; if (diff < area->lsp_gen_interval[lvl - 1]) { area->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], lsp_l1_refresh, area, area->lsp_gen_interval[lvl - 1] - diff); else if (lvl == IS_LEVEL_2) THREAD_TIMER_ON (master, area->t_lsp_refresh[lvl - 1], lsp_l2_refresh, area, area->lsp_gen_interval[lvl - 1] - diff); } else { lsp_regenerate (area, lvl); } } if (all_pseudo) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) lsp_regenerate_schedule_pseudo (circuit, level); } return ISIS_OK; } /* * Funcs for pseudonode LSPs */ /* * 7.3.8 and 7.3.10 Generation of level 1 and 2 pseudonode LSPs */ static void lsp_build_pseudo (struct isis_lsp *lsp, struct isis_circuit *circuit, int level) { struct isis_adjacency *adj; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; struct es_neigh *es_neigh; struct list *adj_list; struct listnode *node; lsp->level = level; /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); /* * add self to IS neighbours */ if (circuit->area->oldmetric) { if (lsp->tlv_data.is_neighs == NULL) { lsp->tlv_data.is_neighs = list_new (); lsp->tlv_data.is_neighs->del = free_tlv; } is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); } if (circuit->area->newmetric) { if (lsp->tlv_data.te_is_neighs == NULL) { lsp->tlv_data.te_is_neighs = list_new (); lsp->tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); } adj_list = list_new (); isis_adj_build_up_list (circuit->u.bc.adjdb[level - 1], adj_list); for (ALL_LIST_ELEMENTS_RO (adj_list, node, adj)) { if (adj->level & level) { if ((level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L1_IS) || (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_L2_IS && adj->adj_usage == ISIS_ADJ_LEVEL1AND2) || (level == IS_LEVEL_2 && adj->sys_type == ISIS_SYSTYPE_L2_IS)) { /* an IS neighbour -> add it */ if (circuit->area->oldmetric) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.is_neighs, is_neigh); } if (circuit->area->newmetric) { te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.te_is_neighs, te_is_neigh); } } else if (level == IS_LEVEL_1 && adj->sys_type == ISIS_SYSTYPE_ES) { /* an ES neigbour add it, if we are building level 1 LSP */ /* FIXME: the tlv-format is hard to use here */ if (lsp->tlv_data.es_neighs == NULL) { lsp->tlv_data.es_neighs = list_new (); lsp->tlv_data.es_neighs->del = free_tlv; } es_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct es_neigh)); memcpy (&es_neigh->first_es_neigh, adj->sysid, ISIS_SYS_ID_LEN); listnode_add (lsp->tlv_data.es_neighs, es_neigh); } } } list_delete (adj_list); /* Reset endp of stream to overwrite only TLV part of it. */ stream_reset (lsp->pdu); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add the authentication info if it's present */ lsp_auth_add (lsp); if (lsp->tlv_data.is_neighs && listcount (lsp->tlv_data.is_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.is_neighs, lsp->pdu); if (lsp->tlv_data.te_is_neighs && listcount (lsp->tlv_data.te_is_neighs) > 0) tlv_add_te_is_neighs (lsp->tlv_data.te_is_neighs, lsp->pdu); if (lsp->tlv_data.es_neighs && listcount (lsp->tlv_data.es_neighs) > 0) tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); /* Recompute authentication and checksum information */ lsp_auth_update (lsp); fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); return; } int lsp_generate_pseudo (struct isis_circuit *circuit, int level) { dict_t *lspdb = circuit->area->lspdb[level - 1]; struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((circuit->is_type & level) != level || (circuit->state != C_STATE_UP) || (circuit->circ_type != CIRCUIT_T_BROADCAST) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_FRAGMENT (lsp_id) = 0; LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; /* * If for some reason have a pseudo LSP in the db already -> regenerate */ if (lsp_search (lsp_id, lspdb)) return lsp_regenerate_schedule_pseudo (circuit, level); rem_lifetime = lsp_rem_lifetime (circuit->area, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp = lsp_new (lsp_id, rem_lifetime, 1, circuit->area->is_type, 0, level); lsp->area = circuit->area; lsp_build_pseudo (lsp, circuit, level); lsp->own_lsp = 1; lsp_insert (lsp, lspdb); lsp_set_all_srmflags (lsp); refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[level - 1]); circuit->lsp_regenerate_pending[level - 1] = 0; if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l1_refresh_pseudo, circuit, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Building L%d Pseudo LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", circuit->area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } static int lsp_regenerate_pseudo (struct isis_circuit *circuit, int level) { dict_t *lspdb = circuit->area->lspdb[level - 1]; struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int16_t rem_lifetime, refresh_time; if ((circuit->is_type & level) != level || (circuit->state != C_STATE_UP) || (circuit->circ_type != CIRCUIT_T_BROADCAST) || (circuit->u.bc.is_dr[level - 1] == 0)) return ISIS_ERROR; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; LSP_FRAGMENT (lsp_id) = 0; lsp = lsp_search (lsp_id, lspdb); if (!lsp) { zlog_err ("lsp_regenerate_pseudo: no l%d LSP %s found!", level, rawlspid_print (lsp_id)); return ISIS_ERROR; } lsp_clear_data (lsp); lsp_build_pseudo (lsp, circuit, level); /* RFC3787 section 4 SHOULD not set overload bit in pseudo LSPs */ lsp->lsp_header->lsp_bits = lsp_bits_generate (level, 0); rem_lifetime = lsp_rem_lifetime (circuit->area, level); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); lsp_inc_seqnum (lsp, 0); lsp->last_generated = time (NULL); lsp_set_all_srmflags (lsp); refresh_time = lsp_refresh_time (lsp, rem_lifetime); if (level == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l1_refresh_pseudo, circuit, refresh_time); else if (level == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[level - 1], lsp_l2_refresh_pseudo, circuit, refresh_time); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (%s): Refreshing L%d Pseudo LSP %s, len %d, " "seq 0x%08x, cksum 0x%04x, lifetime %us, refresh %us", circuit->area->area_tag, level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->pdu_len), ntohl (lsp->lsp_header->seq_num), ntohs (lsp->lsp_header->checksum), ntohs (lsp->lsp_header->rem_lifetime), refresh_time); } return ISIS_OK; } /* * Something has changed or periodic refresh -> regenerate pseudo LSP */ static int lsp_l1_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); circuit->u.bc.t_refresh_pseudo_lsp[0] = NULL; circuit->lsp_regenerate_pending[0] = 0; if ((circuit->u.bc.is_dr[0] == 0) || (circuit->is_type & IS_LEVEL_1) == 0) { memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, IS_LEVEL_1); return ISIS_ERROR; } return lsp_regenerate_pseudo (circuit, IS_LEVEL_1); } static int lsp_l2_refresh_pseudo (struct thread *thread) { struct isis_circuit *circuit; u_char id[ISIS_SYS_ID_LEN + 2]; circuit = THREAD_ARG (thread); circuit->u.bc.t_refresh_pseudo_lsp[1] = NULL; circuit->lsp_regenerate_pending[1] = 0; if ((circuit->u.bc.is_dr[1] == 0) || (circuit->is_type & IS_LEVEL_2) == 0) { memcpy (id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (id) = circuit->circuit_id; LSP_FRAGMENT (id) = 0; lsp_purge_pseudo (id, circuit, IS_LEVEL_2); return ISIS_ERROR; } return lsp_regenerate_pseudo (circuit, IS_LEVEL_2); } int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; time_t now, diff; int lvl; if (circuit == NULL || circuit->circ_type != CIRCUIT_T_BROADCAST || circuit->state != C_STATE_UP) return ISIS_OK; memcpy (lsp_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lsp_id) = circuit->circuit_id; LSP_FRAGMENT (lsp_id) = 0; now = time (NULL); for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; lvl++) { if (!((level & lvl) && (circuit->is_type & lvl))) continue; if (circuit->u.bc.is_dr[lvl - 1] == 0 || circuit->lsp_regenerate_pending[lvl - 1]) continue; lsp = lsp_search (lsp_id, circuit->area->lspdb[lvl - 1]); if (!lsp) continue; /* * Throttle avoidance */ THREAD_TIMER_OFF (circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1]); diff = now - lsp->last_generated; if (diff < circuit->area->lsp_gen_interval[lvl - 1]) { circuit->lsp_regenerate_pending[lvl - 1] = 1; if (lvl == IS_LEVEL_1) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l1_refresh_pseudo, circuit, circuit->area->lsp_gen_interval[lvl - 1] - diff); else if (lvl == IS_LEVEL_2) THREAD_TIMER_ON (master, circuit->u.bc.t_refresh_pseudo_lsp[lvl - 1], lsp_l2_refresh_pseudo, circuit, circuit->area->lsp_gen_interval[lvl - 1] - diff); } else { lsp_regenerate_pseudo (circuit, lvl); } } return ISIS_OK; } /* * Walk through LSPs for an area * - set remaining lifetime * - set LSPs with SRMflag set for sending */ int lsp_tick (struct thread *thread) { struct isis_area *area; struct isis_circuit *circuit; struct isis_lsp *lsp; struct list *lsp_list; struct listnode *lspnode, *cnode; dnode_t *dnode, *dnode_next; int level; u_int16_t rem_lifetime; lsp_list = list_new (); area = THREAD_ARG (thread); assert (area); area->t_tick = NULL; THREAD_TIMER_ON (master, area->t_tick, lsp_tick, area, 1); /* * Build a list of LSPs with (any) SRMflag set * and removed the ones that have aged out */ for (level = 0; level < ISIS_LEVELS; level++) { if (area->lspdb[level] && dict_count (area->lspdb[level]) > 0) { for (dnode = dict_first (area->lspdb[level]); dnode != NULL; dnode = dnode_next) { dnode_next = dict_next (area->lspdb[level], dnode); lsp = dnode_get (dnode); /* * The lsp rem_lifetime is kept at 0 for MaxAge or * ZeroAgeLifetime depending on explicit purge or * natural age out. So schedule spf only once when * the first time rem_lifetime becomes 0. */ rem_lifetime = ntohs(lsp->lsp_header->rem_lifetime); lsp_set_time (lsp); /* * Schedule may run spf which should be done only after * the lsp rem_lifetime becomes 0 for the first time. * ISO 10589 - 7.3.16.4 first paragraph. */ if (rem_lifetime == 1 && lsp->lsp_header->seq_num != 0) { /* 7.3.16.4 a) set SRM flags on all */ lsp_set_all_srmflags (lsp); /* 7.3.16.4 b) retain only the header FIXME */ /* 7.3.16.4 c) record the time to purge FIXME */ /* run/schedule spf */ /* isis_spf_schedule is called inside lsp_destroy() below; * so it is not needed here. */ /* isis_spf_schedule (lsp->area, lsp->level); */ } if (lsp->age_out == 0) { zlog_debug ("ISIS-Upd (%s): L%u LSP %s seq 0x%08x aged out", area->area_tag, lsp->level, rawlspid_print (lsp->lsp_header->lsp_id), ntohl (lsp->lsp_header->seq_num)); #ifdef TOPOLOGY_GENERATE if (lsp->from_topology) THREAD_TIMER_OFF (lsp->t_lsp_top_ref); #endif /* TOPOLOGY_GENERATE */ lsp_destroy (lsp); lsp = NULL; dict_delete_free (area->lspdb[level], dnode); } else if (flags_any_set (lsp->SRMflags)) listnode_add (lsp_list, lsp); } /* * Send LSPs on circuits indicated by the SRMflags */ if (listcount (lsp_list) > 0) { for (ALL_LIST_ELEMENTS_RO (area->circuit_list, cnode, circuit)) { int diff = time (NULL) - circuit->lsp_queue_last_cleared; if (circuit->lsp_queue == NULL || diff < MIN_LSP_TRANS_INTERVAL) continue; for (ALL_LIST_ELEMENTS_RO (lsp_list, lspnode, lsp)) { if (circuit->upadjcount[lsp->level - 1] && ISIS_CHECK_FLAG (lsp->SRMflags, circuit)) { /* Add the lsp only if it is not already in lsp * queue */ if (! listnode_lookup (circuit->lsp_queue, lsp)) { listnode_add (circuit->lsp_queue, lsp); thread_add_event (master, send_lsp, circuit, 0); } } } } list_delete_all_node (lsp_list); } } } list_delete (lsp_list); return ISIS_OK; } void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level) { struct isis_lsp *lsp; u_int16_t seq_num; u_int8_t lsp_bits; lsp = lsp_search (id, circuit->area->lspdb[level - 1]); if (!lsp) return; /* store old values */ seq_num = lsp->lsp_header->seq_num; lsp_bits = lsp->lsp_header->lsp_bits; /* reset stream */ lsp_clear_data (lsp); stream_reset (lsp->pdu); /* update header */ lsp->lsp_header->pdu_len = htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); memcpy (lsp->lsp_header->lsp_id, id, ISIS_SYS_ID_LEN + 2); lsp->lsp_header->checksum = 0; lsp->lsp_header->seq_num = seq_num; lsp->lsp_header->rem_lifetime = 0; lsp->lsp_header->lsp_bits = lsp_bits; lsp->level = level; lsp->age_out = lsp->area->max_lsp_lifetime[level-1]; stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Add and update the authentication info if its present */ lsp_auth_add (lsp); lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); lsp_auth_update (lsp); fletcher_checksum(STREAM_DATA (lsp->pdu) + 12, ntohs (lsp->lsp_header->pdu_len) - 12, 12); lsp_set_all_srmflags (lsp); return; } /* * Purge own LSP that is received and we don't have. * -> Do as in 7.3.16.4 */ void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, struct isis_area *area) { struct isis_lsp *lsp; /* * We need to create the LSP to be purged */ lsp = XCALLOC (MTYPE_ISIS_LSP, sizeof (struct isis_lsp)); lsp->area = area; lsp->level = ((lsp_hdr->lsp_bits & LSPBIT_IST) == IS_LEVEL_1) ? IS_LEVEL_1 : IS_LEVEL_2; /* FIXME: Should be minimal mtu? */ lsp->pdu = stream_new (1500); lsp->isis_header = (struct isis_fixed_hdr *) STREAM_DATA (lsp->pdu); fill_fixed_hdr (lsp->isis_header, (lsp->level == IS_LEVEL_1) ? L1_LINK_STATE : L2_LINK_STATE); lsp->lsp_header = (struct isis_link_state_hdr *) (STREAM_DATA (lsp->pdu) + ISIS_FIXED_HDR_LEN); memcpy (lsp->lsp_header, lsp_hdr, ISIS_LSP_HDR_LEN); stream_forward_endp (lsp->pdu, ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN); /* * Set the remaining lifetime to 0 */ lsp->lsp_header->rem_lifetime = 0; /* * Add and update the authentication info if its present */ lsp_auth_add (lsp); lsp_auth_update (lsp); /* * Update the PDU length to header plus any authentication TLV. */ lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu)); /* * Put the lsp into LSPdb */ lsp_insert (lsp, area->lspdb[lsp->level - 1]); /* * Send in to whole area */ lsp_set_all_srmflags (lsp); return; } void lsp_set_all_srmflags (struct isis_lsp *lsp) { struct listnode *node; struct isis_circuit *circuit; assert (lsp); ISIS_FLAGS_CLEAR_ALL(lsp->SRMflags); if (lsp->area) { struct list *circuit_list = lsp->area->circuit_list; for (ALL_LIST_ELEMENTS_RO (circuit_list, node, circuit)) { ISIS_SET_FLAG(lsp->SRMflags, circuit); } } } #ifdef TOPOLOGY_GENERATE static int top_lsp_refresh (struct thread *thread) { struct isis_lsp *lsp; u_int16_t rem_lifetime, refresh_time; lsp = THREAD_ARG (thread); assert (lsp); lsp->t_lsp_top_ref = NULL; lsp_seqnum_update (lsp); lsp_set_all_srmflags (lsp); if (isis->debugs & DEBUG_UPDATE_PACKETS) { zlog_debug ("ISIS-Upd (): refreshing Topology L1 %s", rawlspid_print (lsp->lsp_header->lsp_id)); } /* Refresh dynamic hostname in the cache. */ isis_dynhn_insert (lsp->lsp_header->lsp_id, lsp->tlv_data.hostname, IS_LEVEL_1); lsp->lsp_header->lsp_bits = lsp_bits_generate (lsp->level, lsp->area->overload_bit); rem_lifetime = lsp_rem_lifetime (lsp->area, IS_LEVEL_1); lsp->lsp_header->rem_lifetime = htons (rem_lifetime); refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, lsp->area->lsp_refresh[0]); return ISIS_OK; } void generate_topology_lsps (struct isis_area *area) { struct listnode *node; int i, max = 0; struct arc *arc; u_char lspid[ISIS_SYS_ID_LEN + 2]; struct isis_lsp *lsp; u_int16_t rem_lifetime, refresh_time; /* first we find the maximal node */ for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc)) { if (arc->from_node > max) max = arc->from_node; if (arc->to_node > max) max = arc->to_node; } for (i = 1; i < (max + 1); i++) { memcpy (lspid, area->topology_baseis, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (lspid) = 0x00; LSP_FRAGMENT (lspid) = 0x00; lspid[ISIS_SYS_ID_LEN - 1] = (i & 0xFF); lspid[ISIS_SYS_ID_LEN - 2] = ((i >> 8) & 0xFF); rem_lifetime = lsp_rem_lifetime (area, IS_LEVEL_1); lsp = lsp_new (lspid, rem_lifetime, 1, IS_LEVEL_1 | area->overload_bit, 0, 1); if (!lsp) return; lsp->area = area; lsp->from_topology = 1; /* Creating LSP data based on topology info. */ build_topology_lsp_data (lsp, area, i); /* Checksum is also calculated here. */ lsp_seqnum_update (lsp); /* Take care of inserting dynamic hostname into cache. */ isis_dynhn_insert (lspid, lsp->tlv_data.hostname, IS_LEVEL_1); refresh_time = lsp_refresh_time (lsp, rem_lifetime); THREAD_TIMER_ON (master, lsp->t_lsp_top_ref, top_lsp_refresh, lsp, refresh_time); lsp_set_all_srmflags (lsp); lsp_insert (lsp, area->lspdb[0]); } } void remove_topology_lsps (struct isis_area *area) { struct isis_lsp *lsp; dnode_t *dnode, *dnode_next; dnode = dict_first (area->lspdb[0]); while (dnode != NULL) { dnode_next = dict_next (area->lspdb[0], dnode); lsp = dnode_get (dnode); if (lsp->from_topology) { THREAD_TIMER_OFF (lsp->t_lsp_top_ref); lsp_destroy (lsp); dict_delete (area->lspdb[0], dnode); } dnode = dnode_next; } } void build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, int lsp_top_num) { struct listnode *node; struct arc *arc; struct is_neigh *is_neigh; struct te_is_neigh *te_is_neigh; char buff[200]; struct tlvs tlv_data; struct isis_lsp *lsp0 = lsp; /* Add area addresses. FIXME: Is it needed at all? */ if (lsp->tlv_data.area_addrs == NULL) lsp->tlv_data.area_addrs = list_new (); list_add_list (lsp->tlv_data.area_addrs, area->area_addrs); if (lsp->tlv_data.nlpids == NULL) lsp->tlv_data.nlpids = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct nlpids)); lsp->tlv_data.nlpids->count = 1; lsp->tlv_data.nlpids->nlpids[0] = NLPID_IP; if (area->dynhostname) { lsp->tlv_data.hostname = XMALLOC (MTYPE_ISIS_TLV, sizeof (struct hostname)); memset (buff, 0x00, 200); sprintf (buff, "%s%d", area->topology_basedynh ? area->topology_basedynh : "feedme", lsp_top_num); memcpy (lsp->tlv_data.hostname->name, buff, strlen (buff)); lsp->tlv_data.hostname->namelen = strlen (buff); } if (lsp->tlv_data.nlpids) tlv_add_nlpid (lsp->tlv_data.nlpids, lsp->pdu); if (lsp->tlv_data.hostname) tlv_add_dynamic_hostname (lsp->tlv_data.hostname, lsp->pdu); if (lsp->tlv_data.area_addrs && listcount (lsp->tlv_data.area_addrs) > 0) tlv_add_area_addrs (lsp->tlv_data.area_addrs, lsp->pdu); memset (&tlv_data, 0, sizeof (struct tlvs)); if (tlv_data.is_neighs == NULL) { tlv_data.is_neighs = list_new (); tlv_data.is_neighs->del = free_tlv; } /* Add reachability for this IS for simulated 1. */ if (lsp_top_num == 1) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, isis->sysid, ISIS_SYS_ID_LEN); LSP_PSEUDO_ID (is_neigh->neigh_id) = 0x00; /* Metric MUST NOT be 0, unless it's not alias TLV. */ is_neigh->metrics.metric_default = 0x01; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } /* Add IS reachabilities. */ for (ALL_LIST_ELEMENTS_RO (area->topology, node, arc)) { int to_lsp = 0; if ((lsp_top_num != arc->from_node) && (lsp_top_num != arc->to_node)) continue; if (lsp_top_num == arc->from_node) to_lsp = arc->to_node; else to_lsp = arc->from_node; if (area->oldmetric) { is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct is_neigh)); memcpy (&is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF); is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF); is_neigh->metrics.metric_default = arc->distance; is_neigh->metrics.metric_delay = METRICS_UNSUPPORTED; is_neigh->metrics.metric_expense = METRICS_UNSUPPORTED; is_neigh->metrics.metric_error = METRICS_UNSUPPORTED; listnode_add (tlv_data.is_neighs, is_neigh); } if (area->newmetric) { if (tlv_data.te_is_neighs == NULL) { tlv_data.te_is_neighs = list_new (); tlv_data.te_is_neighs->del = free_tlv; } te_is_neigh = XCALLOC (MTYPE_ISIS_TLV, sizeof (struct te_is_neigh)); memcpy (&te_is_neigh->neigh_id, area->topology_baseis, ISIS_SYS_ID_LEN); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 1] = (to_lsp & 0xFF); te_is_neigh->neigh_id[ISIS_SYS_ID_LEN - 2] = ((to_lsp >> 8) & 0xFF); SET_TE_METRIC(te_is_neigh, arc->distance); listnode_add (tlv_data.te_is_neighs, te_is_neigh); } } while (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) { if (lsp->tlv_data.is_neighs == NULL) lsp->tlv_data.is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.is_neighs, &lsp->tlv_data.is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_is_neighs); if (tlv_data.is_neighs && listcount (tlv_data.is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, IS_LEVEL_1); } while (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) { if (lsp->tlv_data.te_is_neighs == NULL) lsp->tlv_data.te_is_neighs = list_new (); lsp_tlv_fit (lsp, &tlv_data.te_is_neighs, &lsp->tlv_data.te_is_neighs, IS_NEIGHBOURS_LEN, area->lsp_frag_threshold, tlv_add_te_is_neighs); if (tlv_data.te_is_neighs && listcount (tlv_data.te_is_neighs)) lsp = lsp_next_frag (LSP_FRAGMENT (lsp->lsp_header->lsp_id) + 1, lsp0, area, IS_LEVEL_1); } free_tlvs (&tlv_data); return; } #endif /* TOPOLOGY_GENERATE */ quagga-0.99.24.1/isisd/isis_adjacency.c0000644000175000017500000003417712476520570014477 00000000000000/* * IS-IS Rout(e)ing protocol - isis_adjacency.c * handling of IS-IS adjacencies * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "hash.h" #include "vty.h" #include "linklist.h" #include "thread.h" #include "if.h" #include "stream.h" #include "isisd/dict.h" #include "isisd/include-netbsd/iso.h" #include "isisd/isis_constants.h" #include "isisd/isis_common.h" #include "isisd/isis_flags.h" #include "isisd/isisd.h" #include "isisd/isis_circuit.h" #include "isisd/isis_adjacency.h" #include "isisd/isis_misc.h" #include "isisd/isis_dr.h" #include "isisd/isis_dynhn.h" #include "isisd/isis_pdu.h" #include "isisd/isis_tlv.h" #include "isisd/isis_lsp.h" #include "isisd/isis_spf.h" #include "isisd/isis_events.h" extern struct isis *isis; static struct isis_adjacency * adj_alloc (u_char * id) { struct isis_adjacency *adj; adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency)); memcpy (adj->sysid, id, ISIS_SYS_ID_LEN); return adj; } struct isis_adjacency * isis_new_adj (u_char * id, u_char * snpa, int level, struct isis_circuit *circuit) { struct isis_adjacency *adj; int i; adj = adj_alloc (id); /* P2P kludge */ if (adj == NULL) { zlog_err ("Out of memory!"); return NULL; } if (snpa) { memcpy (adj->snpa, snpa, ETH_ALEN); } else { memset (adj->snpa, ' ', ETH_ALEN); } adj->circuit = circuit; adj->level = level; adj->flaps = 0; adj->last_flap = time (NULL); if (circuit->circ_type == CIRCUIT_T_BROADCAST) { listnode_add (circuit->u.bc.adjdb[level - 1], adj); adj->dischanges[level - 1] = 0; for (i = 0; i < DIS_RECORDS; i++) /* clear N DIS state change records */ { adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis = ISIS_UNKNOWN_DIS; adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change = time (NULL); } } return adj; } struct isis_adjacency * isis_adj_lookup (u_char * sysid, struct list *adjdb) { struct isis_adjacency *adj; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0) return adj; return NULL; } struct isis_adjacency * isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb) { struct listnode *node; struct isis_adjacency *adj; for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0) return adj; return NULL; } void isis_delete_adj (void *arg) { struct isis_adjacency *adj = arg; if (!adj) return; THREAD_TIMER_OFF (adj->t_expire); /* remove from SPF trees */ spftree_area_adj_del (adj->circuit->area, adj); if (adj->area_addrs) list_delete (adj->area_addrs); if (adj->ipv4_addrs) list_delete (adj->ipv4_addrs); #ifdef HAVE_IPV6 if (adj->ipv6_addrs) list_delete (adj->ipv6_addrs); #endif XFREE (MTYPE_ISIS_ADJACENCY, adj); return; } static const char * adj_state2string (int state) { switch (state) { case ISIS_ADJ_INITIALIZING: return "Initializing"; case ISIS_ADJ_UP: return "Up"; case ISIS_ADJ_DOWN: return "Down"; default: return "Unknown"; } return NULL; /* not reached */ } void isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state new_state, const char *reason) { int old_state; int level; struct isis_circuit *circuit; old_state = adj->adj_state; adj->adj_state = new_state; circuit = adj->circuit; if (isis->debugs & DEBUG_ADJ_PACKETS) { zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s", circuit->area->area_tag, old_state, new_state, reason ? reason : "unspecified"); } if (circuit->area->log_adj_changes) { const char *adj_name; struct isis_dynhn *dyn; dyn = dynhn_find_by_id (adj->sysid); if (dyn) adj_name = (const char *)dyn->name.name; else adj_name = adj->sysid ? sysid_print (adj->sysid) : "unknown"; zlog_info ("%%ADJCHANGE: Adjacency to %s (%s) changed from %s to %s, %s", adj_name, adj->circuit->interface->name, adj_state2string (old_state), adj_state2string (new_state), reason ? reason : "unspecified"); } if (circuit->circ_type == CIRCUIT_T_BROADCAST) { for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; isis_event_adjacency_state_change (adj, new_state); /* update counter & timers for debugging purposes */ adj->last_flap = time (NULL); adj->flaps++; } else if (new_state == ISIS_ADJ_DOWN) { listnode_delete (circuit->u.bc.adjdb[level - 1], adj); circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) { /* Clean lsp_queue when no adj is up. */ if (circuit->lsp_queue) list_delete_all_node (circuit->lsp_queue); } isis_event_adjacency_state_change (adj, new_state); isis_delete_adj (adj); } if (circuit->u.bc.lan_neighs[level - 1]) { list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]); isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1], circuit->u.bc.lan_neighs[level - 1]); } /* On adjacency state change send new pseudo LSP if we are the DR */ if (circuit->u.bc.is_dr[level - 1]) lsp_regenerate_schedule_pseudo (circuit, level); } } else if (circuit->circ_type == CIRCUIT_T_P2P) { for (level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) { if ((adj->level & level) == 0) continue; if (new_state == ISIS_ADJ_UP) { circuit->upadjcount[level - 1]++; isis_event_adjacency_state_change (adj, new_state); if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN) send_hello (circuit, level); /* update counter & timers for debugging purposes */ adj->last_flap = time (NULL); adj->flaps++; /* 7.3.17 - going up on P2P -> send CSNP */ /* FIXME: yup, I know its wrong... but i will do it! (for now) */ send_csnp (circuit, level); } else if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) adj->circuit->u.p2p.neighbor = NULL; circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) { /* Clean lsp_queue when no adj is up. */ if (circuit->lsp_queue) list_delete_all_node (circuit->lsp_queue); } isis_event_adjacency_state_change (adj, new_state); isis_delete_adj (adj); } } } return; } void isis_adj_print (struct isis_adjacency *adj) { struct isis_dynhn *dyn; struct listnode *node; struct in_addr *ipv4_addr; #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; u_char ip6[INET6_ADDRSTRLEN]; #endif /* HAVE_IPV6 */ if (!adj) return; dyn = dynhn_find_by_id (adj->sysid); if (dyn) zlog_debug ("%s", dyn->name.name); zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d", adj->sysid ? sysid_print (adj->sysid) : "unknown", snpa_print (adj->snpa), adj->level, adj->hold_time); if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { zlog_debug ("IPv4 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr)) zlog_debug ("%s", inet_ntoa (*ipv4_addr)); } #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { zlog_debug ("IPv6 Address(es):"); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); zlog_debug ("%s", ip6); } } #endif /* HAVE_IPV6 */ zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids)); return; } int isis_adj_expire (struct thread *thread) { struct isis_adjacency *adj; /* * Get the adjacency */ adj = THREAD_ARG (thread); assert (adj); adj->t_expire = NULL; /* trigger the adj expire event */ isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired"); return 0; } /* * show isis neighbor [detail] */ void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail) { #ifdef HAVE_IPV6 struct in6_addr *ipv6_addr; u_char ip6[INET6_ADDRSTRLEN]; #endif /* HAVE_IPV6 */ struct in_addr *ip_addr; time_t now; struct isis_dynhn *dyn; int level; struct listnode *node; dyn = dynhn_find_by_id (adj->sysid); if (dyn) vty_out (vty, " %-20s", dyn->name.name); else if (adj->sysid) { vty_out (vty, " %-20s", sysid_print (adj->sysid)); } else { vty_out (vty, " unknown "); } if (detail == ISIS_UI_LEVEL_BRIEF) { if (adj->circuit) vty_out (vty, "%-12s", adj->circuit->interface->name); else vty_out (vty, "NULL circuit!"); vty_out (vty, "%-3u", adj->level); /* level */ vty_out (vty, "%-13s", adj_state2string (adj->adj_state)); now = time (NULL); if (adj->last_upd) vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now); else vty_out (vty, "- "); vty_out (vty, "%-10s", snpa_print (adj->snpa)); vty_out (vty, "%s", VTY_NEWLINE); } if (detail == ISIS_UI_LEVEL_DETAIL) { level = adj->level; vty_out (vty, "%s", VTY_NEWLINE); if (adj->circuit) vty_out (vty, " Interface: %s", adj->circuit->interface->name); else vty_out (vty, " Interface: NULL circuit"); vty_out (vty, ", Level: %u", adj->level); /* level */ vty_out (vty, ", State: %s", adj_state2string (adj->adj_state)); now = time (NULL); if (adj->last_upd) vty_out (vty, ", Expires in %s", time2string (adj->last_upd + adj->hold_time - now)); else vty_out (vty, ", Expires in %s", time2string (adj->hold_time)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Adjacency flaps: %u", adj->flaps); vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Circuit type: %s", circuit_t2string (adj->circuit_t)); vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids)); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " SNPA: %s", snpa_print (adj->snpa)); if (adj->circuit && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) { dyn = dynhn_find_by_id (adj->lanid); if (dyn) vty_out (vty, ", LAN id: %s.%02x", dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]); else vty_out (vty, ", LAN id: %s.%02x", sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " LAN Priority: %u", adj->prio[adj->level - 1]); vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago", isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1]. dis), adj->dischanges[level - 1], time2string (now - (adj->dis_record[ISIS_LEVELS + level - 1]. last_dis_change))); } vty_out (vty, "%s", VTY_NEWLINE); if (adj->area_addrs && listcount (adj->area_addrs) > 0) { struct area_addr *area_addr; vty_out (vty, " Area Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->area_addrs, node, area_addr)) vty_out (vty, " %s%s", isonet_print (area_addr->area_addr, area_addr->addr_len), VTY_NEWLINE); } if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0) { vty_out (vty, " IPv4 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr)) vty_out (vty, " %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE); } #ifdef HAVE_IPV6 if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0) { vty_out (vty, " IPv6 Address(es):%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr)) { inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN); vty_out (vty, " %s%s", ip6, VTY_NEWLINE); } } #endif /* HAVE_IPV6 */ vty_out (vty, "%s", VTY_NEWLINE); } return; } void isis_adj_build_neigh_list (struct list *adjdb, struct list *list) { struct isis_adjacency *adj; struct listnode *node; if (!list) { zlog_warn ("isis_adj_build_neigh_list(): NULL list"); return; } for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) { if (!adj) { zlog_warn ("isis_adj_build_neigh_list(): NULL adj"); return; } if ((adj->adj_state == ISIS_ADJ_UP || adj->adj_state == ISIS_ADJ_INITIALIZING)) listnode_add (list, adj->snpa); } return; } void isis_adj_build_up_list (struct list *adjdb, struct list *list) { struct isis_adjacency *adj; struct listnode *node; if (!list) { zlog_warn ("isis_adj_build_up_list(): NULL list"); return; } for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj)) { if (!adj) { zlog_warn ("isis_adj_build_up_list(): NULL adj"); return; } if (adj->adj_state == ISIS_ADJ_UP) listnode_add (list, adj); } return; } quagga-0.99.24.1/isisd/README0000644000175000017500000000006212476520570012225 00000000000000Constraints o Maximum number of interfaces 255 quagga-0.99.24.1/isisd/AUTHORS0000644000175000017500000000022712476520570012420 00000000000000Sampo Saaristo Ofer Wald Hannes Gredler Subbaiah Venkata quagga-0.99.24.1/isisd/isis_route.h0000644000175000017500000000442012476520570013705 00000000000000/* * IS-IS Rout(e)ing protocol - isis_route.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * based on ../ospf6d/ospf6_route.[ch] * by Yasuhiro Ohara * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_ROUTE_H #define _ZEBRA_ISIS_ROUTE_H #ifdef HAVE_IPV6 struct isis_nexthop6 { unsigned int ifindex; struct in6_addr ip6; struct in6_addr router_address6; unsigned int lock; }; #endif /* HAVE_IPV6 */ struct isis_nexthop { unsigned int ifindex; struct in_addr ip; struct in_addr router_address; unsigned int lock; }; struct isis_route_info { #define ISIS_ROUTE_FLAG_ACTIVE 0x01 /* active route for the prefix */ #define ISIS_ROUTE_FLAG_ZEBRA_SYNCED 0x02 /* set when route synced to zebra */ #define ISIS_ROUTE_FLAG_ZEBRA_RESYNC 0x04 /* set when route needs to sync */ u_char flag; u_int32_t cost; u_int32_t depth; struct list *nexthops; #ifdef HAVE_IPV6 struct list *nexthops6; #endif /* HAVE_IPV6 */ }; struct isis_route_info *isis_route_create (struct prefix *prefix, u_int32_t cost, u_int32_t depth, struct list *adjacencies, struct isis_area *area, int level); void isis_route_validate (struct isis_area *area); void isis_route_invalidate_table (struct isis_area *area, struct route_table *table); void isis_route_invalidate (struct isis_area *area); #endif /* _ZEBRA_ISIS_ROUTE_H */ quagga-0.99.24.1/isisd/isis_spf.h0000644000175000017500000000557712476520570013355 00000000000000/* * IS-IS Rout(e)ing protocol - isis_spf.h * IS-IS Shortest Path First algorithm * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_SPF_H #define _ZEBRA_ISIS_SPF_H enum vertextype { VTYPE_PSEUDO_IS = 1, VTYPE_PSEUDO_TE_IS, VTYPE_NONPSEUDO_IS, VTYPE_NONPSEUDO_TE_IS, VTYPE_ES, VTYPE_IPREACH_INTERNAL, VTYPE_IPREACH_EXTERNAL, VTYPE_IPREACH_TE #ifdef HAVE_IPV6 , VTYPE_IP6REACH_INTERNAL, VTYPE_IP6REACH_EXTERNAL #endif /* HAVE_IPV6 */ }; /* * Triple */ struct isis_vertex { enum vertextype type; union { u_char id[ISIS_SYS_ID_LEN + 1]; struct prefix prefix; } N; u_int32_t d_N; /* d(N) Distance from this IS */ u_int16_t depth; /* The depth in the imaginary tree */ struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ struct list *parents; /* list of parents for ECMP */ struct list *children; /* list of children used for tree dump */ }; struct isis_spftree { struct thread *t_spf; /* spf threads */ struct list *paths; /* the SPT */ struct list *tents; /* TENT */ struct isis_area *area; /* back pointer to area */ int pending; /* already scheduled */ unsigned int runcount; /* number of runs since uptime */ time_t last_run_timestamp; /* last run timestamp for scheduling */ time_t last_run_duration; /* last run duration in msec */ }; struct isis_spftree * isis_spftree_new (struct isis_area *area); void isis_spftree_del (struct isis_spftree *spftree); void isis_spftree_adj_del (struct isis_spftree *spftree, struct isis_adjacency *adj); void spftree_area_init (struct isis_area *area); void spftree_area_del (struct isis_area *area); void spftree_area_adj_del (struct isis_area *area, struct isis_adjacency *adj); int isis_spf_schedule (struct isis_area *area, int level); void isis_spf_cmds_init (void); #ifdef HAVE_IPV6 int isis_spf_schedule6 (struct isis_area *area, int level); #endif #endif /* _ZEBRA_ISIS_SPF_H */ quagga-0.99.24.1/isisd/isis_events.h0000644000175000017500000000341712476520570014060 00000000000000/* * IS-IS Rout(e)ing protocol - isis_events.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_EVENTS_H #define _ZEBRA_ISIS_EVENTS_H /* * Events related to area */ void isis_event_system_type_change (struct isis_area *area, int newtype); /* * Events related to circuit */ void isis_event_circuit_state_change (struct isis_circuit *circuit, struct isis_area *area, int state); void isis_event_circuit_type_change (struct isis_circuit *circuit, int newtype); /* * Events related to adjacencies */ void isis_event_adjacency_state_change (struct isis_adjacency *adj, int newstate); int isis_event_dis_status_change (struct thread *thread); /* * Error events */ #define AUTH_ERROR_TYPE_LSP 3 #define AUTH_ERROR_TYPE_SNP 2 #define AUTH_ERROR_TYPE_HELLO 1 void isis_event_auth_failure (char *area_tag, const char *error_string, u_char *sysid); #endif /* _ZEBRA_ISIS_EVENTS_H */ quagga-0.99.24.1/isisd/isis_csm.h0000644000175000017500000000301712476520570013332 00000000000000/* * IS-IS Rout(e)ing protocol - isis_csm.h * IS-IS circuit state machine * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_CSM_H #define _ZEBRA_ISIS_CSM_H /* * Circuit states */ #define C_STATE_NA 0 #define C_STATE_INIT 1 /* Connected to interface */ #define C_STATE_CONF 2 /* Configured for ISIS */ #define C_STATE_UP 3 /* CONN | CONF */ /* * Circuit events */ #define ISIS_ENABLE 1 #define IF_UP_FROM_Z 2 #define ISIS_DISABLE 3 #define IF_DOWN_FROM_Z 4 struct isis_circuit *isis_csm_state_change (int event, struct isis_circuit *circuit, void *arg); #endif /* _ZEBRA_ISIS_CSM_H */ quagga-0.99.24.1/isisd/iso_checksum.h0000644000175000017500000000222412476520570014174 00000000000000/* * IS-IS Rout(e)ing protocol - iso_checksum.c * ISO checksum related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISO_CSUM_H #define _ZEBRA_ISO_CSUM_H int iso_csum_verify (u_char * buffer, int len, uint16_t * csum); #endif /* _ZEBRA_ISO_CSUM_H */ quagga-0.99.24.1/isisd/isis_common.h0000644000175000017500000000332012476520570014035 00000000000000/* * IS-IS Rout(e)ing protocol - isis_common.h * some common data structures * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISIS_COMMON_H #define ISIS_COMMON_H /* * Area Address */ struct area_addr { u_char addr_len; u_char area_addr[20]; }; struct isis_passwd { u_char len; #define ISIS_PASSWD_TYPE_UNUSED 0 #define ISIS_PASSWD_TYPE_CLEARTXT 1 #define ISIS_PASSWD_TYPE_HMAC_MD5 54 #define ISIS_PASSWD_TYPE_PRIVATE 255 u_char type; /* Authenticate SNPs? */ #define SNP_AUTH_SEND 0x01 #define SNP_AUTH_RECV 0x02 u_char snp_auth; u_char passwd[255]; }; /* * (Dynamic) Hostname * one struct for cache list * one struct for LSP TLV */ struct hostname { u_char namelen; u_char name[255]; }; /* * Supported Protocol IDs */ struct nlpids { u_char count; u_char nlpids[4]; /* FIXME: enough ? */ }; #endif quagga-0.99.24.1/isisd/isis_dynhn.h0000644000175000017500000000274412476520570013676 00000000000000/* * IS-IS Rout(e)ing protocol - isis_dynhn.h * Dynamic hostname cache * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_DYNHN_H #define _ZEBRA_ISIS_DYNHN_H struct isis_dynhn { u_char id[ISIS_SYS_ID_LEN]; struct hostname name; time_t refresh; int level; }; void dyn_cache_init (void); void isis_dynhn_insert (u_char * id, struct hostname *hostname, int level); void isis_dynhn_remove (u_char * id); struct isis_dynhn *dynhn_find_by_id (u_char * id); struct isis_dynhn *dynhn_find_by_name (const char *hostname); void dynhn_print_all (struct vty *vty); #endif /* _ZEBRA_ISIS_DYNHN_H */ quagga-0.99.24.1/isisd/isis_flags.h0000644000175000017500000000413612476520570013647 00000000000000/* * IS-IS Rout(e)ing protocol - isis_flags.h * Routines for manipulation of SSN and SRM flags * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_FLAGS_H #define _ZEBRA_ISIS_FLAGS_H /* The grand plan is to support 1024 circuits so we have 32*32 bit flags * the support will be achived using the newest drafts */ #define ISIS_MAX_CIRCUITS 32 /* = 1024 */ /* * Flags structure for SSN and SRM flags */ struct flags { int maxindex; struct list *free_idcs; }; void flags_initialize (struct flags *flags); long int flags_get_index (struct flags *flags); void flags_free_index (struct flags *flags, long int index); int flags_any_set (u_int32_t * flags); #define ISIS_SET_FLAG(F,C) \ { \ F[C->idx>>5] |= (1<<(C->idx & 0x1F)); \ } #define ISIS_CLEAR_FLAG(F,C) \ { \ F[C->idx>>5] &= ~(1<<(C->idx & 0x1F)); \ } #define ISIS_CHECK_FLAG(F, C) (F[(C)->idx>>5] & (1<<(C->idx & 0x1F))) /* sets all u_32int_t flags to 1 */ #define ISIS_FLAGS_SET_ALL(FLAGS) \ { \ memset(FLAGS,0xFF,ISIS_MAX_CIRCUITS*4); \ } #define ISIS_FLAGS_CLEAR_ALL(FLAGS) \ { \ memset(FLAGS,0x00,ISIS_MAX_CIRCUITS*4); \ } #endif /* _ZEBRA_ISIS_FLAGS_H */ quagga-0.99.24.1/isisd/isis_dr.h0000644000175000017500000000277112476520570013163 00000000000000/* * IS-IS Rout(e)ing protocol - isis_dr.h * IS-IS designated router related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_DR_H #define _ZEBRA_ISIS_DR_H int isis_run_dr_l1 (struct thread *thread); int isis_run_dr_l2 (struct thread *thread); int isis_dr_elect (struct isis_circuit *circuit, int level); int isis_dr_resign (struct isis_circuit *circuit, int level); int isis_dr_commence (struct isis_circuit *circuit, int level); const char *isis_disflag2string (int disflag); enum isis_dis_state { ISIS_IS_NOT_DIS, ISIS_IS_DIS, ISIS_WAS_DIS, ISIS_UNKNOWN_DIS }; #endif /* _ZEBRA_ISIS_DR_H */ quagga-0.99.24.1/isisd/isis_zebra.h0000644000175000017500000000235512476520570013657 00000000000000/* * IS-IS Rout(e)ing protocol - isis_zebra.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_ZEBRA_H #define _ZEBRA_ISIS_ZEBRA_H extern struct zclient *zclient; void isis_zebra_init (void); void isis_zebra_route_update (struct prefix *prefix, struct isis_route_info *route_info); int isis_distribute_list_update (int routetype); #endif /* _ZEBRA_ISIS_ZEBRA_H */ quagga-0.99.24.1/isisd/isis_network.h0000644000175000017500000000265612476520570014251 00000000000000/* * IS-IS Rout(e)ing protocol - isis_network.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_NETWORK_H #define _ZEBRA_ISIS_NETWORK_H extern u_char ALL_L1_ISYSTEMS[]; extern u_char ALL_L2_ISYSTEMS[]; int isis_sock_init (struct isis_circuit *circuit); int isis_recv_pdu_bcast (struct isis_circuit *circuit, u_char * ssnpa); int isis_recv_pdu_p2p (struct isis_circuit *circuit, u_char * ssnpa); int isis_send_pdu_bcast (struct isis_circuit *circuit, int level); int isis_send_pdu_p2p (struct isis_circuit *circuit, int level); #endif /* _ZEBRA_ISIS_NETWORK_H */ quagga-0.99.24.1/isisd/isis_misc.h0000644000175000017500000000503712476520570013507 00000000000000/* * IS-IS Rout(e)ing protocol - isis_misc.h * Miscellanous routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_MISC_H #define _ZEBRA_ISIS_MISC_H int string2circuit_t (const char *); const char *circuit_t2string (int); const char *circuit_state2string (int state); const char *circuit_type2string (int type); const char *syst2string (int); struct in_addr newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen); /* * Converting input to memory stored format * return value of 0 indicates wrong input */ int dotformat2buff (u_char *, const char *); int sysid2buff (u_char *, const char *); /* * Printing functions */ const char *isonet_print (u_char *, int len); const char *sysid_print (u_char *); const char *snpa_print (u_char *); const char *rawlspid_print (u_char *); const char *time2string (u_int32_t); /* typedef struct nlpids nlpids; */ char *nlpid2string (struct nlpids *); const char *print_sys_hostname (u_char *sysid); void zlog_dump_data (void *data, int len); /* * misc functions */ int speaks (struct nlpids *nlpids, int family); unsigned long isis_jitter (unsigned long timer, unsigned long jitter); const char *unix_hostname (void); /* * macros */ #define GETSYSID(A) (A->area_addr + (A->addr_len - \ (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN))) /* used for calculating nice string representation instead of plain seconds */ #define SECS_PER_MINUTE 60 #define SECS_PER_HOUR 3600 #define SECS_PER_DAY 86400 #define SECS_PER_WEEK 604800 #define SECS_PER_MONTH 2628000 #define SECS_PER_YEAR 31536000 enum { ISIS_UI_LEVEL_BRIEF, ISIS_UI_LEVEL_DETAIL, ISIS_UI_LEVEL_EXTENSIVE, }; #endif quagga-0.99.24.1/isisd/isis_circuit.h0000644000175000017500000001426612476520570014222 00000000000000/* * IS-IS Rout(e)ing protocol - isis_circuit.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISIS_CIRCUIT_H #define ISIS_CIRCUIT_H #define CIRCUIT_MAX 255 struct password { struct password *next; int len; u_char *pass; }; struct metric { u_char metric_default; u_char metric_error; u_char metric_expense; u_char metric_delay; }; struct isis_bcast_info { u_char snpa[ETH_ALEN]; /* SNPA of this circuit */ char run_dr_elect[2]; /* Should we run dr election ? */ struct thread *t_run_dr[2]; /* DR election thread */ struct thread *t_send_lan_hello[2]; /* send LAN IIHs in this thread */ struct list *adjdb[2]; /* adjacency dbs */ struct list *lan_neighs[2]; /* list of lx neigh snpa */ char is_dr[2]; /* Are we level x DR ? */ u_char l1_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-1 DR */ u_char l2_desig_is[ISIS_SYS_ID_LEN + 1]; /* level-2 DR */ struct thread *t_refresh_pseudo_lsp[2]; /* refresh pseudo-node LSPs */ }; struct isis_p2p_info { struct isis_adjacency *neighbor; struct thread *t_send_p2p_hello; /* send P2P IIHs in this thread */ }; struct isis_circuit { int state; u_char circuit_id; /* l1/l2 p2p/bcast CircuitID */ struct isis_area *area; /* back pointer to the area */ struct interface *interface; /* interface info from z */ int fd; /* IS-IS l1/2 socket */ int sap_length; /* SAP length for DLPI */ struct nlpids nlpids; /* * Threads */ struct thread *t_read; struct thread *t_send_csnp[2]; struct thread *t_send_psnp[2]; struct list *lsp_queue; /* LSPs to be txed (both levels) */ time_t lsp_queue_last_cleared;/* timestamp used to enforce transmit interval; * for scalability, use one timestamp per * circuit, instead of one per lsp per circuit */ /* there is no real point in two streams, just for programming kicker */ int (*rx) (struct isis_circuit * circuit, u_char * ssnpa); struct stream *rcv_stream; /* Stream for receiving */ int (*tx) (struct isis_circuit * circuit, int level); struct stream *snd_stream; /* Stream for sending */ int idx; /* idx in S[RM|SN] flags */ #define CIRCUIT_T_UNKNOWN 0 #define CIRCUIT_T_BROADCAST 1 #define CIRCUIT_T_P2P 2 #define CIRCUIT_T_LOOPBACK 3 int circ_type; /* type of the physical interface */ int circ_type_config; /* config type of the physical interface */ union { struct isis_bcast_info bc; struct isis_p2p_info p2p; } u; u_char priority[2]; /* l1/2 IS configured priority */ int pad_hellos; /* add padding to Hello PDUs ? */ char ext_domain; /* externalDomain (boolean) */ int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables */ struct isis_passwd passwd; /* Circuit rx/tx password */ int is_type; /* circuit is type == level of circuit * diffrenciated from circuit type (media) */ u_int32_t hello_interval[2]; /* l1HelloInterval in msecs */ u_int16_t hello_multiplier[2]; /* l1HelloMultiplier */ u_int16_t csnp_interval[2]; /* level-1 csnp-interval in seconds */ u_int16_t psnp_interval[2]; /* level-1 psnp-interval in seconds */ struct metric metrics[2]; /* l1XxxMetric */ u_int32_t te_metric[2]; int ip_router; /* Route IP ? */ int is_passive; /* Is Passive ? */ struct list *ip_addrs; /* our IP addresses */ #ifdef HAVE_IPV6 int ipv6_router; /* Route IPv6 ? */ struct list *ipv6_link; /* our link local IPv6 addresses */ struct list *ipv6_non_link; /* our non-link local IPv6 addresses */ #endif /* HAVE_IPV6 */ u_int16_t upadjcount[2]; #define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01 u_char flags; /* * Counters as in 10589--11.2.5.9 */ u_int32_t adj_state_changes; /* changesInAdjacencyState */ u_int32_t init_failures; /* intialisationFailures */ u_int32_t ctrl_pdus_rxed; /* controlPDUsReceived */ u_int32_t ctrl_pdus_txed; /* controlPDUsSent */ u_int32_t desig_changes[2]; /* lanLxDesignatedIntermediateSystemChanges */ u_int32_t rej_adjacencies; /* rejectedAdjacencies */ }; void isis_circuit_init (void); struct isis_circuit *isis_circuit_new (void); void isis_circuit_del (struct isis_circuit *circuit); struct isis_circuit *circuit_lookup_by_ifp (struct interface *ifp, struct list *list); struct isis_circuit *circuit_scan_by_ifp (struct interface *ifp); void isis_circuit_configure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_deconfigure (struct isis_circuit *circuit, struct isis_area *area); void isis_circuit_if_add (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_del (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_bind (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_if_unbind (struct isis_circuit *circuit, struct interface *ifp); void isis_circuit_add_addr (struct isis_circuit *circuit, struct connected *conn); void isis_circuit_del_addr (struct isis_circuit *circuit, struct connected *conn); int isis_circuit_up (struct isis_circuit *circuit); void isis_circuit_down (struct isis_circuit *); void circuit_update_nlpids (struct isis_circuit *circuit); void isis_circuit_print_vty (struct isis_circuit *circuit, struct vty *vty, char detail); #endif /* _ZEBRA_ISIS_CIRCUIT_H */ quagga-0.99.24.1/isisd/dict.h0000644000175000017500000000773712476520570012461 00000000000000/* * Dictionary Abstract Data Type * Copyright (C) 1997 Kaz Kylheku * * Free Software License: * * All rights are reserved by the author, with the following exceptions: * Permission is granted to freely reproduce and distribute this software, * possibly in exchange for a fee, provided that this copyright notice appears * intact. Permission is also granted to adapt this software to produce * derivative works, as long as the modified versions carry this copyright * notice and additional notices stating that the work has been modified. * This source code may be translated into executable form and incorporated * into proprietary software; there is no requirement for such software to * contain a copyright notice related to this source. * * $Id: dict.h,v 1.3 2005/09/25 12:04:25 hasso Exp $ * $Name: $ */ #ifndef DICT_H #define DICT_H #include /* * Blurb for inclusion into C++ translation units */ #ifdef __cplusplus extern "C" { #endif typedef unsigned long dictcount_t; #define DICTCOUNT_T_MAX ULONG_MAX /* * The dictionary is implemented as a red-black tree */ typedef enum { dnode_red, dnode_black } dnode_color_t; typedef struct dnode_t { struct dnode_t *dict_left; struct dnode_t *dict_right; struct dnode_t *dict_parent; dnode_color_t dict_color; const void *dict_key; void *dict_data; } dnode_t; typedef int (*dict_comp_t)(const void *, const void *); typedef dnode_t *(*dnode_alloc_t)(void *); typedef void (*dnode_free_t)(dnode_t *, void *); typedef struct dict_t { dnode_t dict_nilnode; dictcount_t dict_nodecount; dictcount_t dict_maxcount; dict_comp_t dict_compare; dnode_alloc_t dict_allocnode; dnode_free_t dict_freenode; void *dict_context; int dict_dupes; } dict_t; typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); typedef struct dict_load_t { dict_t *dict_dictptr; dnode_t dict_nilnode; } dict_load_t; extern dict_t *dict_create(dictcount_t, dict_comp_t); extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); extern void dict_destroy(dict_t *); extern void dict_free_nodes(dict_t *); extern void dict_free(dict_t *); extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); extern void dict_init_like(dict_t *, const dict_t *); extern int dict_verify(dict_t *); extern int dict_similar(const dict_t *, const dict_t *); extern dnode_t *dict_lookup(dict_t *, const void *); extern dnode_t *dict_lower_bound(dict_t *, const void *); extern dnode_t *dict_upper_bound(dict_t *, const void *); extern void dict_insert(dict_t *, dnode_t *, const void *); extern dnode_t *dict_delete(dict_t *, dnode_t *); extern int dict_alloc_insert(dict_t *, const void *, void *); extern void dict_delete_free(dict_t *, dnode_t *); extern dnode_t *dict_first(dict_t *); extern dnode_t *dict_last(dict_t *); extern dnode_t *dict_next(dict_t *, dnode_t *); extern dnode_t *dict_prev(dict_t *, dnode_t *); extern dictcount_t dict_count(dict_t *); extern int dict_isempty(dict_t *); extern int dict_isfull(dict_t *); extern int dict_contains(dict_t *, dnode_t *); extern void dict_allow_dupes(dict_t *); extern int dnode_is_in_a_dict(dnode_t *); extern dnode_t *dnode_create(void *); extern dnode_t *dnode_init(dnode_t *, void *); extern void dnode_destroy(dnode_t *); extern void *dnode_get(dnode_t *); extern const void *dnode_getkey(dnode_t *); extern void dnode_put(dnode_t *, void *); extern void dict_process(dict_t *, void *, dnode_process_t); extern void dict_load_begin(dict_load_t *, dict_t *); extern void dict_load_next(dict_load_t *, dnode_t *, const void *); extern void dict_load_end(dict_load_t *); extern void dict_merge(dict_t *, dict_t *); #define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) #define dict_count(D) ((D)->dict_nodecount) #define dict_isempty(D) ((D)->dict_nodecount == 0) #define dnode_get(N) ((N)->dict_data) #define dnode_getkey(N) ((N)->dict_key) #define dnode_put(N, X) ((N)->dict_data = (X)) #ifdef __cplusplus } #endif #endif quagga-0.99.24.1/isisd/isis_lsp.h0000644000175000017500000001146612476520570013355 00000000000000/* * IS-IS Rout(e)ing protocol - isis_lsp.h * LSP processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_LSP_H #define _ZEBRA_ISIS_LSP_H /* Structure for isis_lsp, this structure will only support the fixed * System ID (Currently 6) (atleast for now). In order to support more * We will have to split the header into two parts, and for readability * sake it should better be avoided */ struct isis_lsp { struct isis_fixed_hdr *isis_header; /* normally equals pdu */ struct isis_link_state_hdr *lsp_header; /* pdu + isis_header_len */ struct stream *pdu; /* full pdu lsp */ union { struct list *frags; struct isis_lsp *zero_lsp; } lspu; u_int32_t auth_tlv_offset; /* authentication TLV position in the pdu */ u_int32_t SRMflags[ISIS_MAX_CIRCUITS]; u_int32_t SSNflags[ISIS_MAX_CIRCUITS]; int level; /* L1 or L2? */ int scheduled; /* scheduled for sending */ time_t installed; time_t last_generated; int own_lsp; #ifdef TOPOLOGY_GENERATE int from_topology; struct thread *t_lsp_top_ref; #endif /* used for 60 second counting when rem_lifetime is zero */ int age_out; struct isis_area *area; struct tlvs tlv_data; /* Simplifies TLV access */ }; dict_t *lsp_db_init (void); void lsp_db_destroy (dict_t * lspdb); int lsp_tick (struct thread *thread); int lsp_generate (struct isis_area *area, int level); int lsp_regenerate_schedule (struct isis_area *area, int level, int all_pseudo); int lsp_generate_pseudo (struct isis_circuit *circuit, int level); int lsp_regenerate_schedule_pseudo (struct isis_circuit *circuit, int level); struct isis_lsp *lsp_new (u_char * lsp_id, u_int16_t rem_lifetime, u_int32_t seq_num, u_int8_t lsp_bits, u_int16_t checksum, int level); struct isis_lsp *lsp_new_from_stream_ptr (struct stream *stream, u_int16_t pdu_len, struct isis_lsp *lsp0, struct isis_area *area, int level); void lsp_insert (struct isis_lsp *lsp, dict_t * lspdb); struct isis_lsp *lsp_search (u_char * id, dict_t * lspdb); void lsp_build_list (u_char * start_id, u_char * stop_id, u_char num_lsps, struct list *list, dict_t * lspdb); void lsp_build_list_nonzero_ht (u_char * start_id, u_char * stop_id, struct list *list, dict_t * lspdb); void lsp_build_list_ssn (struct isis_circuit *circuit, u_char num_lsps, struct list *list, dict_t * lspdb); void lsp_search_and_destroy (u_char * id, dict_t * lspdb); void lsp_purge_pseudo (u_char * id, struct isis_circuit *circuit, int level); void lsp_purge_non_exist (struct isis_link_state_hdr *lsp_hdr, struct isis_area *area); #define LSP_EQUAL 1 #define LSP_NEWER 2 #define LSP_OLDER 3 #define LSP_PSEUDO_ID(I) ((I)[ISIS_SYS_ID_LEN]) #define LSP_FRAGMENT(I) ((I)[ISIS_SYS_ID_LEN + 1]) #define OWNLSPID(I) \ memcpy ((I), isis->sysid, ISIS_SYS_ID_LEN);\ (I)[ISIS_SYS_ID_LEN] = 0;\ (I)[ISIS_SYS_ID_LEN + 1] = 0 int lsp_id_cmp (u_char * id1, u_char * id2); int lsp_compare (char *areatag, struct isis_lsp *lsp, u_int32_t seq_num, u_int16_t checksum, u_int16_t rem_lifetime); void lsp_update (struct isis_lsp *lsp, struct stream *stream, struct isis_area *area, int level); void lsp_inc_seqnum (struct isis_lsp *lsp, u_int32_t seq_num); void lsp_print (struct isis_lsp *lsp, struct vty *vty, char dynhost); void lsp_print_detail (struct isis_lsp *lsp, struct vty *vty, char dynhost); int lsp_print_all (struct vty *vty, dict_t * lspdb, char detail, char dynhost); const char *lsp_bits2string (u_char *); /* sets SRMflags for all active circuits of an lsp */ void lsp_set_all_srmflags (struct isis_lsp *lsp); #ifdef TOPOLOGY_GENERATE void generate_topology_lsps (struct isis_area *area); void remove_topology_lsps (struct isis_area *area); void build_topology_lsp_data (struct isis_lsp *lsp, struct isis_area *area, int lsp_top_num); #endif /* TOPOLOGY_GENERATE */ #endif /* ISIS_LSP */ quagga-0.99.24.1/isisd/isis_constants.h0000644000175000017500000001144212476520570014565 00000000000000/* * IS-IS Rout(e)ing protocol - isis_constants.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISIS_CONSTANTS_H #define ISIS_CONSTANTS_H /* * Architectural constant values from p. 35 of ISO/IEC 10589 */ #define MAX_NARROW_LINK_METRIC 63 #define MAX_NARROW_PATH_METRIC 1023 #define MAX_WIDE_LINK_METRIC 0x00FFFFFF /* RFC4444 */ #define MAX_WIDE_PATH_METRIC 0xFE000000 /* RFC3787 */ #define ISO_SAP 0xFE #define INTRADOMAIN_ROUTEING_SELECTOR 0 #define SEQUENCE_MODULUS 4294967296 #define RECEIVE_LSP_BUFFER_SIZE 1492 /* * implementation specific jitter values */ #define IIH_JITTER 10 /* % */ #define MAX_AGE_JITTER 5 /* % */ #define MAX_LSP_GEN_JITTER 5 /* % */ #define CSNP_JITTER 10 /* % */ #define PSNP_JITTER 10 /* % */ #define RANDOM_SPREAD 100000.0 #define ISIS_LEVELS 2 #define ISIS_LEVEL1 1 #define ISIS_LEVEL2 2 /* * Default values * ISO - 10589 Section 7.3.21 - Parameters * RFC 4444 */ #define MAX_AGE 1200 #define ZERO_AGE_LIFETIME 60 #define MIN_LSP_LIFETIME 350 #define MAX_LSP_LIFETIME 65535 #define DEFAULT_LSP_LIFETIME 1200 #define MIN_MAX_LSP_GEN_INTERVAL 1 #define MAX_MAX_LSP_GEN_INTERVAL 65235 #define DEFAULT_MAX_LSP_GEN_INTERVAL 900 #define MIN_MIN_LSP_GEN_INTERVAL 1 #define MAX_MIN_LSP_GEN_INTERVAL 120 /* RFC 4444 says 65535 */ #define DEFAULT_MIN_LSP_GEN_INTERVAL 30 #define MIN_LSP_TRANS_INTERVAL 5 #define MIN_CSNP_INTERVAL 1 #define MAX_CSNP_INTERVAL 600 #define DEFAULT_CSNP_INTERVAL 10 #define MIN_PSNP_INTERVAL 1 #define MAX_PSNP_INTERVAL 120 #define DEFAULT_PSNP_INTERVAL 2 #define MIN_HELLO_INTERVAL 1 #define MAX_HELLO_INTERVAL 600 #define DEFAULT_HELLO_INTERVAL 3 #define MIN_HELLO_MULTIPLIER 2 #define MAX_HELLO_MULTIPLIER 100 #define DEFAULT_HELLO_MULTIPLIER 10 #define MIN_PRIORITY 0 #define MAX_PRIORITY 127 #define DEFAULT_PRIORITY 64 /* min and max metric varies by new vs old metric types */ #define DEFAULT_CIRCUIT_METRIC 10 #define METRICS_UNSUPPORTED 0x80 #define MINIMUM_SPF_INTERVAL 1 #define ISIS_MAX_PATH_SPLITS 64 /* * NLPID values */ #define NLPID_IP 204 #define NLPID_IPV6 142 #define NLPID_SNAP 128 #define NLPID_CLNP 129 #define NLPID_ESIS 130 /* * Return values for functions */ #define ISIS_OK 0 #define ISIS_WARNING 1 #define ISIS_ERROR 2 #define ISIS_CRITICAL 3 /* * IS-IS Circuit Types */ #define IS_LEVEL_1 1 #define IS_LEVEL_2 2 #define IS_LEVEL_1_AND_2 3 #define SNPA_ADDRSTRLEN 18 #define ISIS_SYS_ID_LEN 6 #define ISIS_NSEL_LEN 1 #define SYSID_STRLEN 24 /* * LSP bit masks */ #define LSPBIT_P 0x80 #define LSPBIT_ATT 0x78 #define LSPBIT_OL 0x04 #define LSPBIT_IST 0x03 /* * LSP bit masking macros * taken from tcpdumps * print-isoclns.c */ #define ISIS_MASK_LSP_OL_BIT(x) ((x)&0x4) #define ISIS_MASK_LSP_IS_L1_BIT(x) ((x)&0x1) #define ISIS_MASK_LSP_IS_L2_BIT(x) ((x)&0x2) #define ISIS_MASK_LSP_PARTITION_BIT(x) ((x)&0x80) #define ISIS_MASK_LSP_ATT_BITS(x) ((x)&0x78) #define ISIS_MASK_LSP_ATT_ERROR_BIT(x) ((x)&0x40) #define ISIS_MASK_LSP_ATT_EXPENSE_BIT(x) ((x)&0x20) #define ISIS_MASK_LSP_ATT_DELAY_BIT(x) ((x)&0x10) #define ISIS_MASK_LSP_ATT_DEFAULT_BIT(x) ((x)&0x8) #define LLC_LEN 3 /* we need to be aware of the fact we are using ISO sized * packets, using isomtu = mtu - LLC_LEN */ #define ISO_MTU(C) \ ((if_is_broadcast ((C)->interface)) ? \ (C->interface->mtu - LLC_LEN) : (C->interface->mtu)) #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #endif /* ISIS_CONSTANTS_H */ quagga-0.99.24.1/isisd/isis_adjacency.h0000644000175000017500000000757712476520570014510 00000000000000/* * IS-IS Rout(e)ing protocol - isis_adjacency.h * IS-IS adjacency handling * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_ADJACENCY_H #define _ZEBRA_ISIS_ADJACENCY_H enum isis_adj_usage { ISIS_ADJ_NONE, ISIS_ADJ_LEVEL1, ISIS_ADJ_LEVEL2, ISIS_ADJ_LEVEL1AND2 }; enum isis_system_type { ISIS_SYSTYPE_UNKNOWN, ISIS_SYSTYPE_ES, ISIS_SYSTYPE_IS, ISIS_SYSTYPE_L1_IS, ISIS_SYSTYPE_L2_IS }; enum isis_adj_state { ISIS_ADJ_UNKNOWN, ISIS_ADJ_INITIALIZING, ISIS_ADJ_UP, ISIS_ADJ_DOWN }; /* * we use the following codes to give an indication _why_ * a specific adjacency is up or down */ enum isis_adj_updown_reason { ISIS_ADJ_REASON_SEENSELF, ISIS_ADJ_REASON_AREA_MISMATCH, ISIS_ADJ_REASON_HOLDTIMER_EXPIRED, ISIS_ADJ_REASON_AUTH_FAILED, ISIS_ADJ_REASON_CHECKSUM_FAILED }; #define DIS_RECORDS 8 /* keep the last 8 DIS state changes on record */ struct isis_dis_record { int dis; /* is our neighbor the DIS ? */ time_t last_dis_change; /* timestamp for last dis change */ }; struct isis_adjacency { u_char snpa[ETH_ALEN]; /* NeighbourSNPAAddress */ u_char sysid[ISIS_SYS_ID_LEN]; /* neighbourSystemIdentifier */ u_char lanid[ISIS_SYS_ID_LEN + 1]; /* LAN id on bcast circuits */ int dischanges[ISIS_LEVELS]; /* how many DIS changes ? */ /* an array of N levels for M records */ struct isis_dis_record dis_record[DIS_RECORDS * ISIS_LEVELS]; enum isis_adj_state adj_state; /* adjacencyState */ enum isis_adj_usage adj_usage; /* adjacencyUsage */ struct list *area_addrs; /* areaAdressesOfNeighbour */ struct nlpids nlpids; /* protocols spoken ... */ struct list *ipv4_addrs; struct in_addr router_address; #ifdef HAVE_IPV6 struct list *ipv6_addrs; struct in6_addr router_address6; #endif /* HAVE_IPV6 */ u_char prio[ISIS_LEVELS]; /* priorityOfNeighbour for DIS */ int circuit_t; /* from hello PDU hdr */ int level; /* level (1 or 2) */ enum isis_system_type sys_type; /* neighbourSystemType */ u_int16_t hold_time; /* entryRemainingTime */ u_int32_t last_upd; u_int32_t last_flap; /* last time the adj flapped */ int flaps; /* number of adjacency flaps */ struct thread *t_expire; /* expire after hold_time */ struct isis_circuit *circuit; /* back pointer */ }; struct isis_adjacency *isis_adj_lookup (u_char * sysid, struct list *adjdb); struct isis_adjacency *isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb); struct isis_adjacency *isis_new_adj (u_char * id, u_char * snpa, int level, struct isis_circuit *circuit); void isis_delete_adj (void *adj); void isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state, const char *reason); void isis_adj_print (struct isis_adjacency *adj); int isis_adj_expire (struct thread *thread); void isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty, char detail); void isis_adj_build_neigh_list (struct list *adjdb, struct list *list); void isis_adj_build_up_list (struct list *adjdb, struct list *list); #endif /* ISIS_ADJACENCY_H */ quagga-0.99.24.1/isisd/isis_tlv.h0000644000175000017500000002504312476520570013360 00000000000000/* * IS-IS Rout(e)ing protocol - isis_tlv.h * IS-IS TLV related routines * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_TLV_H #define _ZEBRA_ISIS_TLV_H /* * The list of TLVs we (should) support. * ____________________________________________________________________________ * Name Value IIH LSP SNP Status * LAN * ____________________________________________________________________________ * * Area Addresses 1 y y n ISO10589 * IIS Neighbors 2 n y n ISO10589 * ES Neighbors 3 n y n ISO10589 * IIS Neighbors 6 y n n ISO10589 * Padding 8 y n n ISO10589 * LSP Entries 9 n n y ISO10589 * Authentication 10 y y y ISO10589, RFC3567 * Checksum 12 y n y RFC3358 * TE IS Reachability 22 n y n RFC5305 * IS Alias 24 n y n RFC3786 * IP Int. Reachability 128 n y n RFC1195 * Protocols Supported 129 y y n RFC1195 * IP Ext. Reachability 130 n y n RFC1195 * IDRPI 131 n y y RFC1195 * IP Interface Address 132 y y n RFC1195 * TE Router ID 134 n y n RFC5305 * Extended IP Reachability 135 n y n RFC5305 * Dynamic Hostname 137 n y n RFC2763 * Shared Risk Link Group 138 n y y RFC5307 * Restart TLV 211 y n n RFC3847 * MT IS Reachability 222 n y n RFC5120 * MT Supported 229 y y n RFC5120 * IPv6 Interface Address 232 y y n RFC5308 * MT IP Reachability 235 n y n RFC5120 * IPv6 IP Reachability 236 n y n RFC5308 * MT IPv6 IP Reachability 237 n y n RFC5120 * P2P Adjacency State 240 y n n RFC3373 * IIH Sequence Number 241 y n n draft-shen-isis-iih-sequence * Router Capability 242 - - - draft-ietf-isis-caps * * * IS Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ * Administartive group (color) 3 RFC5305 * Link Local/Remote Identifiers 4 RFC5307 * IPv4 interface address 6 RFC5305 * IPv4 neighbor address 8 RFC5305 * Maximum link bandwidth 9 RFC5305 * Reservable link bandwidth 10 RFC5305 * Unreserved bandwidth 11 RFC5305 * TE Default metric 18 RFC5305 * Link Protection Type 20 RFC5307 * Interface Switching Capability 21 RFC5307 * * * IP Reachability sub-TLVs we (should) support. * ____________________________________________________________________________ * Name Value Status * ____________________________________________________________________________ * 32bit administrative tag 1 RFC5130 * 64bit administrative tag 2 RFC5130 * Management prefix color 117 RFC5120 */ #define AREA_ADDRESSES 1 #define IS_NEIGHBOURS 2 #define ES_NEIGHBOURS 3 #define LAN_NEIGHBOURS 6 #define PADDING 8 #define LSP_ENTRIES 9 #define AUTH_INFO 10 #define CHECKSUM 12 #define TE_IS_NEIGHBOURS 22 #define IS_ALIAS 24 #define IPV4_INT_REACHABILITY 128 #define PROTOCOLS_SUPPORTED 129 #define IPV4_EXT_REACHABILITY 130 #define IDRP_INFO 131 #define IPV4_ADDR 132 #define TE_ROUTER_ID 134 #define TE_IPV4_REACHABILITY 135 #define DYNAMIC_HOSTNAME 137 #define GRACEFUL_RESTART 211 #define IPV6_ADDR 232 #define IPV6_REACHABILITY 236 #define WAY3_HELLO 240 #define AUTH_INFO_HDRLEN 3 #define IS_NEIGHBOURS_LEN (ISIS_SYS_ID_LEN + 5) #define LAN_NEIGHBOURS_LEN 6 #define LSP_ENTRIES_LEN (10 + ISIS_SYS_ID_LEN) /* FIXME: should be entry */ #define IPV4_REACH_LEN 12 #define IPV6_REACH_LEN 22 #define TE_IPV4_REACH_LEN 9 /* struct for neighbor */ struct is_neigh { struct metric metrics; u_char neigh_id[ISIS_SYS_ID_LEN + 1]; }; /* struct for te is neighbor */ struct te_is_neigh { u_char neigh_id[ISIS_SYS_ID_LEN + 1]; u_char te_metric[3]; u_char sub_tlvs_length; }; /* Decode and encode three-octet metric into host byte order integer */ #define GET_TE_METRIC(t) \ (((unsigned)(t)->te_metric[0]<<16) | ((t)->te_metric[1]<<8) | \ (t)->te_metric[2]) #define SET_TE_METRIC(t, m) \ (((t)->te_metric[0] = (m) >> 16), \ ((t)->te_metric[1] = (m) >> 8), \ ((t)->te_metric[2] = (m))) /* struct for es neighbors */ struct es_neigh { struct metric metrics; /* approximate position of first, we use the * length ((uchar*)metric-1) to know all */ u_char first_es_neigh[ISIS_SYS_ID_LEN]; }; struct partition_desig_level2_is { struct list *isis_system_ids; }; /* struct for lan neighbors */ struct lan_neigh { u_char LAN_addr[6]; }; #ifdef __SUNPRO_C #pragma pack(1) #endif /* struct for LSP entry */ struct lsp_entry { u_int16_t rem_lifetime; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int32_t seq_num; u_int16_t checksum; } __attribute__ ((packed)); #ifdef __SUNPRO_C #pragma pack() #endif /* struct for checksum */ struct checksum { u_int16_t checksum; }; /* ipv4 reachability */ struct ipv4_reachability { struct metric metrics; struct in_addr prefix; struct in_addr mask; }; /* te router id */ struct te_router_id { struct in_addr id; }; /* te ipv4 reachability */ struct te_ipv4_reachability { u_int32_t te_metric; u_char control; u_char prefix_start; /* since this is variable length by nature it only */ }; /* points to an approximate location */ struct idrp_info { u_char len; u_char *value; }; #ifdef HAVE_IPV6 struct ipv6_reachability { u_int32_t metric; u_char control_info; u_char prefix_len; u_char prefix[16]; }; /* bits in control_info */ #define CTRL_INFO_DIRECTION 0x80 #define DIRECTION_UP 0 #define DIRECTION_DOWN 1 #define CTRL_INFO_DISTRIBUTION 0x40 #define DISTRIBUTION_INTERNAL 0 #define DISTRIBUTION_EXTERNAL 1 #define CTRL_INFO_SUBTLVS 0x20 #endif /* HAVE_IPV6 */ /* * Pointer to each tlv type, filled by parse_tlvs() */ struct tlvs { struct checksum *checksum; struct hostname *hostname; struct nlpids *nlpids; struct te_router_id *router_id; struct list *area_addrs; struct list *is_neighs; struct list *te_is_neighs; struct list *es_neighs; struct list *lsp_entries; struct list *prefix_neighs; struct list *lan_neighs; struct list *ipv4_addrs; struct list *ipv4_int_reachs; struct list *ipv4_ext_reachs; struct list *te_ipv4_reachs; #ifdef HAVE_IPV6 struct list *ipv6_addrs; struct list *ipv6_reachs; #endif struct isis_passwd auth_info; }; /* * Own definitions - used to bitmask found and expected */ #define TLVFLAG_AREA_ADDRS (1<<0) #define TLVFLAG_IS_NEIGHS (1<<1) #define TLVFLAG_ES_NEIGHS (1<<2) #define TLVFLAG_PARTITION_DESIG_LEVEL2_IS (1<<3) #define TLVFLAG_PREFIX_NEIGHS (1<<4) #define TLVFLAG_LAN_NEIGHS (1<<5) #define TLVFLAG_LSP_ENTRIES (1<<6) #define TLVFLAG_PADDING (1<<7) #define TLVFLAG_AUTH_INFO (1<<8) #define TLVFLAG_IPV4_INT_REACHABILITY (1<<9) #define TLVFLAG_NLPID (1<<10) #define TLVFLAG_IPV4_EXT_REACHABILITY (1<<11) #define TLVFLAG_IPV4_ADDR (1<<12) #define TLVFLAG_DYN_HOSTNAME (1<<13) #define TLVFLAG_IPV6_ADDR (1<<14) #define TLVFLAG_IPV6_REACHABILITY (1<<15) #define TLVFLAG_TE_IS_NEIGHS (1<<16) #define TLVFLAG_TE_IPV4_REACHABILITY (1<<17) #define TLVFLAG_3WAY_HELLO (1<<18) #define TLVFLAG_TE_ROUTER_ID (1<<19) #define TLVFLAG_CHECKSUM (1<<20) #define TLVFLAG_GRACEFUL_RESTART (1<<21) void init_tlvs (struct tlvs *tlvs, uint32_t expected); void free_tlvs (struct tlvs *tlvs); int parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected, u_int32_t * found, struct tlvs *tlvs, u_int32_t * auth_tlv_offset); int add_tlv (u_char, u_char, u_char *, struct stream *); void free_tlv (void *val); int tlv_add_area_addrs (struct list *area_addrs, struct stream *stream); int tlv_add_is_neighs (struct list *is_neighs, struct stream *stream); int tlv_add_te_is_neighs (struct list *te_is_neighs, struct stream *stream); int tlv_add_lan_neighs (struct list *lan_neighs, struct stream *stream); int tlv_add_nlpid (struct nlpids *nlpids, struct stream *stream); int tlv_add_checksum (struct checksum *checksum, struct stream *stream); int tlv_add_authinfo (u_char auth_type, u_char authlen, u_char *auth_value, struct stream *stream); int tlv_add_ip_addrs (struct list *ip_addrs, struct stream *stream); int tlv_add_in_addr (struct in_addr *, struct stream *stream, u_char tag); int tlv_add_dynamic_hostname (struct hostname *hostname, struct stream *stream); int tlv_add_lsp_entries (struct list *lsps, struct stream *stream); int tlv_add_ipv4_reachs (struct list *ipv4_reachs, struct stream *stream); int tlv_add_te_ipv4_reachs (struct list *te_ipv4_reachs, struct stream *stream); #ifdef HAVE_IPV6 int tlv_add_ipv6_addrs (struct list *ipv6_addrs, struct stream *stream); int tlv_add_ipv6_reachs (struct list *ipv6_reachs, struct stream *stream); #endif /* HAVE_IPV6 */ int tlv_add_padding (struct stream *stream); #endif /* _ZEBRA_ISIS_TLV_H */ quagga-0.99.24.1/isisd/isis_pdu.h0000644000175000017500000002446012476520570013345 00000000000000/* * IS-IS Rout(e)ing protocol - isis_pdu.h * PDU processing * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_ISIS_PDU_H #define _ZEBRA_ISIS_PDU_H #ifdef __SUNPRO_C #pragma pack(1) #endif /* * ISO 9542 - 7.5,7.6 * * ES to IS Fixed Header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Intradomain Routeing Protocol Discriminator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Length Indicator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version/Protocol ID extension | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved = 0 | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | 0 | 0 | 0 | PDU Type | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Checksum | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct esis_fixed_hdr { u_char idrp; u_char length; u_char version; u_char id_len; u_char pdu_type; u_int16_t holdtime; u_int16_t checksum; } __attribute__ ((packed)); #define ESIS_FIXED_HDR_LEN 9 #define ESH_PDU 2 #define ISH_PDU 4 #define RD_PDU 5 /* * IS to IS Fixed Header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Intradomain Routeing Protocol Discriminator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Length Indicator | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version/Protocol ID extension | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | R | R | PDU Type | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Version | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Maximum Area Addresses | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_fixed_hdr { u_char idrp; u_char length; u_char version1; u_char id_len; u_char pdu_type; u_char version2; u_char reserved; u_char max_area_addrs; } __attribute__ ((packed)); #define ISIS_FIXED_HDR_LEN 8 /* * IS-IS PDU types. */ #define L1_LAN_HELLO 15 #define L2_LAN_HELLO 16 /* * L1 and L2 LAN IS to IS Hello PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | Circuit Type | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Holding Time | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | PDU Length | 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | R | Priority | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LAN ID | id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_lan_hello_hdr { u_char circuit_t; u_char source_id[ISIS_SYS_ID_LEN]; u_int16_t hold_time; u_int16_t pdu_len; u_char prio; u_char lan_id[ISIS_SYS_ID_LEN + 1]; } __attribute__ ((packed)); #define ISIS_LANHELLO_HDRLEN 19 #define P2P_HELLO 17 /* * Point-to-point IS to IS hello PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Reserved | Circuit Type | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Holding Time + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | Local Circuit ID | 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_p2p_hello_hdr { u_char circuit_t; u_char source_id[ISIS_SYS_ID_LEN]; u_int16_t hold_time; u_int16_t pdu_len; u_char local_id; } __attribute__ ((packed)); #define ISIS_P2PHELLO_HDRLEN 12 #define L1_LINK_STATE 18 #define L2_LINK_STATE 20 /* * L1 and L2 IS to IS link state PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Remaining Lifetime + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | LSP ID | id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Sequence Number + 4 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Checksum + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * | P | ATT |LSPDBOL| ISTYPE | * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_link_state_hdr { u_int16_t pdu_len; u_int16_t rem_lifetime; u_char lsp_id[ISIS_SYS_ID_LEN + 2]; u_int32_t seq_num; u_int16_t checksum; u_int8_t lsp_bits; } __attribute__ ((packed)); #define ISIS_LSP_HDR_LEN 19 /* * Since the length field of LSP Entries TLV is one byte long, and each LSP * entry is LSP_ENTRIES_LEN (16) bytes long, the maximum number of LSP entries * can be accomodated in a TLV is * 255 / 16 = 15. * * Therefore, the maximum length of the LSP Entries TLV is * 16 * 15 + 2 (header) = 242 bytes. */ #define MAX_LSP_ENTRIES_TLV_SIZE 242 #define L1_COMPLETE_SEQ_NUM 24 #define L2_COMPLETE_SEQ_NUM 25 /* * L1 and L2 IS to IS complete sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Start LSP ID + id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + End LSP ID + id_len + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ */ struct isis_complete_seqnum_hdr { u_int16_t pdu_len; u_char source_id[ISIS_SYS_ID_LEN + 1]; u_char start_lsp_id[ISIS_SYS_ID_LEN + 2]; u_char stop_lsp_id[ISIS_SYS_ID_LEN + 2]; }; #define ISIS_CSNP_HDRLEN 25 #define L1_PARTIAL_SEQ_NUM 26 #define L2_PARTIAL_SEQ_NUM 27 /* * L1 and L2 IS to IS partial sequence numbers PDU header * +-------+-------+-------+-------+-------+-------+-------+-------+ * + PDU Length + 2 * +-------+-------+-------+-------+-------+-------+-------+-------+ * + Source ID + id_len + 1 * +---------------------------------------------------------------+ */ struct isis_partial_seqnum_hdr { u_int16_t pdu_len; u_char source_id[ISIS_SYS_ID_LEN + 1]; }; #define ISIS_PSNP_HDRLEN 9 #ifdef __SUNPRO_C #pragma pack() #endif /* * Function for receiving IS-IS PDUs */ int isis_receive (struct thread *thread); /* * calling arguments for snp_process () */ #define ISIS_SNP_PSNP_FLAG 0 #define ISIS_SNP_CSNP_FLAG 1 #define ISIS_AUTH_MD5_SIZE 16U /* * Sending functions */ int send_lan_l1_hello (struct thread *thread); int send_lan_l2_hello (struct thread *thread); int send_p2p_hello (struct thread *thread); int send_csnp (struct isis_circuit *circuit, int level); int send_l1_csnp (struct thread *thread); int send_l2_csnp (struct thread *thread); int send_l1_psnp (struct thread *thread); int send_l2_psnp (struct thread *thread); int send_lsp (struct thread *thread); int ack_lsp (struct isis_link_state_hdr *hdr, struct isis_circuit *circuit, int level); void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type); int send_hello (struct isis_circuit *circuit, int level); #endif /* _ZEBRA_ISIS_PDU_H */ quagga-0.99.24.1/isisd/isisd.h0000644000175000017500000001241212476520570012633 00000000000000/* * IS-IS Rout(e)ing protocol - isisd.h * * Copyright (C) 2001,2002 Sampo Saaristo * Tampere University of Technology * Institute of Communications Engineering * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licenseas published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ISISD_H #define ISISD_H #define ISISD_VERSION "0.0.7" /* uncomment if you are a developer in bug hunt */ /* #define EXTREME_DEBUG */ /* #define EXTREME_TLV_DEBUG */ struct rmap { char *name; struct route_map *map; }; struct isis { u_long process_id; int sysid_set; u_char sysid[ISIS_SYS_ID_LEN]; /* SystemID for this IS */ u_int32_t router_id; /* Router ID from zebra */ struct list *area_list; /* list of IS-IS areas */ struct list *init_circ_list; struct list *nexthops; /* IPv4 next hops from this IS */ #ifdef HAVE_IPV6 struct list *nexthops6; /* IPv6 next hops from this IS */ #endif /* HAVE_IPV6 */ u_char max_area_addrs; /* maximumAreaAdresses */ struct area_addr *man_area_addrs; /* manualAreaAddresses */ u_int32_t debugs; /* bitmap for debug */ time_t uptime; /* when did we start */ struct thread *t_dync_clean; /* dynamic hostname cache cleanup thread */ /* Redistributed external information. */ struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; /* Redistribute metric info. */ struct { int type; /* Internal or External */ int value; /* metric value */ } dmetric[ZEBRA_ROUTE_MAX + 1]; struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX + 1]; #ifdef HAVE_IPV6 struct { struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX + 1]; } inet6_afmode; #endif }; extern struct isis *isis; struct isis_area { struct isis *isis; /* back pointer */ dict_t *lspdb[ISIS_LEVELS]; /* link-state dbs */ struct isis_spftree *spftree[ISIS_LEVELS]; /* The v4 SPTs */ struct route_table *route_table[ISIS_LEVELS]; /* IPv4 routes */ #ifdef HAVE_IPV6 struct isis_spftree *spftree6[ISIS_LEVELS]; /* The v6 SPTs */ struct route_table *route_table6[ISIS_LEVELS]; /* IPv6 routes */ #endif unsigned int min_bcast_mtu; struct list *circuit_list; /* IS-IS circuits */ struct flags flags; struct thread *t_tick; /* LSP walker */ struct thread *t_lsp_refresh[ISIS_LEVELS]; int lsp_regenerate_pending[ISIS_LEVELS]; /* * Configurables */ struct isis_passwd area_passwd; struct isis_passwd domain_passwd; /* do we support dynamic hostnames? */ char dynhostname; /* do we support new style metrics? */ char newmetric; char oldmetric; /* identifies the routing instance */ char *area_tag; /* area addresses for this area */ struct list *area_addrs; u_int16_t max_lsp_lifetime[ISIS_LEVELS]; char is_type; /* level-1 level-1-2 or level-2-only */ /* are we overloaded? */ char overload_bit; u_int16_t lsp_refresh[ISIS_LEVELS]; /* minimum time allowed before lsp retransmission */ u_int16_t lsp_gen_interval[ISIS_LEVELS]; /* min interval between between consequtive SPFs */ u_int16_t min_spf_interval[ISIS_LEVELS]; /* the percentage of LSP mtu size used, before generating a new frag */ int lsp_frag_threshold; int ip_circuits; /* logging adjacency changes? */ u_char log_adj_changes; #ifdef HAVE_IPV6 int ipv6_circuits; #endif /* HAVE_IPV6 */ /* Counters */ u_int32_t circuit_state_changes; #ifdef TOPOLOGY_GENERATE struct list *topology; u_char topology_baseis[ISIS_SYS_ID_LEN]; /* IS for the first IS emulated. */ char *topology_basedynh; /* Dynamic hostname base. */ char top_params[200]; /* FIXME: what is reasonable? */ #endif /* TOPOLOGY_GENERATE */ }; void isis_init (void); void isis_new(unsigned long); struct isis_area *isis_area_create(const char *); struct isis_area *isis_area_lookup (const char *); int isis_area_get (struct vty *vty, const char *area_tag); void print_debug(struct vty *, int, int); /* Master of threads. */ extern struct thread_master *master; #define DEBUG_ADJ_PACKETS (1<<0) #define DEBUG_CHECKSUM_ERRORS (1<<1) #define DEBUG_LOCAL_UPDATES (1<<2) #define DEBUG_PROTOCOL_ERRORS (1<<3) #define DEBUG_SNP_PACKETS (1<<4) #define DEBUG_UPDATE_PACKETS (1<<5) #define DEBUG_SPF_EVENTS (1<<6) #define DEBUG_SPF_STATS (1<<7) #define DEBUG_SPF_TRIGGERS (1<<8) #define DEBUG_RTE_EVENTS (1<<9) #define DEBUG_EVENTS (1<<10) #define DEBUG_ZEBRA (1<<11) #define DEBUG_PACKET_DUMP (1<<12) #endif /* ISISD_H */ quagga-0.99.24.1/isisd/isisd.conf.sample0000644000175000017500000000142512476520570014613 00000000000000! -*- isis -*- ! ! ISISd sample configuration file ! hostname isisd password foo enable password foo log stdout !log file /tmp/isisd.log ! ! router isis DEAD net 47.0023.0000.0003.0300.0100.0102.0304.0506.00 ! is-type level-1 ! -- set the lifetime either for level-1, level-2 or both ! lsp-lifetime level-1 65535 ! lsp-lifetime level-2 65535 ! lsp-lifetime 65535 ! hostname isisd-router ! area-password foobar ! domain-password foobar interface eth0 ip router isis DEAD ! isis hello-interval 5 ! isis lsp-interval 1000 ! -- optional ! isis circuit-type level-1 ! isis password lallaa level-1 ! isis metric 1 level-1 ! isis csnp-interval 5 level-1 ! isis retransmit-interval 10 ! isis retransmit-throttle-interval ! isis hello-multiplier 2 level-1 ! isis priority 64 ! quagga-0.99.24.1/isisd/Makefile.am0000644000175000017500000000227512476520570013411 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 LIBS = @LIBS@ AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libisis.a sbin_PROGRAMS = isisd SUBDIRS = topology libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_route.c isis_routemap.c noinst_HEADERS = \ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_route.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ isis_bpf.c isis_dlpi.c isis_pfpacket.c isisd_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = isisd.conf.sample quagga-0.99.24.1/isisd/Makefile.in0000644000175000017500000007501612476521250013421 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = isisd$(EXEEXT) subdir = isisd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) \ AUTHORS README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libisis_a_AR = $(AR) $(ARFLAGS) libisis_a_LIBADD = am_libisis_a_OBJECTS = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \ isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) isis_flags.$(OBJEXT) \ isis_dynhn.$(OBJEXT) iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) \ isis_events.$(OBJEXT) isis_spf.$(OBJEXT) isis_route.$(OBJEXT) \ isis_routemap.$(OBJEXT) libisis_a_OBJECTS = $(am_libisis_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = isis_adjacency.$(OBJEXT) isis_lsp.$(OBJEXT) \ dict.$(OBJEXT) isis_circuit.$(OBJEXT) isis_pdu.$(OBJEXT) \ isis_tlv.$(OBJEXT) isisd.$(OBJEXT) isis_misc.$(OBJEXT) \ isis_zebra.$(OBJEXT) isis_dr.$(OBJEXT) isis_flags.$(OBJEXT) \ isis_dynhn.$(OBJEXT) iso_checksum.$(OBJEXT) isis_csm.$(OBJEXT) \ isis_events.$(OBJEXT) isis_spf.$(OBJEXT) isis_route.$(OBJEXT) \ isis_routemap.$(OBJEXT) am_isisd_OBJECTS = isis_main.$(OBJEXT) $(am__objects_1) \ isis_bpf.$(OBJEXT) isis_dlpi.$(OBJEXT) isis_pfpacket.$(OBJEXT) isisd_OBJECTS = $(am_isisd_OBJECTS) isisd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) DIST_SOURCES = $(libisis_a_SOURCES) $(isisd_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib \ @ISIS_TOPOLOGY_INCLUDES@ INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libisis.a SUBDIRS = topology libisis_a_SOURCES = \ isis_adjacency.c isis_lsp.c dict.c isis_circuit.c isis_pdu.c \ isis_tlv.c isisd.c isis_misc.c isis_zebra.c isis_dr.c \ isis_flags.c isis_dynhn.c iso_checksum.c isis_csm.c isis_events.c \ isis_spf.c isis_route.c isis_routemap.c noinst_HEADERS = \ isisd.h isis_pdu.h isis_tlv.h isis_adjacency.h isis_constants.h \ isis_lsp.h dict.h isis_circuit.h isis_misc.h isis_network.h \ isis_zebra.h isis_dr.h isis_flags.h isis_dynhn.h isis_common.h \ iso_checksum.h isis_csm.h isis_events.h isis_spf.h isis_route.h \ include-netbsd/clnp.h include-netbsd/esis.h include-netbsd/iso.h isisd_SOURCES = \ isis_main.c $(libisis_a_SOURCES) \ isis_bpf.c isis_dlpi.c isis_pfpacket.c isisd_LDADD = @ISIS_TOPOLOGY_LIB@ ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = isisd.conf.sample all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu isisd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu isisd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libisis.a: $(libisis_a_OBJECTS) $(libisis_a_DEPENDENCIES) $(EXTRA_libisis_a_DEPENDENCIES) $(AM_V_at)-rm -f libisis.a $(AM_V_AR)$(libisis_a_AR) libisis.a $(libisis_a_OBJECTS) $(libisis_a_LIBADD) $(AM_V_at)$(RANLIB) libisis.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list isisd$(EXEEXT): $(isisd_OBJECTS) $(isisd_DEPENDENCIES) $(EXTRA_isisd_DEPENDENCIES) @rm -f isisd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(isisd_OBJECTS) $(isisd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dict.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_adjacency.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_bpf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_circuit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_csm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dlpi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_dynhn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_events.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_flags.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_lsp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pdu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_pfpacket.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_spf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_tlv.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isis_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isisd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iso_checksum.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-libtool \ clean-noinstLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dist_examplesDATA install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/isisd/include-netbsd/0000755000175000017500000000000012476521356014332 500000000000000quagga-0.99.24.1/isisd/include-netbsd/iso.h0000644000175000017500000001620012476520570015211 00000000000000/* $NetBSD: iso.h,v 1.13 2000/07/28 12:13:34 kleink Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)iso.h 8.1 (Berkeley) 6/10/93 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 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. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ #ifndef _NETISO_ISO_H_ #define _NETISO_ISO_H_ #if 0 #include #endif #if 0 #ifndef sa_family_t typedef __sa_family_t sa_family_t; #define sa_family_t __sa_family_t #endif #endif /* * Return true if this is a multicast address * This assumes that the bit transmission is lsb first. This * assumption is valid for 802.3 but not 802.5. There is a * kludge to get around this for 802.5 -- see if_lan.c * where subnetwork header is setup. */ #define IS_MULTICAST(snpa)\ ((snpa)[0] & 0x01) /* * Protocols */ #define ISOPROTO_TCP 6 /* IETF experiment */ #define ISOPROTO_UDP 17 /* IETF experiment */ #define ISOPROTO_TP0 25 /* connection oriented transport protocol */ #define ISOPROTO_TP1 26 /* not implemented */ #define ISOPROTO_TP2 27 /* not implemented */ #define ISOPROTO_TP3 28 /* not implemented */ #define ISOPROTO_TP4 29 /* connection oriented transport protocol */ #define ISOPROTO_TP ISOPROTO_TP4 /* tp-4 with negotiation */ #define ISOPROTO_CLTP 30 /* connectionless transport (not yet impl.) */ #define ISOPROTO_CLNP 31 /* connectionless internetworking protocol */ #define ISOPROTO_X25 32 /* cons */ #define ISOPROTO_INACT_NL 33 /* inactive network layer! */ #define ISOPROTO_ESIS 34 /* ES-IS protocol */ #define ISOPROTO_INTRAISIS 35 /* IS-IS protocol */ #define ISOPROTO_IDRP 36 /* Interdomain Routing Protocol */ #define ISOPROTO_RAW 255 /* raw clnp */ #define ISOPROTO_MAX 256 #define ISO_PORT_RESERVED 1024 #define ISO_PORT_USERRESERVED 5000 /* * Port/socket numbers: standard network functions * NOT PRESENTLY USED */ #define ISO_PORT_MAINT 501 #define ISO_PORT_ECHO 507 #define ISO_PORT_DISCARD 509 #define ISO_PORT_SYSTAT 511 #define ISO_PORT_NETSTAT 515 /* * Port/socket numbers: non-standard application functions */ #define ISO_PORT_LOGIN 513 /* * Port/socket numbers: public use */ #define ISO_PORT_PUBLIC 1024 /* high bit set --> public */ /* * Network layer protocol identifiers */ #define ISO8473_CLNP 0x81 #define ISO9542_ESIS 0x82 #define ISO9542X25_ESIS 0x8a #define ISO10589_ISIS 0x83 #define ISO8878A_CONS 0x84 #define ISO10747_IDRP 0x85 #ifndef IN_CLASSA_NET #include #endif /* IN_CLASSA_NET */ /* * The following looks like a sockaddr to facilitate using tree lookup * routines */ struct iso_addr { u_char isoa_len; /* length (in bytes) */ char isoa_genaddr[20]; /* general opaque address */ }; struct sockaddr_iso { u_char siso_len; /* length */ sa_family_t siso_family; /* family */ u_char siso_plen; /* presentation selector length */ u_char siso_slen; /* session selector length */ u_char siso_tlen; /* transport selector length */ struct iso_addr siso_addr; /* network address */ u_char siso_pad[6]; /* space for gosip v2 sels */ /* makes struct 32 bytes long */ }; #define siso_nlen siso_addr.isoa_len #define siso_data siso_addr.isoa_genaddr #define TSEL(s) ((caddr_t)((s)->siso_data + (s)->siso_nlen)) #define SAME_ISOADDR(a, b) \ (bcmp((a)->siso_data, (b)->siso_data, (unsigned)(a)->siso_nlen)==0) #define SAME_ISOIFADDR(a, b) (bcmp((a)->siso_data, (b)->siso_data, \ (unsigned)((b)->siso_nlen - (b)->siso_tlen)) == 0) /* * The following are specific values for siso->siso_data[0], * otherwise known as the AFI: */ #define AFI_37 0x37 /* bcd of "37" */ #define AFI_OSINET 0x47 /* bcd of "47" */ #define AFI_RFC986 0x47 /* bcd of "47" */ #define AFI_SNA 0x00 /* SubNetwork Address; invalid really... */ #ifdef _KERNEL extern struct domain isodomain; extern struct protosw isosw[]; #define satosiso(sa) ((struct sockaddr_iso *)(sa)) #define sisotosa(siso) ((struct sockaddr *)(siso)) #else /* user utilities definitions from the iso library */ #ifndef HAVE_SYS_CDEFS_H #define __P(x) x #define __BEGIN_DECLS #define __END_DECLS #else #include #endif __BEGIN_DECLS struct iso_addr *iso_addr __P((const char *)); char *iso_ntoa __P((const struct iso_addr *)); /* THESE DON'T EXIST YET */ struct hostent *iso_gethostbyname __P((const char *)); struct hostent *iso_gethostbyaddr __P((const char *, int, int)); __END_DECLS #endif /* _KERNEL */ #endif /* _NETISO_ISO_H_ */ quagga-0.99.24.1/isisd/include-netbsd/esis.h0000644000175000017500000001412112476520570015362 00000000000000/* $NetBSD: esis.h,v 1.11 1997/11/03 15:01:19 is Exp $ */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)esis.h 8.1 (Berkeley) 6/10/93 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 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. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ #include #define SNPAC_AGE 60 /* seconds */ #define ESIS_CONFIG 60 /* seconds */ #define ESIS_HT (ESIS_CONFIG * 2) /* * Fixed part of an ESIS header */ struct esis_fixed { u_char esis_proto_id; /* network layer protocol identifier */ u_char esis_hdr_len; /* length indicator (octets) */ u_char esis_vers; /* version/protocol identifier * extension */ u_char esis_res1; /* reserved */ u_char esis_type; /* type code */ /* technically, type should be &='d 0x1f */ #define ESIS_ESH 0x02 /* End System Hello */ #define ESIS_ISH 0x04 /* Intermediate System Hello */ #define ESIS_RD 0x06 /* Redirect */ u_char esis_ht_msb; /* holding time (seconds) high byte */ u_char esis_ht_lsb; /* holding time (seconds) low byte */ u_char esis_cksum_msb; /* checksum high byte */ u_char esis_cksum_lsb; /* checksum low byte */ } __attribute__((packed)); /* * Values for ESIS datagram options */ #define ESISOVAL_NETMASK 0xe1 /* address mask option, RD PDU only */ #define ESISOVAL_SNPAMASK 0xe2 /* snpa mask option, RD PDU only */ #define ESISOVAL_ESCT 0xc6 /* end system conf. timer, ISH PDU * only */ #define ESIS_CKSUM_OFF 0x07 #define ESIS_CKSUM_REQUIRED(pdu)\ ((pdu->esis_cksum_msb != 0) || (pdu->esis_cksum_lsb != 0)) #define ESIS_VERSION 1 struct esis_stat { u_short es_nomem; /* insufficient memory to send hello */ u_short es_badcsum; /* incorrect checksum */ u_short es_badvers; /* incorrect version number */ u_short es_badtype; /* unknown pdu type field */ u_short es_toosmall; /* packet too small */ u_short es_eshsent; /* ESH sent */ u_short es_eshrcvd; /* ESH rcvd */ u_short es_ishsent; /* ISH sent */ u_short es_ishrcvd; /* ISH rcvd */ u_short es_rdsent; /* RD sent */ u_short es_rdrcvd; /* RD rcvd */ }; #ifdef _KERNEL struct esis_stat esis_stat; struct socket; struct mbuf; struct snpa_hdr; struct clnp_optidx; struct iso_addr; struct rtentry; struct sockaddr_dl; void esis_init __P((void)); int esis_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); void esis_input __P((struct mbuf *, ...)); void esis_rdoutput __P((struct snpa_hdr *, struct mbuf *, struct clnp_optidx *, struct iso_addr *, struct rtentry *)); int esis_insert_addr __P((caddr_t *, int *, struct iso_addr *, struct mbuf *, int)); void esis_eshinput __P((struct mbuf *, struct snpa_hdr *)); void esis_ishinput __P((struct mbuf *, struct snpa_hdr *)); void esis_rdinput __P((struct mbuf *, struct snpa_hdr *)); void esis_config __P((void *)); void esis_shoutput __P((struct ifnet *, int, int, caddr_t, int, struct iso_addr *)); void isis_input __P((struct mbuf *, ...)); int isis_output __P((struct mbuf *, ...)); void *esis_ctlinput __P((int, struct sockaddr *, void *)); #endif /* _KERNEL */ quagga-0.99.24.1/isisd/include-netbsd/clnp.h0000644000175000017500000005051512476520570015362 00000000000000/* $NetBSD: clnp.h,v 1.13 2001/08/20 12:00:54 wiz Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)clnp.h 8.2 (Berkeley) 4/16/94 */ /*********************************************************** Copyright IBM Corporation 1987 All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of IBM not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, 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. ******************************************************************/ /* * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison */ /* should be config option but cpp breaks with too many #defines */ #define DECBIT /* * Return true if the mbuf is a cluster mbuf */ #define IS_CLUSTER(m) ((m)->m_flags & M_EXT) /* * Move the halfword into the two characters */ #define HTOC(msb, lsb, hword)\ (msb) = (u_char)((hword) >> 8);\ (lsb) = (u_char)((hword) & 0xff) /* * Move the two charcters into the halfword */ #define CTOH(msb, lsb, hword)\ (hword) = ((msb) << 8) | (lsb) /* * Return true if the checksum has been set - ie. the checksum is * not zero */ #define CKSUM_REQUIRED(clnp)\ (((clnp)->cnf_cksum_msb != 0) || ((clnp)->cnf_cksum_lsb != 0)) /* * Fixed part of clnp header */ struct clnp_fixed { u_char cnf_proto_id; /* network layer protocol identifier */ u_char cnf_hdr_len; /* length indicator (octets) */ u_char cnf_vers; /* version/protocol identifier * extension */ u_char cnf_ttl;/* lifetime (500 milliseconds) */ u_char cnf_type; /* type code */ /* Includes err_ok, more_segs, and seg_ok */ u_char cnf_seglen_msb; /* pdu segment length (octets) high * byte */ u_char cnf_seglen_lsb; /* pdu segment length (octets) low * byte */ u_char cnf_cksum_msb; /* checksum high byte */ u_char cnf_cksum_lsb; /* checksum low byte */ } __attribute__((packed)); #define CNF_TYPE 0x1f #define CNF_ERR_OK 0x20 #define CNF_MORE_SEGS 0x40 #define CNF_SEG_OK 0x80 #define CLNP_CKSUM_OFF 0x07 /* offset of checksum */ #define clnl_fixed clnp_fixed /* * Segmentation part of clnp header */ struct clnp_segment { u_short cng_id; /* data unit identifier */ u_short cng_off;/* segment offset */ u_short cng_tot_len; /* total length */ }; /* * Clnp fragment reassembly structures: * * All packets undergoing reassembly are linked together in * clnp_fragl structures. Each clnp_fragl structure contains a * pointer to the original clnp packet header, as well as a * list of packet fragments. Each packet fragment * is headed by a clnp_frag structure. This structure contains the * offset of the first and last byte of the fragment, as well as * a pointer to the data (an mbuf chain) of the fragment. */ /* * NOTE: * The clnp_frag structure is stored in an mbuf immedately * preceding the fragment data. Since there are words in * this struct, it must be word aligned. * * NOTE: * All the fragment code assumes that the entire clnp header is * contained in the first mbuf. */ struct clnp_frag { u_int cfr_first; /* offset of first byte of this frag */ u_int cfr_last; /* offset of last byte of this frag */ u_int cfr_bytes; /* bytes to shave to get to data */ struct mbuf *cfr_data; /* ptr to data for this frag */ struct clnp_frag *cfr_next; /* next fragment in list */ }; struct clnp_fragl { struct iso_addr cfl_src;/* source of the pkt */ struct iso_addr cfl_dst;/* destination of the pkt */ u_short cfl_id; /* id of the pkt */ u_char cfl_ttl;/* current ttl of pkt */ u_short cfl_last; /* offset of last byte of packet */ struct mbuf *cfl_orighdr; /* ptr to original header */ struct clnp_frag *cfl_frags; /* linked list of fragments for pkt */ struct clnp_fragl *cfl_next; /* next pkt being reassembled */ }; /* * The following structure is used to index into an options section * of a clnp datagram. These values can be used without worry that * offset or length fields are invalid or too big, etc. That is, * the consistancy of the options will be guaranteed before this * structure is filled in. Any pointer (field ending in p) is * actually the offset from the beginning of the mbuf the option * is contained in. A value of NULL for any pointer * means that the option is not present. The length any option * does not include the option code or option length fields. */ struct clnp_optidx { u_short cni_securep; /* ptr to start of security option */ char cni_secure_len; /* length of entire security option */ u_short cni_srcrt_s; /* offset of start of src rt option */ u_short cni_srcrt_len; /* length of entire src rt option */ u_short cni_recrtp; /* ptr to beginning of recrt option */ char cni_recrt_len; /* length of entire recrt option */ char cni_priorp; /* ptr to priority option */ u_short cni_qos_formatp; /* ptr to format of qos * option */ char cni_qos_len; /* length of entire qos option */ u_char cni_er_reason; /* reason from ER pdu option */ /* ESIS options */ u_short cni_esct; /* value from ISH ESCT option */ u_short cni_netmaskp; /* ptr to beginning of netmask option */ char cni_netmask_len; /* length of entire netmask * option */ u_short cni_snpamaskp; /* ptr to start of snpamask option */ char cni_snpamask_len; /* length of entire snpamask * option */ }; #define ER_INVALREAS 0xff /* code for invalid ER pdu discard reason */ /* given an mbuf and addr of option, return offset from data of mbuf */ #define CLNP_OPTTOOFF(m, opt) ((u_short) (opt - mtod(m, caddr_t))) /* given an mbuf and offset of option, return address of option */ #define CLNP_OFFTOOPT(m, off) ((caddr_t) (mtod(m, caddr_t) + off)) /* return true iff src route is valid */ #define CLNPSRCRT_VALID(oidx) ((oidx) && (oidx->cni_srcrt_s)) /* return the offset field of the src rt */ #define CLNPSRCRT_OFF(oidx, options)\ (*((u_char *)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + 1))) /* return the type field of the src rt */ #define CLNPSRCRT_TYPE(oidx, options)\ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s)))) /* return the length of the current address */ #define CLNPSRCRT_CLEN(oidx, options)\ ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options) - 1))) /* return the address of the current address */ #define CLNPSRCRT_CADDR(oidx, options)\ ((caddr_t)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options))) /* * return true if the src route has run out of routes this is true if the * offset of next route is greater than the end of the rt */ #define CLNPSRCRT_TERM(oidx, options)\ (CLNPSRCRT_OFF(oidx, options) > oidx->cni_srcrt_len) /* * Options a user can set/get */ #define CLNPOPT_FLAGS 0x01 /* flags: seg permitted, no er xmit, etc */ #define CLNPOPT_OPTS 0x02 /* datagram options */ /* * Values for particular datagram options */ #define CLNPOVAL_PAD 0xcc /* padding */ #define CLNPOVAL_SECURE 0xc5 /* security */ #define CLNPOVAL_SRCRT 0xc8 /* source routing */ #define CLNPOVAL_RECRT 0xcb /* record route */ #define CLNPOVAL_QOS 0xc3 /* quality of service */ #define CLNPOVAL_PRIOR 0xcd /* priority */ #define CLNPOVAL_ERREAS 0xc1 /* ER PDU ONLY: reason for discard */ #define CLNPOVAL_SRCSPEC 0x40 /* source address specific */ #define CLNPOVAL_DSTSPEC 0x80 /* destination address specific */ #define CLNPOVAL_GLOBAL 0xc0 /* globally unique */ /* Globally Unique QOS */ #define CLNPOVAL_SEQUENCING 0x10 /* sequencing preferred */ #define CLNPOVAL_CONGESTED 0x08 /* congestion experienced */ #define CLNPOVAL_LOWDELAY 0x04 /* low transit delay */ #define CLNPOVAL_PARTRT 0x00 /* partial source routing */ #define CLNPOVAL_COMPRT 0x01 /* complete source routing */ /* * Clnp flags used in a control block flags field. * NOTE: these must be out of the range of bits defined in ../net/raw_cb.h */ #define CLNP_NO_SEG 0x010 /* segmentation not permitted */ #define CLNP_NO_ER 0x020 /* do not generate ERs */ #define CLNP_SEND_RAW 0x080 /* send pkt as RAW DT not TP DT */ #define CLNP_NO_CKSUM 0x100 /* don't use clnp checksum */ #define CLNP_ECHO 0x200 /* send echo request */ #define CLNP_NOCACHE 0x400 /* don't store cache information */ #define CLNP_ECHOR 0x800 /* send echo reply */ /* valid clnp flags */ #define CLNP_VFLAGS \ (CLNP_SEND_RAW|CLNP_NO_SEG|CLNP_NO_ER|CLNP_NO_CKSUM|\ CLNP_ECHO|CLNP_NOCACHE|CLNP_ECHOR) /* * Constants used by clnp */ #define CLNP_HDR_MIN (sizeof (struct clnp_fixed)) #define CLNP_HDR_MAX (254) #define CLNP_TTL_UNITS 2 /* 500 milliseconds */ #define CLNP_TTL 15*CLNP_TTL_UNITS /* time to live (seconds) */ #define ISO8473_V1 0x01 /* * Clnp packet types * In order to test raw clnp and tp/clnp simultaneously, a third type of * packet has been defined: CLNP_RAW. This is done so that the input * routine can switch to the correct input routine (rclnp_input or * tpclnp_input) based on the type field. If clnp had a higher level * protocol field, this would not be necessary. */ #define CLNP_DT 0x1C /* normal data */ #define CLNP_ER 0x01 /* error report */ #define CLNP_RAW 0x1D /* debug only */ #define CLNP_EC 0x1E /* echo packet */ #define CLNP_ECR 0x1F /* echo reply */ /* * ER pdu error codes */ #define GEN_NOREAS 0x00 /* reason not specified */ #define GEN_PROTOERR 0x01 /* protocol procedure error */ #define GEN_BADCSUM 0x02 /* incorrect checksum */ #define GEN_CONGEST 0x03 /* pdu discarded due to congestion */ #define GEN_HDRSYNTAX 0x04 /* header syntax error */ #define GEN_SEGNEEDED 0x05 /* need segmentation but not allowed */ #define GEN_INCOMPLETE 0x06 /* incomplete pdu received */ #define GEN_DUPOPT 0x07 /* duplicate option */ /* address errors */ #define ADDR_DESTUNREACH 0x80 /* destination address unreachable */ #define ADDR_DESTUNKNOWN 0x81 /* destination address unknown */ /* source routing */ #define SRCRT_UNSPECERR 0x90 /* unspecified src rt error */ #define SRCRT_SYNTAX 0x91 /* syntax error in src rt field */ #define SRCRT_UNKNOWNADDR 0x92 /* unknown addr in src rt field */ #define SRCRT_BADPATH 0x93 /* path not acceptable */ /* lifetime */ #define TTL_EXPTRANSIT 0xa0 /* lifetime expired during transit */ #define TTL_EXPREASS 0xa1 /* lifetime expired during reassembly */ /* pdu discarded */ #define DISC_UNSUPPOPT 0xb0 /* unsupported option not specified? */ #define DISC_UNSUPPVERS 0xb1 /* unsupported protocol version */ #define DISC_UNSUPPSECURE 0xb2 /* unsupported security option */ #define DISC_UNSUPPSRCRT 0xb3 /* unsupported src rt option */ #define DISC_UNSUPPRECRT 0xb4 /* unsupported rec rt option */ /* reassembly */ #define REASS_INTERFERE 0xc0 /* reassembly interference */ #define CLNP_ERRORS 22 #ifdef CLNP_ER_CODES u_char clnp_er_codes[CLNP_ERRORS] = { GEN_NOREAS, GEN_PROTOERR, GEN_BADCSUM, GEN_CONGEST, GEN_HDRSYNTAX, GEN_SEGNEEDED, GEN_INCOMPLETE, GEN_DUPOPT, ADDR_DESTUNREACH, ADDR_DESTUNKNOWN, SRCRT_UNSPECERR, SRCRT_SYNTAX, SRCRT_UNKNOWNADDR, SRCRT_BADPATH, TTL_EXPTRANSIT, TTL_EXPREASS, DISC_UNSUPPOPT, DISC_UNSUPPVERS, DISC_UNSUPPSECURE, DISC_UNSUPPSRCRT, DISC_UNSUPPRECRT, REASS_INTERFERE }; #endif #ifdef TROLL #define TR_DUPEND 0x01 /* duplicate end of fragment */ #define TR_DUPPKT 0x02 /* duplicate entire packet */ #define TR_DROPPKT 0x04 /* drop packet on output */ #define TR_TRIM 0x08 /* trim bytes from packet */ #define TR_CHANGE 0x10 /* change bytes in packet */ #define TR_MTU 0x20 /* delta to change device mtu */ #define TR_CHUCK 0x40 /* drop packet in rclnp_input */ #define TR_BLAST 0x80 /* force rclnp_output to blast many * packet */ #define TR_RAWLOOP 0x100 /* make if_loop call clnpintr * directly */ struct troll { int tr_ops; /* operations to perform */ float tr_dup_size; /* % to duplicate */ float tr_dup_freq; /* frequency to duplicate packets */ float tr_drop_freq; /* frequence to drop packets */ int tr_mtu_adj; /* delta to adjust if mtu */ int tr_blast_cnt; /* # of pkts to blast out */ }; #define SN_OUTPUT(clcp, m)\ troll_output(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) #define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))\ - trollctl.tr_mtu_adj) #ifdef _KERNEL extern float troll_random; #endif #else /* NO TROLL */ #define SN_OUTPUT(clcp, m)\ (*clcp->clc_ifp->if_output)(clcp->clc_ifp, m, clcp->clc_firsthop, \ clcp->clc_rt) #define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))) #endif /* TROLL */ /* * Macro to remove an address from a clnp header */ #define CLNP_EXTRACT_ADDR(isoa, hoff, hend)\ {\ isoa.isoa_len = (u_char)*hoff;\ if ((((++hoff) + isoa.isoa_len) > hend) ||\ (isoa.isoa_len > 20) || (isoa.isoa_len == 0)) {\ hoff = (caddr_t)0;\ } else {\ (void) bcopy(hoff, (caddr_t)isoa.isoa_genaddr, \ isoa.isoa_len);\ hoff += isoa.isoa_len;\ }\ } /* * Macro to insert an address into a clnp header */ #define CLNP_INSERT_ADDR(hoff, isoa)\ *hoff++ = (isoa).isoa_len;\ (void) bcopy((caddr_t)((isoa).isoa_genaddr), hoff, (isoa).isoa_len);\ hoff += (isoa).isoa_len; /* * Clnp hdr cache. Whenever a clnp packet is sent, a copy of the * header is made and kept in this cache. In addition to a copy of * the cached clnp hdr, the cache contains * information necessary to determine whether the new packet * to send requires a new header to be built. */ struct clnp_cache { /* these fields are used to check the validity of the cache */ struct iso_addr clc_dst;/* destination of packet */ struct mbuf *clc_options; /* ptr to options mbuf */ int clc_flags; /* flags passed to clnp_output */ /* these fields are state that clnp_output requires to finish the pkt */ int clc_segoff; /* offset of seg part of header */ struct rtentry *clc_rt; /* ptr to rtentry (points into the route * structure) */ struct sockaddr *clc_firsthop; /* first hop of packet */ struct ifnet *clc_ifp;/* ptr to interface structure */ struct iso_ifaddr *clc_ifa;/* ptr to interface address */ struct mbuf *clc_hdr;/* cached pkt hdr (finally)! */ }; #ifdef _KERNEL struct iso_addr; struct sockaddr_iso; struct mbuf; struct clnp_segment; struct sockaddr; struct rt_entry; struct clnp_fragl; struct clnp_optidx; struct isopcb; struct snpa_hdr; struct iso_ifaddr; struct route_iso; /* clnp_debug.c */ char *clnp_hexp __P((char *, int, char *)); char *clnp_iso_addrp __P((struct iso_addr *)); char *clnp_saddr_isop __P((struct sockaddr_iso *)); /* clnp_er.c */ void clnp_er_input __P((struct mbuf *, struct iso_addr *, u_int)); void clnp_discard __P((struct mbuf *, u_int)); void clnp_emit_er __P((struct mbuf *, u_int)); int clnp_er_index __P((u_int)); int clnp_fragment __P((struct ifnet *, struct mbuf *, struct sockaddr *, int, int, int, struct rtentry *)); struct mbuf *clnp_reass __P((struct mbuf *, struct iso_addr *, struct iso_addr *, struct clnp_segment *)); int clnp_newpkt __P((struct mbuf *, struct iso_addr *, struct iso_addr *, struct clnp_segment *)); void clnp_insert_frag __P((struct clnp_fragl *, struct mbuf *, struct clnp_segment *)); struct mbuf *clnp_comp_pdu __P((struct clnp_fragl *)); #ifdef TROLL float troll_random __P((void)); int troll_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); #endif /* clnp_input.c */ void clnp_init __P((void)); void clnlintr __P((void)); void clnp_input __P((struct mbuf *, ...)); /* clnp_options.c */ void clnp_update_srcrt __P((struct mbuf *, struct clnp_optidx *)); void clnp_dooptions __P((struct mbuf *, struct clnp_optidx *, struct ifnet *, struct iso_addr *)); int clnp_set_opts __P((struct mbuf **, struct mbuf **)); int clnp_opt_sanity __P((struct mbuf *, caddr_t, int, struct clnp_optidx *)); /* clnp_output.c */ int clnp_output __P((struct mbuf *, ...)); void clnp_ctloutput __P((void)); /* clnp_raw.c */ void rclnp_input __P((struct mbuf *, ...)); int rclnp_output __P((struct mbuf *, ...)); int rclnp_ctloutput __P((int, struct socket *, int, int, struct mbuf **)); int clnp_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *)); /* clnp_subr.c */ struct mbuf *clnp_data_ck __P((struct mbuf *, int)); caddr_t clnp_extract_addr __P((caddr_t, int, struct iso_addr *, struct iso_addr *)); int clnp_ours __P((struct iso_addr *)); void clnp_forward __P((struct mbuf *, int, struct iso_addr *, struct clnp_optidx *, int, struct snpa_hdr *)); caddr_t clnp_insert_addr __P((caddr_t, struct iso_addr *, struct iso_addr *)); int clnp_route __P((struct iso_addr *, struct route_iso *, int, struct sockaddr **, struct iso_ifaddr **)); int clnp_srcroute __P((struct mbuf *, struct clnp_optidx *, struct route_iso *, struct sockaddr **, struct iso_ifaddr **, struct iso_addr *)); int clnp_echoreply __P((struct mbuf *, int, struct sockaddr_iso *, struct sockaddr_iso *, struct clnp_optidx *)); int clnp_badmtu __P((struct ifnet *, struct rtentry *, int, char *)); void clnp_ypocb __P((caddr_t, caddr_t, u_int)); /* clnp_timer.c */ struct clnp_fragl *clnp_freefrags __P((struct clnp_fragl *)); void clnp_slowtimo __P((void)); void clnp_drain __P((void)); #ifdef TROLL struct troll trollctl; #endif /* TROLL */ #endif /* _KERNEL */ quagga-0.99.24.1/babeld/0000755000175000017500000000000012476521356011530 500000000000000quagga-0.99.24.1/babeld/babel_main.c0000644000175000017500000003540112476520570013665 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* include zebra library */ #include #include "getopt.h" #include "if.h" #include "log.h" #include "thread.h" #include "privs.h" #include "sigevent.h" #include "version.h" #include "command.h" #include "vty.h" #include "memory.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "message.h" #include "resend.h" #include "babel_zebra.h" static void babel_init (int argc, char **argv); static char *babel_get_progname(char *argv_0); static void babel_fail(void); static void babel_init_random(void); static void babel_replace_by_null(int fd); static void babel_init_signals(void); static void babel_exit_properly(void); static void babel_save_state_file(void); struct thread_master *master; /* quagga's threads handler */ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ int debug = 0; int resend_delay = -1; static const char *pidfile = PATH_BABELD_PID; const unsigned char zeroes[16] = {0}; const unsigned char ones[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; static const char *state_file = DAEMON_VTY_DIR "/babel-state"; unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ int protocol_socket = -1; /* socket: communicate with others babeld */ static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; static char *babel_config_file = NULL; static char *babel_vty_addr = NULL; static int babel_vty_port = BABEL_VTY_PORT; /* Babeld options. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* babeld privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; static struct zebra_privs_t babeld_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; int main(int argc, char **argv) { struct thread thread; /* and print banner too */ babel_init(argc, argv); while (thread_fetch (master, &thread)) { thread_call (&thread); } return 0; } static void babel_usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages Babel routing protocol.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* make initialisations witch don't need infos about kernel(interfaces, etc.) */ static void babel_init(int argc, char **argv) { int rc, opt; int do_daemonise = 0; char *progname = NULL; /* Set umask before anything for security */ umask (0027); progname = babel_get_progname(argv[0]); /* set default log (lib/log.h) */ zlog_default = openzlog(progname, ZLOG_BABEL, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* set log destination as stdout until the config file is read */ zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); babel_init_random(); /* set the Babel's default link-local multicast address and Babel's port */ parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); protocol_port = 6696; /* get options */ while(1) { opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); if(opt < 0) break; switch(opt) { case 0: break; case 'd': do_daemonise = -1; break; case 'f': babel_config_file = optarg; break; case 'i': pidfile = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'A': babel_vty_addr = optarg; break; case 'P': babel_vty_port = atoi (optarg); if (babel_vty_port <= 0 || babel_vty_port > 0xffff) babel_vty_port = BABEL_VTY_PORT; break; case 'u': babeld_privs.user = optarg; break; case 'g': babeld_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': babel_usage (progname, 0); break; default: babel_usage (progname, 1); break; } } /* create the threads handler */ master = thread_master_create (); /* Library inits. */ zprivs_init (&babeld_privs); babel_init_signals(); cmd_init (1); vty_init (master); memory_init (); resend_delay = BABEL_DEFAULT_RESEND_DELAY; babel_replace_by_null(STDIN_FILENO); if (do_daemonise && daemonise() < 0) { zlog_err("daemonise: %s", safe_strerror(errno)); exit (1); } /* write pid file */ if (pid_output(pidfile) < 0) { zlog_err("error while writing pidfile"); exit (1); }; /* init some quagga's dependencies, and babeld's commands */ babeld_quagga_init(); /* init zebra client's structure and it's commands */ /* this replace kernel_setup && kernel_setup_socket */ babelz_zebra_init (); /* Get zebra configuration file. */ zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); vty_read_config (babel_config_file, babel_config_default); /* Create VTY socket */ vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); /* init buffer */ rc = resize_receive_buffer(1500); if(rc < 0) babel_fail(); schedule_neighbours_check(5000, 1); zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port); } /* return the progname (without path, example: "./x/progname" --> "progname") */ static char * babel_get_progname(char *argv_0) { char *p = strrchr (argv_0, '/'); return (p ? ++p : argv_0); } static void babel_fail(void) { exit(1); } /* initialize random value, and set 'babel_now' by the way. */ static void babel_init_random(void) { gettime(&babel_now); int rc; unsigned int seed; rc = read_random_bytes(&seed, sizeof(seed)); if(rc < 0) { zlog_err("read(random): %s", safe_strerror(errno)); seed = 42; } seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); srandom(seed); } /* close fd, and replace it by "/dev/null" exit if error */ static void babel_replace_by_null(int fd) { int fd_null; int rc; fd_null = open("/dev/null", O_RDONLY); if(fd_null < 0) { zlog_err("open(null): %s", safe_strerror(errno)); exit(1); } rc = dup2(fd_null, fd); if(rc < 0) { zlog_err("dup2(null, 0): %s", safe_strerror(errno)); exit(1); } close(fd_null); } /* Load the state file: check last babeld's running state, usefull in case of "/etc/init.d/babeld restart" */ void babel_load_state_file(void) { int fd; int rc; fd = open(state_file, O_RDONLY); if(fd < 0 && errno != ENOENT) zlog_err("open(babel-state: %s)", safe_strerror(errno)); rc = unlink(state_file); if(fd >= 0 && rc < 0) { zlog_err("unlink(babel-state): %s", safe_strerror(errno)); /* If we couldn't unlink it, it's probably stale. */ close(fd); fd = -1; } if(fd >= 0) { char buf[100]; char buf2[100]; int s; long t; rc = read(fd, buf, 99); if(rc < 0) { zlog_err("read(babel-state): %s", safe_strerror(errno)); } else { buf[rc] = '\0'; rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); if(rc == 3 && s >= 0 && s <= 0xFFFF) { unsigned char sid[8]; rc = parse_eui64(buf2, sid); if(rc < 0) { zlog_err("Couldn't parse babel-state."); } else { struct timeval realnow; debugf(BABEL_DEBUG_COMMON, "Got %s %d %ld from babel-state.", format_eui64(sid), s, t); gettimeofday(&realnow, NULL); if(memcmp(sid, myid, 8) == 0) myseqno = seqno_plus(s, 1); else zlog_err("ID mismatch in babel-state. id=%s; old=%s", format_eui64(myid), format_eui64(sid)); } } else { zlog_err("Couldn't parse babel-state."); } } close(fd); fd = -1; } } static void babel_sigexit(void) { zlog_notice("Terminating on signal"); babel_exit_properly(); } static void babel_sigusr1 (void) { zlog_rotate (NULL); } static void babel_init_signals(void) { static struct quagga_signal_t babel_signals[] = { { .signal = SIGUSR1, .handler = &babel_sigusr1, }, { .signal = SIGINT, .handler = &babel_sigexit, }, { .signal = SIGTERM, .handler = &babel_sigexit, }, }; signal_init (master, array_size(babel_signals), babel_signals); } static void babel_exit_properly(void) { debugf(BABEL_DEBUG_COMMON, "Exiting..."); usleep(roughly(10000)); gettime(&babel_now); /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); flush_all_routes(); babel_interface_close_all(); babel_zebra_close_connexion(); babel_save_state_file(); debugf(BABEL_DEBUG_COMMON, "Remove pid file."); if(pidfile) unlink(pidfile); debugf(BABEL_DEBUG_COMMON, "Done."); exit(0); } static void babel_save_state_file(void) { int fd; int rc; debugf(BABEL_DEBUG_COMMON, "Save state file."); fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); if(fd < 0) { zlog_err("creat(babel-state): %s", safe_strerror(errno)); unlink(state_file); } else { struct timeval realnow; char buf[100]; gettimeofday(&realnow, NULL); rc = snprintf(buf, 100, "%s %d %ld\n", format_eui64(myid), (int)myseqno, (long)realnow.tv_sec); if(rc < 0 || rc >= 100) { zlog_err("write(babel-state): overflow."); unlink(state_file); } else { rc = write(fd, buf, rc); if(rc < 0) { zlog_err("write(babel-state): %s", safe_strerror(errno)); unlink(state_file); } fsync(fd); } close(fd); } } void show_babel_main_configuration (struct vty *vty) { vty_out(vty, "pid file = %s%s" "state file = %s%s" "configuration file = %s%s" "protocol informations:%s" " multicast address = %s%s" " port = %d%s" "vty address = %s%s" "vty port = %d%s" "id = %s%s" "allow_duplicates = %s%s" "kernel_metric = %d%s", pidfile, VTY_NEWLINE, state_file, VTY_NEWLINE, babel_config_file ? babel_config_file : babel_config_default, VTY_NEWLINE, VTY_NEWLINE, format_address(protocol_group), VTY_NEWLINE, protocol_port, VTY_NEWLINE, babel_vty_addr ? babel_vty_addr : "None", VTY_NEWLINE, babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, kernel_metric, VTY_NEWLINE); } quagga-0.99.24.1/babeld/babel_filter.c0000644000175000017500000001136612476520570014232 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "babel_filter.h" #include "vty.h" #include "filter.h" #include "log.h" #include "plist.h" #include "distribute.h" #include "util.h" int babel_filter(int output, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { struct interface *ifp = if_lookup_by_index(ifindex); babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL; struct prefix p; struct distribute *dist; struct access_list *alist; struct prefix_list *plist; int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN; int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) uchar_to_inaddr(&p.u.prefix4, prefix); else uchar_to_in6addr(&p.u.prefix6, prefix); if (babel_ifp != NULL && babel_ifp->list[filter]) { if (access_list_apply (babel_ifp->list[filter], &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } if (babel_ifp != NULL && babel_ifp->prefix[filter]) { if (prefix_list_apply (babel_ifp->prefix[filter], &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[distribute]) { alist = access_list_lookup (AFI_IP6, dist->list[distribute]); if (alist) { if (access_list_apply (alist, &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } } if (dist->prefix[distribute]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); if (plist) { if (prefix_list_apply (plist, &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", p.family == AF_INET ? inet_ntoa(p.u.prefix4) : inet6_ntoa (p.u.prefix6), p.prefixlen); return INFINITY; } } } } return 0; } quagga-0.99.24.1/babeld/babeld.c0000644000175000017500000005223612476520570013032 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "command.h" #include "prefix.h" #include "memory.h" #include "memtypes.h" #include "table.h" #include "distribute.h" #include "prefix.h" #include "filter.h" #include "plist.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "net.h" #include "kernel.h" #include "babel_interface.h" #include "neighbour.h" #include "route.h" #include "message.h" #include "resend.h" #include "babel_filter.h" #include "babel_zebra.h" static int babel_init_routing_process(struct thread *thread); static void babel_get_myid(void); static void babel_initial_noise(void); static int babel_read_protocol (struct thread *thread); static int babel_main_loop(struct thread *thread); static void babel_set_timer(struct timeval *timeout); static void babel_fill_with_next_timeout(struct timeval *tv); /* Informations relative to the babel running daemon. */ static struct babel *babel_routing_process = NULL; static unsigned char *receive_buffer = NULL; static int receive_buffer_size = 0; /* timeouts */ struct timeval check_neighbours_timeout; static time_t expiry_time; static time_t source_expiry_time; /* Babel node structure. */ static struct cmd_node cmd_babel_node = { .node = BABEL_NODE, .prompt = "%s(config-router)# ", .vtysh = 1, }; /* print current babel configuration on vty */ static int babel_config_write (struct vty *vty) { int lines = 0; int i; /* list enabled debug modes */ lines += debug_babel_config_write (vty); if (!babel_routing_process) return lines; vty_out (vty, "router babel%s", VTY_NEWLINE); if (resend_delay != BABEL_DEFAULT_RESEND_DELAY) { vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE); lines++; } /* list enabled interfaces */ lines = 1 + babel_enable_if_config_write (vty); /* list redistributed protocols */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) { vty_out (vty, " redistribute %s%s", zebra_route_string (i), VTY_NEWLINE); lines++; } return lines; } static int babel_create_routing_process (void) { assert (babel_routing_process == NULL); /* Allocaste Babel instance. */ babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel)); /* Initialize timeouts */ gettime(&babel_now); expiry_time = babel_now.tv_sec + roughly(30); source_expiry_time = babel_now.tv_sec + roughly(300); /* Make socket for Babel protocol. */ protocol_socket = babel_socket(protocol_port); if (protocol_socket < 0) { zlog_err("Couldn't create link local socket: %s", safe_strerror(errno)); goto fail; } /* Threads. */ babel_routing_process->t_read = thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); /* wait a little: zebra will announce interfaces, addresses, routes... */ babel_routing_process->t_update = thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L); return 0; fail: XFREE(MTYPE_BABEL, babel_routing_process); babel_routing_process = NULL; return -1; } /* thread reading entries form others babel daemons */ static int babel_read_protocol (struct thread *thread) { int rc; struct interface *ifp = NULL; struct sockaddr_in6 sin6; struct listnode *linklist_node = NULL; assert(babel_routing_process != NULL); assert(protocol_socket >= 0); rc = babel_recv(protocol_socket, receive_buffer, receive_buffer_size, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) { if(errno != EAGAIN && errno != EINTR) { zlog_err("recv: %s", safe_strerror(errno)); } } else { FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; if(ifp->ifindex == sin6.sin6_scope_id) { parse_packet((unsigned char*)&sin6.sin6_addr, ifp, receive_buffer, rc); break; } } } /* re-add thread */ babel_routing_process->t_read = thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); return 0; } /* Zebra will give some information, especially about interfaces. This function must be call with a litte timeout wich may give zebra the time to do his job, making these inits have sense. */ static int babel_init_routing_process(struct thread *thread) { myseqno = (random() & 0xFFFF); babel_get_myid(); babel_load_state_file(); debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); babel_initial_noise(); babel_main_loop(thread);/* this function self-add to the t_update thread */ return 0; } /* fill "myid" with an unique id (only if myid != {0}). */ static void babel_get_myid(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; int rc; int i; /* if we already have an id (from state file), we return. */ if (memcmp(myid, zeroes, 8) != 0) { return; } FOR_ALL_INTERFACES(ifp, linklist_node) { /* ifp->ifindex is not necessarily valid at this point */ int ifindex = if_nametoindex(ifp->name); if(ifindex > 0) { unsigned char eui[8]; rc = if_eui64(ifp->name, ifindex, eui); if(rc < 0) continue; memcpy(myid, eui, 8); return; } } /* We failed to get a global EUI64 from the interfaces we were given. Let's try to find an interface with a MAC address. */ for(i = 1; i < 256; i++) { char buf[IF_NAMESIZE], *ifname; unsigned char eui[8]; ifname = if_indextoname(i, buf); if(ifname == NULL) continue; rc = if_eui64(ifname, i, eui); if(rc < 0) continue; memcpy(myid, eui, 8); return; } zlog_err("Warning: couldn't find router id -- using random value."); rc = read_random_bytes(myid, 8); if(rc < 0) { zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno)); exit(1); } /* Clear group and global bits */ myid[0] &= ~3; } /* Make some noise so that others notice us, and send retractions in case we were restarted recently */ static void babel_initial_noise(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; /* Apply jitter before we send the first message. */ usleep(roughly(10000)); gettime(&babel_now); send_hello(ifp); send_wildcard_retraction(ifp); } FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; usleep(roughly(10000)); gettime(&babel_now); send_hello(ifp); send_wildcard_retraction(ifp); send_self_update(ifp); send_request(ifp, NULL, 0); flushupdates(ifp); flushbuf(ifp); } } /* Delete all the added babel routes, make babeld only speak to zebra. */ static void babel_clean_routing_process() { flush_all_routes(); babel_interface_close_all(); /* cancel threads */ if (babel_routing_process->t_read != NULL) { thread_cancel(babel_routing_process->t_read); } if (babel_routing_process->t_update != NULL) { thread_cancel(babel_routing_process->t_update); } XFREE(MTYPE_BABEL, babel_routing_process); babel_routing_process = NULL; } /* Function used with timeout. */ static int babel_main_loop(struct thread *thread) { struct timeval tv; struct interface *ifp = NULL; struct listnode *linklist_node = NULL; while(1) { gettime(&babel_now); /* timeouts --------------------------------------------------------- */ /* get the next timeout */ babel_fill_with_next_timeout(&tv); /* if there is no timeout, we must wait. */ if(timeval_compare(&tv, &babel_now) > 0) { timeval_minus(&tv, &tv, &babel_now); debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs", tv.tv_sec * 1000 + tv.tv_usec / 1000); /* it happens often to have less than 1 ms, it's bad. */ timeval_add_msec(&tv, &tv, 300); babel_set_timer(&tv); return 0; } gettime(&babel_now); /* update database -------------------------------------------------- */ if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) { int msecs; msecs = check_neighbours(); msecs = MAX(msecs, 10); schedule_neighbours_check(msecs, 1); } if(babel_now.tv_sec >= expiry_time) { expire_routes(); expire_resend(); expiry_time = babel_now.tv_sec + roughly(30); } if(babel_now.tv_sec >= source_expiry_time) { expire_sources(); source_expiry_time = babel_now.tv_sec + roughly(300); } FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0) send_hello(ifp); if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0) send_update(ifp, 0, NULL, 0); if(timeval_compare(&babel_now, &babel_ifp->update_flush_timeout) >= 0) flushupdates(ifp); } if(resend_time.tv_sec != 0) { if(timeval_compare(&babel_now, &resend_time) >= 0) do_resend(); } if(unicast_flush_timeout.tv_sec != 0) { if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0) flush_unicast(1); } FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->flush_timeout.tv_sec != 0) { if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0) flushbuf(ifp); } } } assert(0); /* this line should never be reach */ } static void printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname) { static struct timeval curr_tv; static char buffer[200]; static const char *curr_tag = NULL; switch (cmd) { case 0: /* reset timeval */ curr_tv = *tv; if(ifname != NULL) { snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); curr_tag = buffer; } else { curr_tag = tag; } break; case 1: /* take the min */ if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */ break; } if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec && tv->tv_usec < curr_tv.tv_usec)) { curr_tv = *tv; if(ifname != NULL) { snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); curr_tag = buffer; } else { curr_tag = tag; } } break; case 2: /* print message */ debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag); break; default: break; } } static void babel_fill_with_next_timeout(struct timeval *tv) { #if (defined NO_DEBUG) #define printIfMin(a,b,c,d) #else #define printIfMin(a,b,c,d) \ if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);} struct interface *ifp = NULL; struct listnode *linklist_node = NULL; *tv = check_neighbours_timeout; printIfMin(tv, 0, "check_neighbours_timeout", NULL); timeval_min_sec(tv, expiry_time); printIfMin(tv, 1, "expiry_time", NULL); timeval_min_sec(tv, source_expiry_time); printIfMin(tv, 1, "source_expiry_time", NULL); timeval_min(tv, &resend_time); printIfMin(tv, 1, "resend_time", NULL); FOR_ALL_INTERFACES(ifp, linklist_node) { babel_interface_nfo *babel_ifp = NULL; if(!if_up(ifp)) continue; babel_ifp = babel_get_if_nfo(ifp); timeval_min(tv, &babel_ifp->flush_timeout); printIfMin(tv, 1, "flush_timeout", ifp->name); timeval_min(tv, &babel_ifp->hello_timeout); printIfMin(tv, 1, "hello_timeout", ifp->name); timeval_min(tv, &babel_ifp->update_timeout); printIfMin(tv, 1, "update_timeout", ifp->name); timeval_min(tv, &babel_ifp->update_flush_timeout); printIfMin(tv, 1, "update_flush_timeout",ifp->name); } timeval_min(tv, &unicast_flush_timeout); printIfMin(tv, 1, "unicast_flush_timeout", NULL); printIfMin(tv, 2, NULL, NULL); #undef printIfMin #endif } /* set the t_update thread of the babel routing process to be launch in 'timeout' (approximate at the milisecond) */ static void babel_set_timer(struct timeval *timeout) { long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; if (babel_routing_process->t_update != NULL) { thread_cancel(babel_routing_process->t_update); } babel_routing_process->t_update = thread_add_timer_msec(master, &babel_main_loop, NULL, msecs); } /* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */ void schedule_neighbours_check(int msecs, int override) { struct timeval timeout; timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2)); if(override) check_neighbours_timeout = timeout; else timeval_min(&check_neighbours_timeout, &timeout); } int resize_receive_buffer(int size) { if(size <= receive_buffer_size) return 0; if(receive_buffer == NULL) { receive_buffer = malloc(size); if(receive_buffer == NULL) { zlog_err("malloc(receive_buffer): %s", safe_strerror(errno)); return -1; } receive_buffer_size = size; } else { unsigned char *new; new = realloc(receive_buffer, size); if(new == NULL) { zlog_err("realloc(receive_buffer): %s", safe_strerror(errno)); return -1; } receive_buffer = new; receive_buffer_size = size; } return 1; } static void babel_distribute_update (struct distribute *dist) { struct interface *ifp; babel_interface_nfo *babel_ifp; struct access_list *alist; struct prefix_list *plist; if (! dist->ifname) return; ifp = if_lookup_by_name (dist->ifname); if (ifp == NULL) return; babel_ifp = babel_get_if_nfo(ifp); if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) babel_ifp->list[BABEL_FILTER_IN] = alist; else babel_ifp->list[BABEL_FILTER_IN] = NULL; } else { babel_ifp->list[BABEL_FILTER_IN] = NULL; } if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) babel_ifp->list[BABEL_FILTER_OUT] = alist; else babel_ifp->list[BABEL_FILTER_OUT] = NULL; } else { babel_ifp->list[BABEL_FILTER_OUT] = NULL; } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); if (plist) babel_ifp->prefix[BABEL_FILTER_IN] = plist; else babel_ifp->prefix[BABEL_FILTER_IN] = NULL; } else { babel_ifp->prefix[BABEL_FILTER_IN] = NULL; } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); if (plist) babel_ifp->prefix[BABEL_FILTER_OUT] = plist; else babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; } else { babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; } } static void babel_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) babel_distribute_update (dist); } /* Update all interface's distribute list. */ static void babel_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) babel_distribute_update_interface (ifp); } static void babel_distribute_update_all_wrapper (struct access_list *notused) { babel_distribute_update_all(NULL); } /* [Command] */ DEFUN (router_babel, router_babel_cmd, "router babel", "Enable a routing process\n" "Make Babel instance command\n" "No attributes\n") { int ret; vty->node = BABEL_NODE; if (!babel_routing_process) { ret = babel_create_routing_process (); /* Notice to user we couldn't create Babel. */ if (ret < 0) { zlog_warn ("can't create Babel"); return CMD_WARNING; } } return CMD_SUCCESS; } /* [Command] */ DEFUN (no_router_babel, no_router_babel_cmd, "no router babel", NO_STR "Disable a routing process\n" "Remove Babel instance command\n" "No attributes\n") { if(babel_routing_process) babel_clean_routing_process(); return CMD_SUCCESS; } /* [Babel Command] */ DEFUN (babel_set_resend_delay, babel_set_resend_delay_cmd, "babel resend-delay <20-655340>", "Babel commands\n" "Time before resending a message\n" "Milliseconds\n") { int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); resend_delay = interval; return CMD_SUCCESS; } void babeld_quagga_init(void) { install_node(&cmd_babel_node, &babel_config_write); install_element(CONFIG_NODE, &router_babel_cmd); install_element(CONFIG_NODE, &no_router_babel_cmd); install_default(BABEL_NODE); install_element(BABEL_NODE, &babel_set_resend_delay_cmd); babel_if_init(); /* Access list install. */ access_list_init (); access_list_add_hook (babel_distribute_update_all_wrapper); access_list_delete_hook (babel_distribute_update_all_wrapper); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (babel_distribute_update_all); prefix_list_delete_hook (babel_distribute_update_all); /* Distribute list install. */ distribute_list_init (BABEL_NODE); distribute_list_add_hook (babel_distribute_update); distribute_list_delete_hook (babel_distribute_update); } /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, const unsigned char *neigh, unsigned int ifindex) { return babel_filter(0, prefix, plen, ifindex); } int output_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { return babel_filter(1, prefix, plen, ifindex); } /* There's no redistribute filter in Quagga -- the zebra daemon does its own filtering. */ int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto) { return 0; } quagga-0.99.24.1/babeld/babel_interface.c0000644000175000017500000007165412476520570014713 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "memory.h" #include "log.h" #include "command.h" #include "prefix.h" #include "vector.h" #include "distribute.h" #include "babel_main.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "message.h" #include "route.h" #include "babel_zebra.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) static int babel_enable_if_lookup (const char *ifname); static int babel_enable_if_add (const char *ifname); static int babel_enable_if_delete (const char *ifname); static int interface_recalculate(struct interface *ifp); static int interface_reset(struct interface *ifp); static int babel_if_new_hook (struct interface *ifp); static int babel_if_delete_hook (struct interface *ifp); static int interface_config_write (struct vty *vty); static babel_interface_nfo * babel_interface_allocate (void); static void babel_interface_free (babel_interface_nfo *bi); static vector babel_enable_if; /* enable interfaces (by cmd). */ static struct cmd_node babel_interface_node = /* babeld's interface node. */ { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; int babel_interface_up (int cmd, struct zclient *client, zebra_size_t length) { struct stream *s = NULL; struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface up'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; } interface_recalculate(ifp); return 0; } int babel_interface_down (int cmd, struct zclient *client, zebra_size_t length) { struct stream *s = NULL; struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; } interface_reset(ifp); return 0; } int babel_interface_add (int cmd, struct zclient *client, zebra_size_t length) { struct interface *ifp = NULL; debugf(BABEL_DEBUG_IF, "receive a 'interface add'"); /* read and add the interface in the iflist. */ ifp = zebra_interface_add_read (zclient->ibuf); if (ifp == NULL) { return 0; } interface_recalculate(ifp); return 0; } int babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length) { struct interface *ifp; struct stream *s; debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); s = zclient->ibuf; ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) return 0; if (IS_ENABLE(ifp)) interface_reset(ifp); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } int babel_interface_address_add (int cmd, struct zclient *client, zebra_size_t length) { babel_interface_nfo *babel_ifp; struct connected *ifc; struct prefix *prefix; debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (ifc == NULL) return 0; prefix = ifc->address; if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { zlog_err("not einough memory"); } else { memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4); } } } send_request(ifc->ifp, NULL, 0); send_update(ifc->ifp, 0, NULL, 0); return 0; } int babel_interface_address_delete (int cmd, struct zclient *client, zebra_size_t length) { babel_interface_nfo *babel_ifp; struct connected *ifc; struct prefix *prefix; debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (ifc == NULL) return 0; prefix = ifc->address; if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) { free(babel_ifp->ipv4); babel_ifp->ipv4 = NULL; } } send_request(ifc->ifp, NULL, 0); send_update(ifc->ifp, 0, NULL, 0); return 0; } /* Lookup function. */ static int babel_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (babel_enable_if); i++) if ((str = vector_slot (babel_enable_if, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } /* Add interface to babel_enable_if. */ static int babel_enable_if_add (const char *ifname) { int ret; struct interface *ifp = NULL; ret = babel_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (babel_enable_if, strdup (ifname)); ifp = if_lookup_by_name(ifname); if (ifp != NULL) interface_recalculate(ifp); return 1; } /* Delete interface from babel_enable_if. */ static int babel_enable_if_delete (const char *ifname) { int babel_enable_if_index; char *str; struct interface *ifp = NULL; babel_enable_if_index = babel_enable_if_lookup (ifname); if (babel_enable_if_index < 0) return -1; str = vector_slot (babel_enable_if, babel_enable_if_index); free (str); vector_unset (babel_enable_if, babel_enable_if_index); ifp = if_lookup_by_name(ifname); if (ifp != NULL) interface_reset(ifp); return 1; } /* [Babel Command] Babel enable on specified interface or matched network. */ DEFUN (babel_network, babel_network_cmd, "network IF_OR_ADDR", "Enable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is: */ if (ret) /* an IPv4 or v6 network */ return CMD_ERR_NO_MATCH; /* not implemented yet */ else /* an interface name */ ret = babel_enable_if_add (argv[0]); if (ret < 0) { vty_out (vty, "There is same network configuration %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* [Babel Command] Babel enable on specified interface or matched network. */ DEFUN (no_babel_network, no_babel_network_cmd, "no network IF_OR_ADDR", NO_STR "Disable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is: */ if (ret) /* an IPv4 or v6 network */ return CMD_ERR_NO_MATCH; /* not implemented yet */ else /* an interface name */ ret = babel_enable_if_delete (argv[0]); if (ret < 0) { vty_out (vty, "can't find network %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* There are a number of interface parameters that must be changed when an interface becomes wired/wireless. In Quagga, they cannot be configured separately. */ static void babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired) { if(wired) { babel_ifp->flags |= BABEL_IF_WIRED; babel_ifp->cost = 96; babel_ifp->flags &= ~BABEL_IF_LQ; } else { babel_ifp->flags &= ~BABEL_IF_WIRED; babel_ifp->cost = 256; babel_ifp->flags |= BABEL_IF_LQ; } } /* [Interface Command] Tell the interface is wire. */ DEFUN (babel_set_wired, babel_set_wired_cmd, "babel wired", "Babel interface commands\n" "Enable wired optimisations") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_set_wired_internal(babel_ifp, 1); return CMD_SUCCESS; } /* [Interface Command] Tell the interface is wireless (default). */ DEFUN (babel_set_wireless, babel_set_wireless_cmd, "babel wireless", "Babel interface commands\n" "Disable wired optimiations (assume wireless)") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_set_wired_internal(babel_ifp, 0); return CMD_SUCCESS; } /* [Interface Command] Enable split horizon. */ DEFUN (babel_split_horizon, babel_split_horizon_cmd, "babel split-horizon", "Babel interface commands\n" "Enable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON; return CMD_SUCCESS; } /* [Interface Command] Disable split horizon (default). */ DEFUN (no_babel_split_horizon, no_babel_split_horizon_cmd, "no babel split-horizon", NO_STR "Babel interface commands\n" "Disable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON; return CMD_SUCCESS; } /* [Interface Command]. */ DEFUN (babel_set_hello_interval, babel_set_hello_interval_cmd, "babel hello-interval <20-655340>", "Babel interface commands\n" "Time between scheduled hellos\n" "Milliseconds\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->hello_interval = interval; return CMD_SUCCESS; } /* [Interface Command]. */ DEFUN (babel_set_update_interval, babel_set_update_interval_cmd, "babel update-interval <20-655340>", "Babel interface commands\n" "Time between scheduled updates\n" "Milliseconds\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; int interval; VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); babel_ifp->update_interval = interval; return CMD_SUCCESS; } /* This should be no more than half the hello interval, so that hellos aren't sent late. The result is in milliseconds. */ unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { unsigned interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else interval = MIN(interval, 4000); return roughly(interval) / 4; } unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { unsigned interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else interval = MIN(interval, 4000); return roughly(interval); } /* calculate babeld's specific datas of an interface (change when the interface change) */ static int interface_recalculate(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; if (!IS_ENABLE(ifp)) return -1; if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) { interface_reset(ifp); return -1; } babel_ifp->flags |= BABEL_IF_IS_UP; mtu = MIN(ifp->mtu, ifp->mtu6); /* We need to be able to fit at least two messages into a packet, so MTUs below 116 require lower layer fragmentation. */ /* In IPv6, the minimum MTU is 1280, and every host must be able to reassemble up to 1500 bytes, but I'd rather not rely on this. */ if(mtu < 128) { debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).", mtu, ifp->name, ifp->ifindex); mtu = 128; } /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ babel_ifp->bufsize = mtu - sizeof(packet_header) - 60; tmp = babel_ifp->sendbuf; babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize); if(babel_ifp->sendbuf == NULL) { zlog_err("Couldn't reallocate sendbuf."); free(tmp); babel_ifp->bufsize = 0; return -1; } tmp = NULL; resize_receive_buffer(mtu); memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) { zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s", ifp->name, safe_strerror(errno)); /* This is probably due to a missing link-local address, so down this interface, and wait until the main loop tries to up it again. */ interface_reset(ifp); return -1; } set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); send_hello(ifp); send_request(ifp, NULL, 0); update_interface_metric(ifp); debugf(BABEL_DEBUG_COMMON, "Upped interface %s (%s, cost=%d, channel=%d%s).", ifp->name, (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", babel_ifp->cost, babel_ifp->channel, babel_ifp->ipv4 ? ", IPv4" : ""); if(rc > 0) send_update(ifp, 0, NULL, 0); return 1; } /* Reset the interface as it was new: it's not removed from the interface list, and may be considered as a upped interface. */ static int interface_reset(struct interface *ifp) { int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if (!(babel_ifp->flags & BABEL_IF_IS_UP)) return 0; debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name); babel_ifp->flags &= ~BABEL_IF_IS_UP; flush_interface_routes(ifp, 0); babel_ifp->buffered = 0; babel_ifp->bufsize = 0; free(babel_ifp->sendbuf); babel_ifp->num_buffered_updates = 0; babel_ifp->update_bufsize = 0; if(babel_ifp->buffered_updates) free(babel_ifp->buffered_updates); babel_ifp->buffered_updates = NULL; babel_ifp->sendbuf = NULL; if(ifp->ifindex > 0) { memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s", ifp->name, safe_strerror(errno)); } update_interface_metric(ifp); debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).", ifp->name, (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", babel_ifp->cost, babel_ifp->ipv4 ? ", IPv4" : ""); return 1; } /* Send retraction to all, and reset all interfaces statistics. */ void babel_interface_close_all(void) { struct interface *ifp = NULL; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; send_wildcard_retraction(ifp); /* Make sure that we expire quickly from our neighbours' association caches. */ send_hello_noupdate(ifp, 10); flushbuf(ifp); usleep(roughly(1000)); gettime(&babel_now); } FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; /* Make sure they got it. */ send_wildcard_retraction(ifp); send_hello_noupdate(ifp, 1); flushbuf(ifp); usleep(roughly(10000)); gettime(&babel_now); interface_reset(ifp); } } /* return "true" if address is one of our ipv6 addresses */ int is_interface_ll_address(struct interface *ifp, const unsigned char *address) { struct connected *connected; struct listnode *node; if(!if_up(ifp)) return 0; FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) { if(connected->address->family == AF_INET6 && memcmp(&connected->address->u.prefix6, address, 16) == 0) return 1; } return 0; } static void show_babel_interface_sub (struct vty *vty, struct interface *ifp) { int is_up; babel_interface_nfo *babel_ifp; vty_out (vty, "%s is %s%s", ifp->name, ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); vty_out (vty, " ifindex %u, MTU %u bytes %s%s", ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE); if (babel_enable_if_lookup (ifp->name) < 0) { vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE); return; } if (!is_up) { vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE); return; } babel_ifp = babel_get_if_nfo (ifp); vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE); vty_out (vty, " Operating mode is \"%s\"%s", CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE); vty_out (vty, " Split horizon mode is %s%s", CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE); } DEFUN (show_babel_interface, show_babel_interface_cmd, "show babel interface [INTERFACE]", SHOW_STR IP_STR "Babel information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node; if (argc == 0) { for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) show_babel_interface_sub (vty, ifp); return CMD_SUCCESS; } if ((ifp = if_lookup_by_name (argv[0])) == NULL) { vty_out (vty, "No such interface name%s", VTY_NEWLINE); return CMD_WARNING; } show_babel_interface_sub (vty, ifp); return CMD_SUCCESS; } static void show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh) { vty_out (vty, "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s", format_address(neigh->address), neigh->ifp->name, neigh->reach, neighbour_rxcost(neigh), neigh->txcost, if_up(neigh->ifp) ? "" : " (down)", VTY_NEWLINE); } DEFUN (show_babel_neighbour, show_babel_neighbour_cmd, "show babel neighbour [INTERFACE]", SHOW_STR IP_STR "Babel information\n" "Print neighbours\n" "Interface name\n") { struct neighbour *neigh; struct interface *ifp; if (argc == 0) { FOR_ALL_NEIGHBOURS(neigh) { show_babel_neighbour_sub(vty, neigh); } return CMD_SUCCESS; } if ((ifp = if_lookup_by_name (argv[0])) == NULL) { vty_out (vty, "No such interface name%s", VTY_NEWLINE); return CMD_WARNING; } FOR_ALL_NEIGHBOURS(neigh) { if(ifp->ifindex == neigh->ifp->ifindex) { show_babel_neighbour_sub(vty, neigh); } } return CMD_SUCCESS; } static void show_babel_routes_sub (struct babel_route *route, void *closure) { struct vty *vty = (struct vty*) closure; const unsigned char *nexthop = memcmp(route->nexthop, route->neigh->address, 16) == 0 ? NULL : route->nexthop; char channels[100]; if(route->channels[0] == 0) channels[0] = '\0'; else { int k, j = 0; snprintf(channels, 100, " chan ("); j = strlen(channels); for(k = 0; k < DIVERSITY_HOPS; k++) { if(route->channels[k] == 0) break; if(k > 0) channels[j++] = ','; snprintf(channels + j, 100 - j, "%d", route->channels[k]); j = strlen(channels); } snprintf(channels + j, 100 - j, ")"); if(k == 0) channels[0] = '\0'; } vty_out(vty, "%s metric %d refmetric %d id %s seqno %d%s age %d " "via %s neigh %s%s%s%s%s", format_prefix(route->src->prefix, route->src->plen), route_metric(route), route->refmetric, format_eui64(route->src->id), (int)route->seqno, channels, (int)(babel_now.tv_sec - route->time), route->neigh->ifp->name, format_address(route->neigh->address), nexthop ? " nexthop " : "", nexthop ? format_address(nexthop) : "", route->installed ? " (installed)" : route_feasible(route) ? " (feasible)" : "", VTY_NEWLINE); } static void show_babel_xroutes_sub (struct xroute *xroute, void *closure) { struct vty *vty = (struct vty *) closure; vty_out(vty, "%s metric %d (exported)%s", format_prefix(xroute->prefix, xroute->plen), xroute->metric, VTY_NEWLINE); } DEFUN (show_babel_database, show_babel_database_cmd, "show babel database", SHOW_STR IP_STR "Babel information\n" "Database information\n" "No attributes\n") { for_all_routes(show_babel_routes_sub, vty); for_all_xroutes(show_babel_xroutes_sub, vty); return CMD_SUCCESS; } DEFUN (show_babel_parameters, show_babel_parameters_cmd, "show babel parameters", SHOW_STR IP_STR "Babel information\n" "Configuration information\n" "No attributes\n") { vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); show_babel_main_configuration(vty); vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE); config_show_distribute(vty); return CMD_SUCCESS; } void babel_if_init () { /* initialize interface list */ if_init(); if_add_hook (IF_NEW_HOOK, babel_if_new_hook); if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); babel_enable_if = vector_init (1); /* install interface node and commands */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_node (&babel_interface_node, interface_config_write); install_default(INTERFACE_NODE); install_element(INTERFACE_NODE, &interface_cmd); install_element(INTERFACE_NODE, &no_interface_cmd); install_element(BABEL_NODE, &babel_network_cmd); install_element(BABEL_NODE, &no_babel_network_cmd); install_element(INTERFACE_NODE, &babel_split_horizon_cmd); install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd); install_element(INTERFACE_NODE, &babel_set_wired_cmd); install_element(INTERFACE_NODE, &babel_set_wireless_cmd); install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); install_element(INTERFACE_NODE, &babel_set_update_interval_cmd); /* "show babel ..." commands */ install_element(VIEW_NODE, &show_babel_interface_cmd); install_element(ENABLE_NODE, &show_babel_interface_cmd); install_element(VIEW_NODE, &show_babel_neighbour_cmd); install_element(ENABLE_NODE, &show_babel_neighbour_cmd); install_element(VIEW_NODE, &show_babel_database_cmd); install_element(ENABLE_NODE, &show_babel_database_cmd); install_element(VIEW_NODE, &show_babel_parameters_cmd); install_element(ENABLE_NODE, &show_babel_parameters_cmd); } /* hooks: functions called respectively when struct interface is created or deleted. */ static int babel_if_new_hook (struct interface *ifp) { ifp->info = babel_interface_allocate(); return 0; } static int babel_if_delete_hook (struct interface *ifp) { babel_interface_free(ifp->info); ifp->info = NULL; return 0; } /* Output an "interface" section for each of the known interfaces with babeld-specific statement lines where appropriate. */ static int interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; int write = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); if (IS_ENABLE (ifp)) { babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); /* wireless/no split-horizon is the default */ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { vty_out (vty, " babel wired%s", VTY_NEWLINE); write++; } if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) { vty_out (vty, " babel split-horizon%s", VTY_NEWLINE); write++; } if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL) { vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE); write++; } if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL) { vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE); write++; } } vty_out (vty, "!%s", VTY_NEWLINE); write++; } return write; } /* Output a "network" statement line for each of the enabled interfaces. */ int babel_enable_if_config_write (struct vty * vty) { unsigned int i, lines = 0; char *str; for (i = 0; i < vector_active (babel_enable_if); i++) if ((str = vector_slot (babel_enable_if, i)) != NULL) { vty_out (vty, " network %s%s", str, VTY_NEWLINE); lines++; } return lines; } /* functions to allocate or free memory for a babel_interface_nfo, filling needed fields */ static babel_interface_nfo * babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); if(babel_ifp == NULL) return NULL; /* Here are set the default values for an interface. */ memset(babel_ifp, 0, sizeof(babel_interface_nfo)); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (random() & 0xFFFF); babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; babel_set_wired_internal(babel_ifp, 0); return babel_ifp; } static void babel_interface_free (babel_interface_nfo *babel_ifp) { XFREE(MTYPE_BABEL_IF, babel_ifp); } quagga-0.99.24.1/babeld/resend.c0000644000175000017500000002261612476520570013100 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "if.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "neighbour.h" #include "resend.h" #include "message.h" #include "babel_interface.h" struct timeval resend_time = {0, 0}; struct resend *to_resend = NULL; static int resend_match(struct resend *resend, int kind, const unsigned char *prefix, unsigned char plen) { return (resend->kind == kind && resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0); } /* This is called by neigh.c when a neighbour is flushed */ void flush_resends(struct neighbour *neigh) { /* Nothing for now */ } static struct resend * find_resend(int kind, const unsigned char *prefix, unsigned char plen, struct resend **previous_return) { struct resend *current, *previous; previous = NULL; current = to_resend; while(current) { if(resend_match(current, kind, prefix, plen)) { if(previous_return) *previous_return = previous; return current; } previous = current; current = current->next; } return NULL; } struct resend * find_request(const unsigned char *prefix, unsigned char plen, struct resend **previous_return) { return find_resend(RESEND_REQUEST, prefix, plen, previous_return); } int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay) { struct resend *resend; unsigned int ifindex = ifp ? ifp->ifindex : 0; if((kind == RESEND_REQUEST && input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) || (kind == RESEND_UPDATE && output_filter(NULL, prefix, plen, ifindex) >= INFINITY)) return 0; if(delay >= 0xFFFF) delay = 0xFFFF; resend = find_resend(kind, prefix, plen, NULL); if(resend) { if(resend->delay && delay) resend->delay = MIN(resend->delay, delay); else if(delay) resend->delay = delay; resend->time = babel_now; resend->max = RESEND_MAX; if(id && memcmp(resend->id, id, 8) == 0 && seqno_compare(resend->seqno, seqno) > 0) { return 0; } if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->seqno = seqno; if(resend->ifp != ifp) resend->ifp = NULL; } else { resend = malloc(sizeof(struct resend)); if(resend == NULL) return -1; resend->kind = kind; resend->max = RESEND_MAX; resend->delay = delay; memcpy(resend->prefix, prefix, 16); resend->plen = plen; resend->seqno = seqno; if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->ifp = ifp; resend->time = babel_now; resend->next = to_resend; to_resend = resend; } if(resend->delay) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); timeval_min(&resend_time, &timeout); } return 1; } static int resend_expired(struct resend *resend) { switch(resend->kind) { case RESEND_REQUEST: return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT; default: return resend->max <= 0; } } int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) return 1; return 0; } /* Determine whether a given request should be forwarded. */ int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) == 0 && seqno_compare(request->seqno, seqno) > 0) return 0; if(request->ifp != NULL && request->ifp != ifp) return 0; if(request->max > 0) /* Will be resent. */ return 1; if(timeval_minus_msec(&babel_now, &request->time) < (ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000)) /* Fairly recent. */ return 1; return 0; } int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp) { struct resend *request, *previous; request = find_request(prefix, plen, &previous); if(request == NULL) return 0; if(ifp != NULL && request->ifp != ifp) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) { /* We cannot remove the request, as we may be walking the list right now. Mark it as expired, so that expire_resend will remove it. */ request->max = 0; request->time.tv_sec = 0; recompute_resend_time(); return 1; } return 0; } void expire_resend() { struct resend *current, *previous; int recompute = 0; previous = NULL; current = to_resend; while(current) { if(resend_expired(current)) { if(previous == NULL) { to_resend = current->next; free(current); current = to_resend; } else { previous->next = current->next; free(current); current = previous->next; } recompute = 1; } else { previous = current; current = current->next; } } if(recompute) recompute_resend_time(); } void recompute_resend_time() { struct resend *request; struct timeval resend = {0, 0}; request = to_resend; while(request) { if(!resend_expired(request) && request->delay > 0 && request->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &request->time, request->delay); timeval_min(&resend, &timeout); } request = request->next; } resend_time = resend; } void do_resend() { struct resend *resend; resend = to_resend; while(resend) { if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); if(timeval_compare(&babel_now, &timeout) >= 0) { switch(resend->kind) { case RESEND_REQUEST: send_multihop_request(resend->ifp, resend->prefix, resend->plen, resend->seqno, resend->id, 127); break; case RESEND_UPDATE: send_update(resend->ifp, 1, resend->prefix, resend->plen); break; default: abort(); } resend->delay = MIN(0xFFFF, resend->delay * 2); resend->max--; } } resend = resend->next; } recompute_resend_time(); } quagga-0.99.24.1/babeld/message.c0000644000175000017500000014540412476520570013245 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "if.h" #include "babeld.h" #include "util.h" #include "net.h" #include "babel_interface.h" #include "source.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "resend.h" #include "message.h" #include "kernel.h" unsigned char packet_header[4] = {42, 2}; int split_horizon = 1; unsigned short myseqno = 0; struct timeval seqno_time = {0, 0}; #define UNICAST_BUFSIZE 1024 int unicast_buffered = 0; unsigned char *unicast_buffer = NULL; struct neighbour *unicast_neighbour = NULL; struct timeval unicast_flush_timeout = {0, 0}; static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; /* Parse a network prefix, encoded in the somewhat baroque compressed representation used by Babel. Return the number of bytes parsed. */ static int network_prefix(int ae, int plen, unsigned int omitted, const unsigned char *p, const unsigned char *dp, unsigned int len, unsigned char *p_r) { unsigned pb; unsigned char prefix[16]; int ret = -1; if(plen >= 0) pb = (plen + 7) / 8; else if(ae == 1) pb = 4; else pb = 16; if(pb > 16) return -1; memset(prefix, 0, 16); switch(ae) { case 0: ret = 0; break; case 1: if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) return -1; memcpy(prefix, v4prefix, 12); if(omitted) { if (dp == NULL || !v4mapped(dp)) return -1; memcpy(prefix, dp, 12 + omitted); } if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); ret = pb - omitted; break; case 2: if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; if(omitted) { if (dp == NULL || v4mapped(dp)) return -1; memcpy(prefix, dp, omitted); } if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); ret = pb - omitted; break; case 3: if(pb > 8 && len < pb - 8) return -1; prefix[0] = 0xfe; prefix[1] = 0x80; if(pb > 8) memcpy(prefix + 8, p, pb - 8); ret = pb - 8; break; default: return -1; } mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); return ret; } static void parse_route_attributes(const unsigned char *a, int alen, unsigned char *channels) { int type, len, i = 0; while(i < alen) { type = a[i]; if(type == 0) { i++; continue; } if(i + 1 > alen) { fprintf(stderr, "Received truncated attributes.\n"); return; } len = a[i + 1]; if(i + len > alen) { fprintf(stderr, "Received truncated attributes.\n"); return; } if(type == 1) { /* Nothing. */ } else if(type == 2) { if(len > DIVERSITY_HOPS) { fprintf(stderr, "Received overlong channel information (%d > %d).\n", len, DIVERSITY_HOPS); len = DIVERSITY_HOPS; } if(memchr(a + i + 2, 0, len) != NULL) { /* 0 is reserved. */ fprintf(stderr, "Channel information contains 0!"); return; } memset(channels, 0, DIVERSITY_HOPS); memcpy(channels, a + i + 2, len); } else { fprintf(stderr, "Received unknown route attribute %d.\n", type); } i += len + 2; } } static int network_address(int ae, const unsigned char *a, unsigned int len, unsigned char *a_r) { return network_prefix(ae, -1, 0, a, NULL, len, a_r); } static int channels_len(unsigned char *channels) { unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS); return p ? (p - channels) : DIVERSITY_HOPS; } void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen) { int i; const unsigned char *message; unsigned char type, len; int bodylen; struct neighbour *neigh; int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0, have_v4_nh = 0, have_v6_nh = 0; unsigned char router_id[8], v4_prefix[16], v6_prefix[16], v4_nh[16], v6_nh[16]; if(!linklocal(from)) { zlog_err("Received packet from non-local address %s.", format_address(from)); return; } if(packet[0] != 42) { zlog_err("Received malformed packet on %s from %s.", ifp->name, format_address(from)); return; } if(packet[1] != 2) { zlog_err("Received packet with unknown version %d on %s from %s.", packet[1], ifp->name, format_address(from)); return; } neigh = find_neighbour(from, ifp); if(neigh == NULL) { zlog_err("Couldn't allocate neighbour."); return; } DO_NTOHS(bodylen, packet + 2); if(bodylen + 4 > packetlen) { zlog_err("Received truncated packet (%d + 4 > %d).", bodylen, packetlen); bodylen = packetlen - 4; } i = 0; while(i < bodylen) { message = packet + 4 + i; type = message[0]; if(type == MESSAGE_PAD1) { debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.", format_address(from), ifp->name); i++; continue; } if(i + 1 > bodylen) { zlog_err("Received truncated message."); break; } len = message[1]; if(i + len > bodylen) { zlog_err("Received truncated message."); break; } if(type == MESSAGE_PADN) { debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.", len, format_address(from), ifp->name); } else if(type == MESSAGE_ACK_REQ) { unsigned short nonce, interval; if(len < 6) goto fail; DO_NTOHS(nonce, message + 4); DO_NTOHS(interval, message + 6); debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.", nonce, interval, format_address(from), ifp->name); send_ack(neigh, nonce, interval); } else if(type == MESSAGE_ACK) { debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.", format_address(from), ifp->name); /* Nothing right now */ } else if(type == MESSAGE_HELLO) { unsigned short seqno, interval; int changed; if(len < 6) goto fail; DO_NTOHS(seqno, message + 4); DO_NTOHS(interval, message + 6); debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", seqno, interval, format_address(from), ifp->name); changed = update_neighbour(neigh, seqno, interval); update_neighbour_metric(neigh, changed); if(interval > 0) schedule_neighbours_check(interval * 10, 0); } else if(type == MESSAGE_IHU) { unsigned short txcost, interval; unsigned char address[16]; int rc; if(len < 6) goto fail; DO_NTOHS(txcost, message + 4); DO_NTOHS(interval, message + 6); rc = network_address(message[2], message + 8, len - 6, address); if(rc < 0) goto fail; debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.", txcost, interval, format_address(from), ifp->name, format_address(address)); if(message[2] == 0 || is_interface_ll_address(ifp, address)) { int changed = txcost != neigh->txcost; neigh->txcost = txcost; neigh->ihu_time = babel_now; neigh->ihu_interval = interval; update_neighbour_metric(neigh, changed); if(interval > 0) schedule_neighbours_check(interval * 10 * 3, 0); } } else if(type == MESSAGE_ROUTER_ID) { if(len < 10) { have_router_id = 0; goto fail; } memcpy(router_id, message + 4, 8); have_router_id = 1; debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.", format_eui64(router_id), format_address(from), ifp->name); } else if(type == MESSAGE_NH) { unsigned char nh[16]; int rc; if(len < 2) { have_v4_nh = 0; have_v6_nh = 0; goto fail; } rc = network_address(message[2], message + 4, len - 2, nh); if(rc < 0) { have_v4_nh = 0; have_v6_nh = 0; goto fail; } debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.", format_address(nh), message[2], format_address(from), ifp->name); if(message[2] == 1) { memcpy(v4_nh, nh, 16); have_v4_nh = 1; } else { memcpy(v6_nh, nh, 16); have_v6_nh = 1; } } else if(type == MESSAGE_UPDATE) { unsigned char prefix[16], *nh; unsigned char plen; unsigned char channels[DIVERSITY_HOPS]; unsigned short interval, seqno, metric; int rc, parsed_len; if(len < 10) { if(len < 2 || message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; goto fail; } DO_NTOHS(interval, message + 6); DO_NTOHS(seqno, message + 8); DO_NTOHS(metric, message + 10); if(message[5] == 0 || (message[3] == 1 ? have_v4_prefix : have_v6_prefix)) rc = network_prefix(message[2], message[4], message[5], message + 12, message[2] == 1 ? v4_prefix : v6_prefix, len - 10, prefix); else rc = -1; if(rc < 0) { if(message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; goto fail; } parsed_len = 10 + rc; plen = message[4] + (message[2] == 1 ? 96 : 0); if(message[3] & 0x80) { if(message[2] == 1) { memcpy(v4_prefix, prefix, 16); have_v4_prefix = 1; } else { memcpy(v6_prefix, prefix, 16); have_v6_prefix = 1; } } if(message[3] & 0x40) { if(message[2] == 1) { memset(router_id, 0, 4); memcpy(router_id + 4, prefix + 12, 4); } else { memcpy(router_id, prefix + 8, 8); } have_router_id = 1; } if(!have_router_id && message[2] != 0) { zlog_err("Received prefix with no router id."); goto fail; } debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", (message[3] & 0x80) ? "/prefix" : "", (message[3] & 0x40) ? "/id" : "", format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { if(metric < 0xFFFF) { zlog_err("Received wildcard update with finite metric."); goto done; } retract_neighbour_routes(neigh); goto done; } else if(message[2] == 1) { if(!have_v4_nh) goto fail; nh = v4_nh; } else if(have_v6_nh) { nh = v6_nh; } else { nh = neigh->address; } if(message[2] == 1) { if(!babel_get_if_nfo(ifp)->ipv4) goto done; } if((ifp->flags & BABEL_IF_FARAWAY)) { channels[0] = 0; } else { /* This will be overwritten by parse_route_attributes below. */ if(metric < 256) { /* Assume non-interfering (wired) link. */ channels[0] = 0; } else { /* Assume interfering. */ channels[0] = BABEL_IF_CHANNEL_INTERFERING; channels[1] = 0; } if(parsed_len < len) parse_route_attributes(message + 2 + parsed_len, len - parsed_len, channels); } update_route(router_id, prefix, plen, seqno, metric, interval, neigh, nh, channels, channels_len(channels)); } else if(type == MESSAGE_REQUEST) { unsigned char prefix[16], plen; int rc; if(len < 2) goto fail; rc = network_prefix(message[2], message[3], 0, message + 4, NULL, len - 2, prefix); if(rc < 0) goto fail; plen = message[3] + (message[2] == 1 ? 96 : 0); debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.", message[2] == 0 ? "any" : format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp); /* If a neighbour is requesting a full route dump from us, we might as well send it an IHU. */ send_ihu(neigh, NULL); /* Since nodes send wildcard requests on boot, booting a large number of nodes at the same time may cause an update storm. Ignore a wildcard request that happens shortly after we sent a full update. */ if(babel_ifp->last_update_time < (time_t)(babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1))) send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); } } else if(type == MESSAGE_MH_REQUEST) { unsigned char prefix[16], plen; unsigned short seqno; int rc; if(len < 14) goto fail; DO_NTOHS(seqno, message + 4); rc = network_prefix(message[2], message[3], 0, message + 16, NULL, len - 14, prefix); if(rc < 0) goto fail; plen = message[3] + (message[2] == 1 ? 96 : 0); debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).", message[6], format_prefix(prefix, plen), format_address(from), ifp->name, format_eui64(message + 8), seqno); handle_request(neigh, prefix, plen, message[6], seqno, message + 8); } else { debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", type, format_address(from), ifp->name); } done: i += len + 2; continue; fail: zlog_err("Couldn't parse packet (%d, %d) from %s on %s.", message[0], message[1], format_address(from), ifp->name); goto done; } return; } /* Under normal circumstances, there are enough moderation mechanisms elsewhere in the protocol to make sure that this last-ditch check should never trigger. But I'm superstitious. */ static int check_bucket(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bucket <= 0) { int seconds = babel_now.tv_sec - babel_ifp->bucket_time; if(seconds > 0) { babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX, seconds * BUCKET_TOKENS_PER_SEC); } /* Reset bucket time unconditionally, in case clock is stepped. */ babel_ifp->bucket_time = babel_now.tv_sec; } if(babel_ifp->bucket > 0) { babel_ifp->bucket--; return 1; } else { return 0; } } void flushbuf(struct interface *ifp) { int rc; struct sockaddr_in6 sin6; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); assert(babel_ifp->buffered <= babel_ifp->bufsize); flushupdates(ifp); if(babel_ifp->buffered > 0) { debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)", babel_ifp->buffered, ifp->name); if(check_bucket(ifp)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, protocol_group, 16); sin6.sin6_port = htons(protocol_port); sin6.sin6_scope_id = ifp->ifindex; DO_HTONS(packet_header + 2, babel_ifp->buffered); rc = babel_send(protocol_socket, packet_header, sizeof(packet_header), babel_ifp->sendbuf, babel_ifp->buffered, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) zlog_err("send: %s", safe_strerror(errno)); } else { zlog_err("Warning: bucket full, dropping packet to %s.", ifp->name); } } VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); babel_ifp->buffered = 0; babel_ifp->have_buffered_hello = 0; babel_ifp->have_buffered_id = 0; babel_ifp->have_buffered_nh = 0; babel_ifp->have_buffered_prefix = 0; babel_ifp->flush_timeout.tv_sec = 0; babel_ifp->flush_timeout.tv_usec = 0; } static void schedule_flush(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs = jitter(babel_ifp, 0); if(babel_ifp->flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->flush_timeout, msecs); } static void schedule_flush_now(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* Almost now */ unsigned msecs = roughly(10); if(babel_ifp->flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->flush_timeout, msecs); } static void schedule_unicast_flush(unsigned msecs) { if(!unicast_neighbour) return; if(unicast_flush_timeout.tv_sec != 0 && timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs) return; unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000; unicast_flush_timeout.tv_sec = babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; } static void ensure_space(struct interface *ifp, int space) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < space) flushbuf(ifp); } static void start_message(struct interface *ifp, int type, int len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) flushbuf(ifp); babel_ifp->sendbuf[babel_ifp->buffered++] = type; babel_ifp->sendbuf[babel_ifp->buffered++] = len; } static void end_message(struct interface *ifp, int type, int bytes) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); assert(babel_ifp->buffered >= bytes + 2 && babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type && babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes); schedule_flush(ifp); } static void accumulate_byte(struct interface *ifp, unsigned char value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); babel_ifp->sendbuf[babel_ifp->buffered++] = value; } static void accumulate_short(struct interface *ifp, unsigned short value) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); babel_ifp->buffered += 2; } static void accumulate_bytes(struct interface *ifp, const unsigned char *value, unsigned len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len); babel_ifp->buffered += len; } static int start_unicast_message(struct neighbour *neigh, int type, int len) { if(unicast_neighbour) { if(neigh != unicast_neighbour || unicast_buffered + len + 2 >= MIN(UNICAST_BUFSIZE, babel_get_if_nfo(neigh->ifp)->bufsize)) flush_unicast(0); } if(!unicast_buffer) unicast_buffer = malloc(UNICAST_BUFSIZE); if(!unicast_buffer) { zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno)); return -1; } unicast_neighbour = neigh; unicast_buffer[unicast_buffered++] = type; unicast_buffer[unicast_buffered++] = len; return 1; } static void end_unicast_message(struct neighbour *neigh, int type, int bytes) { assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 && unicast_buffer[unicast_buffered - bytes - 2] == type && unicast_buffer[unicast_buffered - bytes - 1] == bytes); schedule_unicast_flush(jitter(babel_get_if_nfo(neigh->ifp), 0)); } static void accumulate_unicast_byte(struct neighbour *neigh, unsigned char value) { unicast_buffer[unicast_buffered++] = value; } static void accumulate_unicast_short(struct neighbour *neigh, unsigned short value) { DO_HTONS(unicast_buffer + unicast_buffered, value); unicast_buffered += 2; } static void accumulate_unicast_bytes(struct neighbour *neigh, const unsigned char *value, unsigned len) { memcpy(unicast_buffer + unicast_buffered, value, len); unicast_buffered += len; } void send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) { int rc; debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", nonce, format_address(neigh->address), neigh->ifp->name); rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; accumulate_unicast_short(neigh, nonce); end_unicast_message(neigh, MESSAGE_ACK, 2); /* Roughly yields a value no larger than 3/2, so this meets the deadline */ schedule_unicast_flush(roughly(interval * 6)); } void send_hello_noupdate(struct interface *ifp, unsigned interval) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); /* This avoids sending multiple hellos in a single packet, which breaks link quality estimation. */ if(babel_ifp->have_buffered_hello) flushbuf(ifp); babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1); set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.", babel_ifp->hello_seqno, interval, ifp->name); start_message(ifp, MESSAGE_HELLO, 6); accumulate_short(ifp, 0); accumulate_short(ifp, babel_ifp->hello_seqno); accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); end_message(ifp, MESSAGE_HELLO, 6); babel_ifp->have_buffered_hello = 1; } void send_hello(struct interface *ifp) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ if(babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); } void flush_unicast(int dofree) { struct sockaddr_in6 sin6; int rc; if(unicast_buffered == 0) goto done; if(!if_up(unicast_neighbour->ifp)) goto done; /* Preserve ordering of messages */ flushbuf(unicast_neighbour->ifp); if(check_bucket(unicast_neighbour->ifp)) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16); sin6.sin6_port = htons(protocol_port); sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex; DO_HTONS(packet_header + 2, unicast_buffered); rc = babel_send(protocol_socket, packet_header, sizeof(packet_header), unicast_buffer, unicast_buffered, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) zlog_err("send(unicast): %s", safe_strerror(errno)); } else { zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.", format_address(unicast_neighbour->address), unicast_neighbour->ifp->name); } done: VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE); unicast_buffered = 0; if(dofree && unicast_buffer) { free(unicast_buffer); unicast_buffer = NULL; } unicast_neighbour = NULL; unicast_flush_timeout.tv_sec = 0; unicast_flush_timeout.tv_usec = 0; } static void really_send_update(struct interface *ifp, const unsigned char *id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short metric, unsigned char *channels, int channels_len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); int add_metric, v4, real_plen, omit = 0; const unsigned char *real_prefix; unsigned short flags = 0; int channels_size; if(diversity_kind != DIVERSITY_CHANNEL) channels_len = -1; channels_size = channels_len >= 0 ? channels_len + 2 : 0; if(!if_up(ifp)) return; add_metric = output_filter(id, prefix, plen, ifp->ifindex); if(add_metric >= INFINITY) return; metric = MIN(metric + add_metric, INFINITY); /* Worst case */ ensure_space(ifp, 20 + 12 + 28); v4 = plen >= 96 && v4mapped(prefix); if(v4) { if(!babel_ifp->ipv4) return; if(!babel_ifp->have_buffered_nh || memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) { start_message(ifp, MESSAGE_NH, 6); accumulate_byte(ifp, 1); accumulate_byte(ifp, 0); accumulate_bytes(ifp, babel_ifp->ipv4, 4); end_message(ifp, MESSAGE_NH, 6); memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4); babel_ifp->have_buffered_nh = 1; } real_prefix = prefix + 12; real_plen = plen - 96; } else { if(babel_ifp->have_buffered_prefix) { while(omit < plen / 8 && babel_ifp->buffered_prefix[omit] == prefix[omit]) omit++; } if(!babel_ifp->have_buffered_prefix || plen >= 48) flags |= 0x80; real_prefix = prefix; real_plen = plen; } if(!babel_ifp->have_buffered_id || memcmp(id, babel_ifp->buffered_id, 8) != 0) { if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { flags |= 0x40; } else { start_message(ifp, MESSAGE_ROUTER_ID, 10); accumulate_short(ifp, 0); accumulate_bytes(ifp, id, 8); end_message(ifp, MESSAGE_ROUTER_ID, 10); } memcpy(babel_ifp->buffered_id, id, 16); babel_ifp->have_buffered_id = 1; } start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, flags); accumulate_byte(ifp, real_plen); accumulate_byte(ifp, omit); accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10); accumulate_short(ifp, seqno); accumulate_short(ifp, metric); accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); /* Note that an empty channels TLV is different from no such TLV. */ if(channels_len >= 0) { accumulate_byte(ifp, 2); accumulate_byte(ifp, channels_len); accumulate_bytes(ifp, channels, channels_len); } end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + channels_size); if(flags & 0x80) { memcpy(babel_ifp->buffered_prefix, prefix, 16); babel_ifp->have_buffered_prefix = 1; } } static int compare_buffered_updates(const void *av, const void *bv) { const struct buffered_update *a = av, *b = bv; int rc, v4a, v4b, ma, mb; rc = memcmp(a->id, b->id, 8); if(rc != 0) return rc; v4a = (a->plen >= 96 && v4mapped(a->prefix)); v4b = (b->plen >= 96 && v4mapped(b->prefix)); if(v4a > v4b) return 1; else if(v4a < v4b) return -1; ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0); mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0); if(ma > mb) return -1; else if(mb > ma) return 1; if(a->plen < b->plen) return 1; else if(a->plen > b->plen) return -1; return memcmp(a->prefix, b->prefix, 16); } void flushupdates(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; struct xroute *xroute; struct babel_route *route; const unsigned char *last_prefix = NULL; unsigned char last_plen = 0xFF; int i; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) flushupdates(ifp_aux); return; } babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->num_buffered_updates > 0) { struct buffered_update *b = babel_ifp->buffered_updates; int n = babel_ifp->num_buffered_updates; babel_ifp->buffered_updates = NULL; babel_ifp->update_bufsize = 0; babel_ifp->num_buffered_updates = 0; if(!if_up(ifp)) goto done; debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))", n, ifp->name, ifp->ifindex); /* In order to send fewer update messages, we want to send updates with the same router-id together, with IPv6 going out before IPv4. */ for(i = 0; i < n; i++) { route = find_installed_route(b[i].prefix, b[i].plen); if(route) memcpy(b[i].id, route->src->id, 8); else memcpy(b[i].id, myid, 8); } qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); for(i = 0; i < n; i++) { /* The same update may be scheduled multiple times before it is sent out. Since our buffer is now sorted, it is enough to compare with the previous update. */ if(last_prefix) { if(b[i].plen == last_plen && memcmp(b[i].prefix, last_prefix, 16) == 0) continue; } xroute = find_xroute(b[i].prefix, b[i].plen); route = find_installed_route(b[i].prefix, b[i].plen); if(xroute && (!route || xroute->metric <= kernel_metric)) { really_send_update(ifp, myid, xroute->prefix, xroute->plen, myseqno, xroute->metric, NULL, 0); last_prefix = xroute->prefix; last_plen = xroute->plen; } else if(route) { unsigned char channels[DIVERSITY_HOPS]; int chlen; struct interface *route_ifp = route->neigh->ifp; struct babel_interface *babel_route_ifp = NULL; unsigned short metric; unsigned short seqno; seqno = route->seqno; metric = route_interferes(route, ifp) ? route_metric(route) : route_metric_noninterfering(route); if(metric < INFINITY) satisfy_request(route->src->prefix, route->src->plen, seqno, route->src->id, ifp); if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && route->neigh->ifp == ifp) continue; babel_route_ifp = babel_get_if_nfo(route_ifp); if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) { memcpy(channels, route->channels, DIVERSITY_HOPS); } else { if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN) channels[0] = BABEL_IF_CHANNEL_INTERFERING; else { assert(babel_route_ifp->channel > 0 && babel_route_ifp->channel <= 255); channels[0] = babel_route_ifp->channel; } memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); } chlen = channels_len(channels); really_send_update(ifp, route->src->id, route->src->prefix, route->src->plen, seqno, metric, channels, chlen); update_source(route->src, seqno, metric); last_prefix = route->src->prefix; last_plen = route->src->plen; } else { /* There's no route for this prefix. This can happen shortly after an xroute has been retracted, so send a retraction. */ really_send_update(ifp, myid, b[i].prefix, b[i].plen, myseqno, INFINITY, NULL, -1); } } schedule_flush_now(ifp); done: free(b); } babel_ifp->update_flush_timeout.tv_sec = 0; babel_ifp->update_flush_timeout.tv_usec = 0; } static void schedule_update_flush(struct interface *ifp, int urgent) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned msecs; msecs = update_jitter(babel_ifp, urgent); if(babel_ifp->update_flush_timeout.tv_sec != 0 && timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) return; set_timeout(&babel_ifp->update_flush_timeout, msecs); } static void buffer_update(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); if(babel_ifp->num_buffered_updates > 0 && babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize) flushupdates(ifp); if(babel_ifp->update_bufsize == 0) { int n; assert(babel_ifp->buffered_updates == NULL); /* Allocate enough space to hold a full update. Since the number of installed routes will grow over time, make sure we have enough space to send a full-ish frame. */ n = installed_routes_estimate() + xroutes_estimate() + 4; n = MAX(n, babel_ifp->bufsize / 16); again: babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); if(babel_ifp->buffered_updates == NULL) { zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); if(n > 4) { /* Try again with a tiny buffer. */ n = 4; goto again; } return; } babel_ifp->update_bufsize = n; babel_ifp->num_buffered_updates = 0; } memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix, prefix, 16); babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen; babel_ifp->num_buffered_updates++; } static void buffer_update_callback(struct babel_route *route, void *closure) { buffer_update((struct interface*)closure, route->src->prefix, route->src->plen); } void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = NULL; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; struct babel_route *route; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_update(ifp_aux, urgent, prefix, plen); if(prefix) { /* Since flushupdates only deals with non-wildcard interfaces, we need to do this now. */ route = find_installed_route(prefix, plen); if(route && route_metric(route) < INFINITY) satisfy_request(prefix, plen, route->src->seqno, route->src->id, NULL); } return; } if(!if_up(ifp)) return; babel_ifp = babel_get_if_nfo(ifp); if(prefix) { debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", ifp->name, format_prefix(prefix, plen)); buffer_update(ifp, prefix, plen); } else { send_self_update(ifp); debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); for_all_installed_routes(buffer_update_callback, ifp); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; } schedule_update_flush(ifp, urgent); } void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { assert(prefix != NULL); send_update(ifp, 1, prefix, plen); record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay); } void send_wildcard_retraction(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_wildcard_retraction(ifp_aux); return; } if(!if_up(ifp)) return; babel_ifp = babel_get_if_nfo(ifp); start_message(ifp, MESSAGE_UPDATE, 10); accumulate_byte(ifp, 0); accumulate_byte(ifp, 0x40); accumulate_byte(ifp, 0); accumulate_byte(ifp, 0); accumulate_short(ifp, 0xFFFF); accumulate_short(ifp, myseqno); accumulate_short(ifp, 0xFFFF); end_message(ifp, MESSAGE_UPDATE, 10); babel_ifp->have_buffered_id = 0; } void update_myseqno() { myseqno = seqno_plus(myseqno, 1); seqno_time = babel_now; } static void send_xroute_update_callback(struct xroute *xroute, void *closure) { struct interface *ifp = (struct interface*)closure; send_update(ifp, 0, xroute->prefix, xroute->plen); } void send_self_update(struct interface *ifp) { if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(!if_up(ifp_aux)) continue; send_self_update(ifp_aux); } return; } debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); for_all_xroutes(send_xroute_update_callback, ifp); } void send_ihu(struct neighbour *neigh, struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; int rxcost, interval; int ll; if(neigh == NULL && ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(if_up(ifp_aux)) continue; send_ihu(NULL, ifp_aux); } return; } if(neigh == NULL) { struct neighbour *ngh; FOR_ALL_NEIGHBOURS(ngh) { if(ngh->ifp == ifp) send_ihu(ngh, ifp); } return; } if(ifp && neigh->ifp != ifp) return; ifp = neigh->ifp; babel_ifp = babel_get_if_nfo(ifp); if(!if_up(ifp)) return; rxcost = neighbour_rxcost(neigh); interval = (babel_ifp->hello_interval * 3 + 9) / 10; /* Conceptually, an IHU is a unicast message. We usually send them as multicast, since this allows aggregation into a single packet and avoids an ARP exchange. If we already have a unicast message queued for this neighbour, however, we might as well piggyback the IHU. */ debugf(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.", unicast_neighbour == neigh ? "unicast " : "", rxcost, neigh->ifp->name, format_address(neigh->address)); ll = linklocal(neigh->address); if(unicast_neighbour != neigh) { start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); accumulate_byte(ifp, ll ? 3 : 2); accumulate_byte(ifp, 0); accumulate_short(ifp, rxcost); accumulate_short(ifp, interval); if(ll) accumulate_bytes(ifp, neigh->address + 8, 8); else accumulate_bytes(ifp, neigh->address, 16); end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); } else { int rc; rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); if(rc < 0) return; accumulate_unicast_byte(neigh, ll ? 3 : 2); accumulate_unicast_byte(neigh, 0); accumulate_unicast_short(neigh, rxcost); accumulate_unicast_short(neigh, interval); if(ll) accumulate_unicast_bytes(neigh, neigh->address + 8, 8); else accumulate_unicast_bytes(neigh, neigh->address, 16); end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); } } /* Send IHUs to all marginal neighbours */ void send_marginal_ihu(struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(ifp && neigh->ifp != ifp) continue; if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) send_ihu(neigh, ifp); } } void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { int v4, len; if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(if_up(ifp_aux)) continue; send_request(ifp_aux, prefix, plen); } return; } /* make sure any buffered updates go out before this request. */ flushupdates(ifp); if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", ifp->name, prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); len = !prefix ? 2 : v4 ? 6 : 18; start_message(ifp, MESSAGE_REQUEST, len); accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2); accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen); if(prefix) { if(v4) accumulate_bytes(ifp, prefix + 12, 4); else accumulate_bytes(ifp, prefix, 16); } end_message(ifp, MESSAGE_REQUEST, len); } void send_unicast_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen) { int rc, v4, len; /* make sure any buffered updates go out before this request. */ flushupdates(neigh->ifp); debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.", format_address(neigh->address), prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); len = !prefix ? 2 : v4 ? 6 : 18; rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); if(rc < 0) return; accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2); accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen); if(prefix) { if(v4) accumulate_unicast_bytes(neigh, prefix + 12, 4); else accumulate_unicast_bytes(neigh, prefix, 16); } end_unicast_message(neigh, MESSAGE_REQUEST, len); } void send_multihop_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { int v4, pb, len; /* Make sure any buffered updates go out before this request. */ flushupdates(ifp); if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; FOR_ALL_INTERFACES(ifp_aux, linklist_node) { if(!if_up(ifp_aux)) continue; send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); } return; } if(!if_up(ifp)) return; debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", hop_count, ifp->name, format_prefix(prefix, plen)); v4 = plen >= 96 && v4mapped(prefix); pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; len = 6 + 8 + pb; start_message(ifp, MESSAGE_MH_REQUEST, len); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, v4 ? plen - 96 : plen); accumulate_short(ifp, seqno); accumulate_byte(ifp, hop_count); accumulate_byte(ifp, 0); accumulate_bytes(ifp, id, 8); if(prefix) { if(v4) accumulate_bytes(ifp, prefix + 12, pb); else accumulate_bytes(ifp, prefix, pb); } end_message(ifp, MESSAGE_MH_REQUEST, len); } void send_unicast_multihop_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { int rc, v4, pb, len; /* Make sure any buffered updates go out before this request. */ flushupdates(neigh->ifp); debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).", format_address(neigh->address), format_prefix(prefix, plen), hop_count); v4 = plen >= 96 && v4mapped(prefix); pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; len = 6 + 8 + pb; rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len); if(rc < 0) return; accumulate_unicast_byte(neigh, v4 ? 1 : 2); accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen); accumulate_unicast_short(neigh, seqno); accumulate_unicast_byte(neigh, hop_count); accumulate_unicast_byte(neigh, 0); accumulate_unicast_bytes(neigh, id, 8); if(prefix) { if(v4) accumulate_unicast_bytes(neigh, prefix + 12, pb); else accumulate_unicast_bytes(neigh, prefix, pb); } end_unicast_message(neigh, MESSAGE_MH_REQUEST, len); } void send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id) { if(neigh) send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); else send_multihop_request(NULL, prefix, plen, seqno, id, 127); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, neigh ? neigh->ifp : NULL, resend_delay); } void handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned char hop_count, unsigned short seqno, const unsigned char *id) { struct xroute *xroute; struct babel_route *route; struct neighbour *successor = NULL; xroute = find_xroute(prefix, plen); route = find_installed_route(prefix, plen); if(xroute && (!route || xroute->metric <= kernel_metric)) { if(hop_count > 0 && memcmp(id, myid, 8) == 0) { if(seqno_compare(seqno, myseqno) > 0) { if(seqno_minus(seqno, myseqno) > 100) { /* Hopelessly out-of-date request */ return; } update_myseqno(); } } send_update(neigh->ifp, 1, prefix, plen); return; } if(route && (memcmp(id, route->src->id, 8) != 0 || seqno_compare(seqno, route->seqno) <= 0)) { send_update(neigh->ifp, 1, prefix, plen); return; } if(hop_count <= 1) return; if(route && memcmp(id, route->src->id, 8) == 0 && seqno_minus(seqno, route->seqno) > 100) { /* Hopelessly out-of-date */ return; } if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) return; /* Let's try to forward this request. */ if(route && route_metric(route) < INFINITY) successor = route->neigh; if(!successor || successor == neigh) { /* We were about to forward a request to its requestor. Try to find a different neighbour to forward the request to. */ struct babel_route *other_route; other_route = find_best_route(prefix, plen, 0, neigh); if(other_route && route_metric(other_route) < INFINITY) successor = other_route->neigh; } if(!successor || successor == neigh) /* Give up */ return; send_unicast_multihop_request(successor, prefix, plen, seqno, id, hop_count - 1); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, neigh->ifp, 0); } quagga-0.99.24.1/babeld/xroute.c0000644000175000017500000001666212476520570013152 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "if.h" #include "log.h" #include "babeld.h" #include "kernel.h" #include "neighbour.h" #include "message.h" #include "route.h" #include "xroute.h" #include "util.h" #include "babel_interface.h" static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto, int send_updates); static struct xroute *xroutes; static int numxroutes = 0, maxxroutes = 0; /* Add redistributed route to Babel table. */ int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex, struct in_addr *nexthop) { unsigned char uchar_prefix[16]; inaddr_to_uchar(uchar_prefix, &prefix->prefix); debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra."); xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96, api->metric, ifindex, 0, 1); return 0; } /* Remove redistributed route from Babel table. */ int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex) { unsigned char uchar_prefix[16]; struct xroute *xroute = NULL; inaddr_to_uchar(uchar_prefix, &prefix->prefix); xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96); if (xroute != NULL) { debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); flush_xroute(xroute); } return 0; } /* Add redistributed route to Babel table. */ int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex, struct in6_addr *nexthop) { unsigned char uchar_prefix[16]; in6addr_to_uchar(uchar_prefix, &prefix->prefix); debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra."); xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, 0, 1); return 0; } /* Remove redistributed route from Babel table. */ int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex) { unsigned char uchar_prefix[16]; struct xroute *xroute = NULL; in6addr_to_uchar(uchar_prefix, &prefix->prefix); xroute = find_xroute(uchar_prefix, prefix->prefixlen); if (xroute != NULL) { debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra)."); flush_xroute(xroute); } return 0; } struct xroute * find_xroute(const unsigned char *prefix, unsigned char plen) { int i; for(i = 0; i < numxroutes; i++) { if(xroutes[i].plen == plen && memcmp(xroutes[i].prefix, prefix, 16) == 0) return &xroutes[i]; } return NULL; } void flush_xroute(struct xroute *xroute) { int i; i = xroute - xroutes; assert(i >= 0 && i < numxroutes); if(i != numxroutes - 1) memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute)); numxroutes--; VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute)); if(numxroutes == 0) { free(xroutes); xroutes = NULL; maxxroutes = 0; } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) { struct xroute *new_xroutes; int n = maxxroutes / 2; new_xroutes = realloc(xroutes, n * sizeof(struct xroute)); if(new_xroutes == NULL) return; xroutes = new_xroutes; maxxroutes = n; } } static int add_xroute(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto) { struct xroute *xroute = find_xroute(prefix, plen); if(xroute) { if(xroute->metric <= metric) return 0; xroute->metric = metric; return 1; } if(numxroutes >= maxxroutes) { struct xroute *new_xroutes; int n = maxxroutes < 1 ? 8 : 2 * maxxroutes; new_xroutes = xroutes == NULL ? malloc(n * sizeof(struct xroute)) : realloc(xroutes, n * sizeof(struct xroute)); if(new_xroutes == NULL) return -1; maxxroutes = n; xroutes = new_xroutes; } memcpy(xroutes[numxroutes].prefix, prefix, 16); xroutes[numxroutes].plen = plen; xroutes[numxroutes].metric = metric; xroutes[numxroutes].ifindex = ifindex; xroutes[numxroutes].proto = proto; numxroutes++; return 1; } /* Returns an overestimate of the number of xroutes. */ int xroutes_estimate() { return numxroutes; } void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure) { int i; for(i = 0; i < numxroutes; i++) (*f)(&xroutes[i], closure); } /* add an xroute, verifying some conditions; return 0 if there is no changes */ static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto, int send_updates) { int rc; if(martian_prefix(prefix, plen)) return 0; metric = redistribute_filter(prefix, plen, ifindex, proto); if(metric < INFINITY) { rc = add_xroute(prefix, plen, metric, ifindex, proto); if(rc > 0) { struct babel_route *route; route = find_installed_route(prefix, plen); if(route) { if(allow_duplicates < 0 || metric < allow_duplicates) uninstall_route(route); } if(send_updates) send_update(NULL, 0, prefix, plen); return 1; } } return 0; } quagga-0.99.24.1/babeld/route.c0000644000175000017500000007032512476520570012756 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "if.h" #include "babeld.h" #include "util.h" #include "kernel.h" #include "babel_interface.h" #include "source.h" #include "neighbour.h" #include "route.h" #include "xroute.h" #include "message.h" #include "resend.h" static void consider_route(struct babel_route *route); struct babel_route **routes = NULL; static int route_slots = 0, max_route_slots = 0; int kernel_metric = 0; int allow_duplicates = -1; int diversity_kind = DIVERSITY_NONE; int diversity_factor = 256; /* in units of 1/256 */ int keep_unfeasible = 0; /* We maintain a list of "slots", ordered by prefix. Every slot contains a linked list of the routes to this prefix, with the installed route, if any, at the head of the list. */ static int route_compare(const unsigned char *prefix, unsigned char plen, struct babel_route *route) { int i = memcmp(prefix, route->src->prefix, 16); if(i != 0) return i; if(plen < route->src->plen) return -1; else if(plen > route->src->plen) return 1; else return 0; } /* Performs binary search, returns -1 in case of failure. In the latter case, new_return is the place where to insert the new element. */ static int find_route_slot(const unsigned char *prefix, unsigned char plen, int *new_return) { int p, m, g, c; if(route_slots < 1) { if(new_return) *new_return = 0; return -1; } p = 0; g = route_slots - 1; do { m = (p + g) / 2; c = route_compare(prefix, plen, routes[m]); if(c == 0) return m; else if(c < 0) g = m - 1; else p = m + 1; } while(p <= g); if(new_return) *new_return = p; return -1; } struct babel_route * find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop) { struct babel_route *route; int i = find_route_slot(prefix, plen, NULL); if(i < 0) return NULL; route = routes[i]; while(route) { if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) return route; route = route->next; } return NULL; } struct babel_route * find_installed_route(const unsigned char *prefix, unsigned char plen) { int i = find_route_slot(prefix, plen, NULL); if(i >= 0 && routes[i]->installed) return routes[i]; return NULL; } /* Returns an overestimate of the number of installed routes. */ int installed_routes_estimate(void) { return route_slots; } static int resize_route_table(int new_slots) { struct babel_route **new_routes; assert(new_slots >= route_slots); if(new_slots == 0) { new_routes = NULL; free(routes); } else { new_routes = realloc(routes, new_slots * sizeof(struct babel_route*)); if(new_routes == NULL) return -1; } max_route_slots = new_slots; routes = new_routes; return 1; } /* Insert a route into the table. If successful, retains the route. On failure, caller must free the route. */ static struct babel_route * insert_route(struct babel_route *route) { int i, n; assert(!route->installed); i = find_route_slot(route->src->prefix, route->src->plen, &n); if(i < 0) { if(route_slots >= max_route_slots) resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); if(route_slots >= max_route_slots) return NULL; route->next = NULL; if(n < route_slots) memmove(routes + n + 1, routes + n, (route_slots - n) * sizeof(struct babel_route*)); route_slots++; routes[n] = route; } else { struct babel_route *r; r = routes[i]; while(r->next) r = r->next; r->next = route; route->next = NULL; } return route; } void flush_route(struct babel_route *route) { int i; struct source *src; unsigned oldmetric; int lost = 0; oldmetric = route_metric(route); src = route->src; if(route->installed) { uninstall_route(route); lost = 1; } i = find_route_slot(route->src->prefix, route->src->plen, NULL); assert(i >= 0 && i < route_slots); if(route == routes[i]) { routes[i] = route->next; route->next = NULL; free(route); if(routes[i] == NULL) { if(i < route_slots - 1) memmove(routes + i, routes + i + 1, (route_slots - i - 1) * sizeof(struct babel_route*)); routes[route_slots - 1] = NULL; route_slots--; } if(route_slots == 0) resize_route_table(0); else if(max_route_slots > 8 && route_slots < max_route_slots / 4) resize_route_table(max_route_slots / 2); } else { struct babel_route *r = routes[i]; while(r->next != route) r = r->next; r->next = route->next; route->next = NULL; free(route); } if(lost) route_lost(src, oldmetric); release_source(src); } void flush_all_routes() { int i; /* Start from the end, to avoid shifting the table. */ i = route_slots - 1; while(i >= 0) { while(i < route_slots) { /* Uninstall first, to avoid calling route_lost. */ if(routes[i]->installed) uninstall_route(routes[0]); flush_route(routes[i]); } i--; } check_sources_released(); } void flush_neighbour_routes(struct neighbour *neigh) { int i; i = 0; while(i < route_slots) { struct babel_route *r; r = routes[i]; while(r) { if(r->neigh == neigh) { flush_route(r); goto again; } r = r->next; } i++; again: ; } } void flush_interface_routes(struct interface *ifp, int v4only) { int i; i = 0; while(i < route_slots) { struct babel_route *r; r = routes[i]; while(r) { if(r->neigh->ifp == ifp && (!v4only || v4mapped(r->nexthop))) { flush_route(r); goto again; } r = r->next; } i++; again: ; } } /* Iterate a function over all routes. */ void for_all_routes(void (*f)(struct babel_route*, void*), void *closure) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { (*f)(r, closure); r = r->next; } } } void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure) { int i; for(i = 0; i < route_slots; i++) { if(routes[i]->installed) (*f)(routes[i], closure); } } static int metric_to_kernel(int metric) { return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; } /* This is used to maintain the invariant that the installed route is at the head of the list. */ static void move_installed_route(struct babel_route *route, int i) { assert(i >= 0 && i < route_slots); assert(route->installed); if(route != routes[i]) { struct babel_route *r = routes[i]; while(r->next != route) r = r->next; r->next = route->next; route->next = routes[i]; routes[i] = route; } } void install_route(struct babel_route *route) { int i, rc; if(route->installed) return; if(!route_feasible(route)) zlog_err("WARNING: installing unfeasible route " "(this shouldn't happen)."); i = find_route_slot(route->src->prefix, route->src->plen, NULL); assert(i >= 0 && i < route_slots); if(routes[i] != route && routes[i]->installed) { fprintf(stderr, "WARNING: attempting to install duplicate route " "(this shouldn't happen)."); return; } rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) { int save = errno; zlog_err("kernel_route(ADD): %s", safe_strerror(errno)); if(save != EEXIST) return; } route->installed = 1; move_installed_route(route, i); } void uninstall_route(struct babel_route *route) { int rc; if(!route->installed) return; rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, metric_to_kernel(route_metric(route)), NULL, 0, 0); if(rc < 0) zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno)); route->installed = 0; } /* This is equivalent to uninstall_route followed with install_route, but without the race condition. The destination of both routes must be the same. */ static void switch_routes(struct babel_route *old, struct babel_route *new) { int rc; if(!old) { install_route(new); return; } if(!old->installed) return; if(!route_feasible(new)) zlog_err("WARNING: switching to unfeasible route " "(this shouldn't happen)."); rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, old->nexthop, old->neigh->ifp->ifindex, metric_to_kernel(route_metric(old)), new->nexthop, new->neigh->ifp->ifindex, metric_to_kernel(route_metric(new))); if(rc < 0) { zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno)); return; } old->installed = 0; new->installed = 1; move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, NULL)); } static void change_route_metric(struct babel_route *route, unsigned refmetric, unsigned cost, unsigned add) { int old, new; int newmetric = MIN(refmetric + cost + add, INFINITY); old = metric_to_kernel(route_metric(route)); new = metric_to_kernel(newmetric); if(route->installed && old != new) { int rc; rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, old, route->nexthop, route->neigh->ifp->ifindex, new); if(rc < 0) { zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno)); return; } } route->refmetric = refmetric; route->cost = cost; route->add_metric = add; } static void retract_route(struct babel_route *route) { change_route_metric(route, INFINITY, INFINITY, 0); } int route_feasible(struct babel_route *route) { return update_feasible(route->src, route->seqno, route->refmetric); } int route_old(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; } int route_expired(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time; } static int channels_interfere(int ch1, int ch2) { if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING || ch2 == BABEL_IF_CHANNEL_NONINTERFERING) return 0; if(ch1 == BABEL_IF_CHANNEL_INTERFERING || ch2 == BABEL_IF_CHANNEL_INTERFERING) return 1; return ch1 == ch2; } int route_interferes(struct babel_route *route, struct interface *ifp) { struct babel_interface *babel_ifp = NULL; switch(diversity_kind) { case DIVERSITY_NONE: return 1; case DIVERSITY_INTERFACE_1: return route->neigh->ifp == ifp; case DIVERSITY_CHANNEL_1: case DIVERSITY_CHANNEL: if(route->neigh->ifp == ifp) return 1; babel_ifp = babel_get_if_nfo(ifp); if(channels_interfere(babel_ifp->channel, babel_get_if_nfo(route->neigh->ifp)->channel)) return 1; if(diversity_kind == DIVERSITY_CHANNEL) { int i; for(i = 0; i < DIVERSITY_HOPS; i++) { if(route->channels[i] == 0) break; if(channels_interfere(babel_ifp->channel, route->channels[i])) return 1; } } return 0; default: fprintf(stderr, "Unknown kind of diversity.\n"); return 1; } } int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric) { if(src == NULL) return 1; if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) /* Never mind what is probably stale data */ return 1; if(refmetric >= INFINITY) /* Retractions are always feasible */ return 1; return (seqno_compare(seqno, src->seqno) > 0 || (src->seqno == seqno && refmetric < src->metric)); } /* This returns the feasible route with the smallest metric. */ struct babel_route * find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude) { struct babel_route *route = NULL, *r = NULL; int i = find_route_slot(prefix, plen, NULL); if(i < 0) return NULL; route = routes[i]; r = route->next; while(r) { if(!route_expired(r) && (!feasible || route_feasible(r)) && (!exclude || r->neigh != exclude) && (route_metric(r) < route_metric(route))) route = r; r = r->next; } return route; } void update_route_metric(struct babel_route *route) { int oldmetric = route_metric(route); if(route_expired(route)) { if(route->refmetric < INFINITY) { route->seqno = seqno_plus(route->src->seqno, 1); retract_route(route); if(oldmetric < INFINITY) route_changed(route, route->src, oldmetric); } } else { struct neighbour *neigh = route->neigh; int add_metric = input_filter(route->src->id, route->src->prefix, route->src->plen, neigh->address, neigh->ifp->ifindex); change_route_metric(route, route->refmetric, neighbour_cost(route->neigh), add_metric); if(route_metric(route) != oldmetric) route_changed(route, route->src, oldmetric); } } /* Called whenever a neighbour's cost changes, to update the metric of all routes through that neighbour. Calls local_notify_neighbour. */ void update_neighbour_metric(struct neighbour *neigh, int changed) { if(changed) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh == neigh) update_route_metric(r); r = r->next; } } } } void update_interface_metric(struct interface *ifp) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh->ifp == ifp) update_route_metric(r); r = r->next; } } } /* This is called whenever we receive an update. */ struct babel_route * update_route(const unsigned char *router_id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, const unsigned char *channels, int channels_len) { struct babel_route *route; struct source *src; int metric, feasible; int add_metric; int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); if(memcmp(router_id, myid, 8) == 0) return NULL; if(martian_prefix(prefix, plen)) { zlog_err("Rejecting martian route to %s through %s.", format_prefix(prefix, plen), format_address(router_id)); return NULL; } add_metric = input_filter(router_id, prefix, plen, neigh->address, neigh->ifp->ifindex); if(add_metric >= INFINITY) return NULL; route = find_route(prefix, plen, neigh, nexthop); if(route && memcmp(route->src->id, router_id, 8) == 0) /* Avoid scanning the source table. */ src = route->src; else src = find_source(router_id, prefix, plen, 1, seqno); if(src == NULL) return NULL; feasible = update_feasible(src, seqno, refmetric); metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); if(route) { struct source *oldsrc; unsigned short oldmetric; int lost = 0; oldsrc = route->src; oldmetric = route_metric(route); /* If a successor switches sources, we must accept his update even if it makes a route unfeasible in order to break any routing loops in a timely manner. If the source remains the same, we ignore the update. */ if(!feasible && route->installed) { debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s " "(%s %d %d -> %s %d %d).", format_prefix(src->prefix, src->plen), format_address(route->src->id), route->seqno, route->refmetric, format_address(src->id), seqno, refmetric); if(src != route->src) { uninstall_route(route); lost = 1; } } route->src = retain_source(src); if((feasible || keep_unfeasible) && refmetric < INFINITY) route->time = babel_now.tv_sec; route->seqno = seqno; change_route_metric(route, refmetric, neighbour_cost(neigh), add_metric); route->hold_time = hold_time; route_changed(route, oldsrc, oldmetric); if(lost) route_lost(oldsrc, oldmetric); if(!feasible) send_unfeasible_request(neigh, route->installed && route_old(route), seqno, metric, src); release_source(oldsrc); } else { struct babel_route *new_route; if(refmetric >= INFINITY) /* Somebody's retracting a route we never saw. */ return NULL; if(!feasible) { send_unfeasible_request(neigh, 0, seqno, metric, src); if(!keep_unfeasible) return NULL; } route = malloc(sizeof(struct babel_route)); if(route == NULL) { perror("malloc(route)"); return NULL; } route->src = retain_source(src); route->refmetric = refmetric; route->cost = neighbour_cost(neigh); route->add_metric = add_metric; route->seqno = seqno; route->neigh = neigh; memcpy(route->nexthop, nexthop, 16); route->time = babel_now.tv_sec; route->hold_time = hold_time; route->installed = 0; memset(&route->channels, 0, sizeof(route->channels)); if(channels_len > 0) memcpy(&route->channels, channels, MIN(channels_len, DIVERSITY_HOPS)); route->next = NULL; new_route = insert_route(route); if(new_route == NULL) { fprintf(stderr, "Couldn't insert route.\n"); free(route); return NULL; } consider_route(route); } return route; } /* We just received an unfeasible update. If it's any good, send a request for a new seqno. */ void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src) { struct babel_route *route = find_installed_route(src->prefix, src->plen); if(seqno_minus(src->seqno, seqno) > 100) { /* Probably a source that lost its seqno. Let it time-out. */ return; } if(force || !route || route_metric(route) >= metric + 512) { send_unicast_multihop_request(neigh, src->prefix, src->plen, src->metric >= INFINITY ? src->seqno : seqno_plus(src->seqno, 1), src->id, 127); } } /* This takes a feasible route and decides whether to install it. */ static void consider_route(struct babel_route *route) { struct babel_route *installed; struct xroute *xroute; if(route->installed) return; if(!route_feasible(route)) return; xroute = find_xroute(route->src->prefix, route->src->plen); if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates)) return; installed = find_installed_route(route->src->prefix, route->src->plen); if(installed == NULL) goto install; if(route_metric(route) >= INFINITY) return; if(route_metric(installed) >= INFINITY) goto install; if(route_metric(installed) >= route_metric(route) + 64) goto install; return; install: switch_routes(installed, route); if(installed && route->installed) send_triggered_update(route, installed->src, route_metric(installed)); else send_update(NULL, 1, route->src->prefix, route->src->plen); return; } void retract_neighbour_routes(struct neighbour *neigh) { int i; for(i = 0; i < route_slots; i++) { struct babel_route *r = routes[i]; while(r) { if(r->neigh == neigh) { if(r->refmetric != INFINITY) { unsigned short oldmetric = route_metric(r); retract_route(r); if(oldmetric != INFINITY) route_changed(r, r->src, oldmetric); } } r = r->next; } i++; } } void send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric) { unsigned newmetric, diff; /* 1 means send speedily, 2 means resend */ int urgent; if(!route->installed) return; newmetric = route_metric(route); diff = newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric; if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY)) /* Switching sources can cause transient routing loops. Retractions can cause blackholes. */ urgent = 2; else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512) /* Route getting significantly worse */ urgent = 1; else if(unsatisfied_request(route->src->prefix, route->src->plen, route->seqno, route->src->id)) /* Make sure that requests are satisfied speedily */ urgent = 1; else if(oldmetric >= INFINITY && newmetric < INFINITY) /* New route */ urgent = 0; else if(newmetric < oldmetric && diff < 1024) /* Route getting better. This may be a transient fluctuation, so don't advertise it to avoid making routes unfeasible later on. */ return; else if(diff < 384) /* Don't fret about trivialities */ return; else urgent = 0; if(urgent >= 2) send_update_resend(NULL, route->src->prefix, route->src->plen); else send_update(NULL, urgent, route->src->prefix, route->src->plen); if(oldmetric < INFINITY) { if(newmetric >= oldmetric + 512) { send_request_resend(NULL, route->src->prefix, route->src->plen, route->src->metric >= INFINITY ? route->src->seqno : seqno_plus(route->src->seqno, 1), route->src->id); } else if(newmetric >= oldmetric + 288) { send_request(NULL, route->src->prefix, route->src->plen); } } } /* A route has just changed. Decide whether to switch to a different route or send an update. */ void route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric) { if(route->installed) { if(route_metric(route) > oldmetric) { struct babel_route *better_route; better_route = find_best_route(route->src->prefix, route->src->plen, 1, NULL); if(better_route && route_metric(better_route) <= route_metric(route) - 96) consider_route(better_route); } if(route->installed) /* We didn't change routes after all. */ send_triggered_update(route, oldsrc, oldmetric); } else { /* Reconsider routes even when their metric didn't decrease, they may not have been feasible before. */ consider_route(route); } } /* We just lost the installed route to a given destination. */ void route_lost(struct source *src, unsigned oldmetric) { struct babel_route *new_route; new_route = find_best_route(src->prefix, src->plen, 1, NULL); if(new_route) { consider_route(new_route); } else if(oldmetric < INFINITY) { /* Complain loudly. */ send_update_resend(NULL, src->prefix, src->plen); send_request_resend(NULL, src->prefix, src->plen, src->metric >= INFINITY ? src->seqno : seqno_plus(src->seqno, 1), src->id); } } /* This is called periodically to flush old routes. It will also send requests for routes that are about to expire. */ void expire_routes(void) { struct babel_route *r; int i; debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); i = 0; while(i < route_slots) { r = routes[i]; while(r) { /* Protect against clock being stepped. */ if(r->time > babel_now.tv_sec || route_old(r)) { flush_route(r); goto again; } update_route_metric(r); if(r->installed && r->refmetric < INFINITY) { if(route_old(r)) /* Route about to expire, send a request. */ send_unicast_request(r->neigh, r->src->prefix, r->src->plen); } r = r->next; } i++; again: ; } } quagga-0.99.24.1/babeld/neighbour.c0000644000175000017500000002445112476520570013601 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include "if.h" #include "babel_main.h" #include "babeld.h" #include "util.h" #include "babel_interface.h" #include "neighbour.h" #include "source.h" #include "route.h" #include "message.h" #include "resend.h" struct neighbour *neighs = NULL; static struct neighbour * find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; FOR_ALL_NEIGHBOURS(neigh) { if(memcmp(address, neigh->address, 16) == 0 && neigh->ifp == ifp) return neigh; } return NULL; } void flush_neighbour(struct neighbour *neigh) { flush_neighbour_routes(neigh); if(unicast_neighbour == neigh) flush_unicast(1); flush_resends(neigh); if(neighs == neigh) { neighs = neigh->next; } else { struct neighbour *previous = neighs; while(previous->next != neigh) previous = previous->next; previous->next = neigh->next; } free(neigh); } struct neighbour * find_neighbour(const unsigned char *address, struct interface *ifp) { struct neighbour *neigh; const struct timeval zero = {0, 0}; neigh = find_neighbour_nocreate(address, ifp); if(neigh) return neigh; debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.", format_address(address), ifp->name); neigh = malloc(sizeof(struct neighbour)); if(neigh == NULL) { zlog_err("malloc(neighbour): %s", safe_strerror(errno)); return NULL; } neigh->hello_seqno = -1; memcpy(neigh->address, address, 16); neigh->reach = 0; neigh->txcost = INFINITY; neigh->ihu_time = babel_now; neigh->hello_time = zero; neigh->hello_interval = 0; neigh->ihu_interval = 0; neigh->ifp = ifp; neigh->next = neighs; neighs = neigh; send_hello(ifp); return neigh; } /* Recompute a neighbour's rxcost. Return true if anything changed. This does not call local_notify_neighbour, see update_neighbour_metric. */ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval) { int missed_hellos; int rc = 0; if(hello < 0) { if(neigh->hello_interval <= 0) return rc; missed_hellos = ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) - neigh->hello_interval * 7) / (neigh->hello_interval * 10); if(missed_hellos <= 0) return rc; timeval_add_msec(&neigh->hello_time, &neigh->hello_time, missed_hellos * neigh->hello_interval * 10); } else { if(neigh->hello_seqno >= 0 && neigh->reach > 0) { missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; if(missed_hellos < -8) { /* Probably a neighbour that rebooted and lost its seqno. Reboot the universe. */ neigh->reach = 0; missed_hellos = 0; rc = 1; } else if(missed_hellos < 0) { if(hello_interval > neigh->hello_interval) { /* This neighbour has increased its hello interval, and we didn't notice. */ neigh->reach <<= -missed_hellos; missed_hellos = 0; } else { /* Late hello. Probably due to the link layer buffering packets during a link outage. Ignore it, but reset the expected seqno. */ neigh->hello_seqno = hello; hello = -1; missed_hellos = 0; } rc = 1; } } else { missed_hellos = 0; } neigh->hello_time = babel_now; neigh->hello_interval = hello_interval; } if(missed_hellos > 0) { neigh->reach >>= missed_hellos; neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos); missed_hellos = 0; rc = 1; } if(hello >= 0) { neigh->hello_seqno = hello; neigh->reach >>= 1; neigh->reach |= 0x8000; if((neigh->reach & 0xFC00) != 0xFC00) rc = 1; } /* Make sure to give neighbours some feedback early after association */ if((neigh->reach & 0xBF00) == 0x8000) { /* A new neighbour */ send_hello(neigh->ifp); } else { /* Don't send hellos, in order to avoid a positive feedback loop. */ int a = (neigh->reach & 0xC000); int b = (neigh->reach & 0x3000); if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { /* Reachability is either 1100 or 0011 */ send_self_update(neigh->ifp); } } if((neigh->reach & 0xFC00) == 0xC000) { /* This is a newish neighbour, let's request a full route dump. We ought to avoid this when the network is dense */ send_unicast_request(neigh, NULL, 0); send_ihu(neigh, NULL); } return rc; } static int reset_txcost(struct neighbour *neigh) { unsigned delay; delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U) return 0; /* If we're losing a lot of packets, we probably lost an IHU too */ if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || (neigh->ihu_interval > 0 && delay >= neigh->ihu_interval * 10U * 10U)) { neigh->txcost = INFINITY; neigh->ihu_time = babel_now; return 1; } return 0; } unsigned neighbour_txcost(struct neighbour *neigh) { return neigh->txcost; } unsigned check_neighbours() { struct neighbour *neigh; int changed, rc; unsigned msecs = 50000; debugf(BABEL_DEBUG_COMMON,"Checking neighbours."); neigh = neighs; while(neigh) { changed = update_neighbour(neigh, -1, 0); if(neigh->reach == 0 || neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */ timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) { struct neighbour *old = neigh; neigh = neigh->next; flush_neighbour(old); continue; } rc = reset_txcost(neigh); changed = changed || rc; update_neighbour_metric(neigh, changed); if(neigh->hello_interval > 0) msecs = MIN(msecs, neigh->hello_interval * 10U); if(neigh->ihu_interval > 0) msecs = MIN(msecs, neigh->ihu_interval * 10U); neigh = neigh->next; } return msecs; } unsigned neighbour_rxcost(struct neighbour *neigh) { unsigned delay; unsigned short reach = neigh->reach; delay = timeval_minus_msec(&babel_now, &neigh->hello_time); if((reach & 0xFFF0) == 0 || delay >= 180000) { return INFINITY; } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { int sreach = ((reach & 0x8000) >> 2) + ((reach & 0x4000) >> 1) + (reach & 0x3FFF); /* 0 <= sreach <= 0x7FFF */ int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); /* cost >= interface->cost */ if(delay >= 40000) cost = (cost * (delay - 20000) + 10000) / 20000; return MIN(cost, INFINITY); } else { /* To lose one hello is a misfortune, to lose two is carelessness. */ if((reach & 0xC000) == 0xC000) return babel_get_if_nfo(neigh->ifp)->cost; else if((reach & 0xC000) == 0) return INFINITY; else if((reach & 0x2000)) return babel_get_if_nfo(neigh->ifp)->cost; else return INFINITY; } } unsigned neighbour_cost(struct neighbour *neigh) { unsigned a, b; if(!if_up(neigh->ifp)) return INFINITY; a = neighbour_txcost(neigh); if(a >= INFINITY) return INFINITY; b = neighbour_rxcost(neigh); if(b >= INFINITY) return INFINITY; if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) || (a < 256 && b < 256)) { return a; } else { /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected probabilities of a packet getting through in the direct and reverse directions. */ a = MAX(a, 256); b = MAX(b, 256); /* 1/(alpha * beta), which is just plain ETX. */ /* Since a and b are capped to 16 bits, overflow is impossible. */ return (a * b + 128) >> 8; } } quagga-0.99.24.1/babeld/source.c0000644000175000017500000001206212476520570013112 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include "babel_main.h" #include "babeld.h" #include "util.h" #include "source.h" #include "babel_interface.h" #include "route.h" struct source *srcs = NULL; struct source* find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno) { struct source *src; for(src = srcs; src; src = src->next) { /* This should really be a hash table. For now, check the last byte first. */ if(src->id[7] != id[7]) continue; if(memcmp(src->id, id, 8) != 0) continue; if(src->plen != plen) continue; if(memcmp(src->prefix, p, 16) == 0) return src; } if(!create) return NULL; src = malloc(sizeof(struct source)); if(src == NULL) { zlog_err("malloc(source): %s", safe_strerror(errno)); return NULL; } memcpy(src->id, id, 8); memcpy(src->prefix, p, 16); src->plen = plen; src->seqno = seqno; src->metric = INFINITY; src->time = babel_now.tv_sec; src->route_count = 0; src->next = srcs; srcs = src; return src; } struct source * retain_source(struct source *src) { assert(src->route_count < 0xffff); src->route_count++; return src; } void release_source(struct source *src) { assert(src->route_count > 0); src->route_count--; } int flush_source(struct source *src) { if(src->route_count > 0) /* The source is in use by a route. */ return 0; if(srcs == src) { srcs = src->next; } else { struct source *previous = srcs; while(previous->next != src) previous = previous->next; previous->next = src->next; } free(src); return 1; } void update_source(struct source *src, unsigned short seqno, unsigned short metric) { if(metric >= INFINITY) return; /* If a source is expired, pretend that it doesn't exist and update it unconditionally. This makes ensures that old data will eventually be overridden, and prevents us from getting stuck if a router loses its sequence number. */ if(src->time < babel_now.tv_sec - SOURCE_GC_TIME || seqno_compare(src->seqno, seqno) < 0 || (src->seqno == seqno && src->metric > metric)) { src->seqno = seqno; src->metric = metric; } src->time = babel_now.tv_sec; } void expire_sources() { struct source *src; src = srcs; while(src) { if(src->time > babel_now.tv_sec) /* clock stepped */ src->time = babel_now.tv_sec; if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) { struct source *old = src; src = src->next; flush_source(old); continue; } src = src->next; } } void check_sources_released(void) { struct source *src; for(src = srcs; src; src = src->next) { if(src->route_count != 0) fprintf(stderr, "Warning: source %s %s has refcount %d.\n", format_eui64(src->id), format_prefix(src->prefix, src->plen), (int)src->route_count); } } quagga-0.99.24.1/babeld/util.c0000644000175000017500000002516212476520570012574 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include "babel_main.h" #include "babeld.h" #include "util.h" unsigned roughly(unsigned value) { return value * 3 / 4 + random() % (value / 2); } /* d = s1 - s2 */ void timeval_minus(struct timeval *d, const struct timeval *s1, const struct timeval *s2) { if(s1->tv_usec >= s2->tv_usec) { d->tv_usec = s1->tv_usec - s2->tv_usec; d->tv_sec = s1->tv_sec - s2->tv_sec; } else { d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec; d->tv_sec = s1->tv_sec - s2->tv_sec - 1; } } unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) { if(s1->tv_sec < s2->tv_sec) return 0; /* Avoid overflow. */ if(s1->tv_sec - s2->tv_sec > 2000000) return 2000000000; if(s1->tv_sec > s2->tv_sec) return (unsigned)((unsigned)(s1->tv_sec - s2->tv_sec) * 1000 + ((int)s1->tv_usec - s2->tv_usec) / 1000); if(s1->tv_usec <= s2->tv_usec) return 0; return (unsigned)(s1->tv_usec - s2->tv_usec) / 1000u; } /* d = s + msecs */ void timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs) { int usecs; d->tv_sec = s->tv_sec + msecs / 1000; usecs = s->tv_usec + (msecs % 1000) * 1000; if(usecs < 1000000) { d->tv_usec = usecs; } else { d->tv_usec = usecs - 1000000; d->tv_sec++; } } void set_timeout(struct timeval *timeout, int msecs) { timeval_add_msec(timeout, &babel_now, roughly(msecs)); } /* returns <0 if "s1" < "s2", etc. */ int timeval_compare(const struct timeval *s1, const struct timeval *s2) { if(s1->tv_sec < s2->tv_sec) return -1; else if(s1->tv_sec > s2->tv_sec) return 1; else if(s1->tv_usec < s2->tv_usec) return -1; else if(s1->tv_usec > s2->tv_usec) return 1; else return 0; } /* set d at min(d, s) */ /* {0, 0} represents infinity */ void timeval_min(struct timeval *d, const struct timeval *s) { if(s->tv_sec == 0) return; if(d->tv_sec == 0 || timeval_compare(d, s) > 0) { *d = *s; } } /* set d to min(d, x) with x in [secs, secs+1] */ void timeval_min_sec(struct timeval *d, time_t secs) { if(d->tv_sec == 0 || d->tv_sec > secs) { d->tv_sec = secs; d->tv_usec = random() % 1000000; } } /* parse a float value in second and return the corresponding mili-seconds. For example: parse_msec("12.342345") returns 12342 */ int parse_msec(const char *string) { unsigned int in, fl; int i, j; in = fl = 0; i = 0; while(string[i] == ' ' || string[i] == '\t') i++; while(string[i] >= '0' && string[i] <= '9') { in = in * 10 + string[i] - '0'; i++; } if(string[i] == '.') { i++; j = 0; while(string[i] >= '0' && string[i] <= '9') { fl = fl * 10 + string[i] - '0'; i++; j++; } while(j > 3) { fl /= 10; j--; } while(j < 3) { fl *= 10; j++; } } while(string[i] == ' ' || string[i] == '\t') i++; if(string[i] == '\0') return in * 1000 + fl; return -1; } int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) { unsigned char m; if(plen > 128) plen = 128; if(memcmp(address, prefix, plen / 8) != 0) return 0; if(plen % 8 == 0) return 1; m = 0xFF << (8 - (plen % 8)); return ((address[plen / 8] & m) == (prefix[plen / 8] & m)); } unsigned char * mask_prefix(unsigned char *restrict ret, const unsigned char *restrict prefix, unsigned char plen) { if(plen >= 128) { memcpy(ret, prefix, 16); return ret; } memset(ret, 0, 16); memcpy(ret, prefix, plen / 8); if(plen % 8 != 0) ret[plen / 8] = (prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF)); return ret; } static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; static const unsigned char llprefix[16] = {0xFE, 0x80}; const char * format_address(const unsigned char *address) { static char buf[4][INET6_ADDRSTRLEN]; static int i = 0; i = (i + 1) % 4; if(v4mapped(address)) inet_ntop(AF_INET, address + 12, buf[i], INET6_ADDRSTRLEN); else inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN); return buf[i]; } const char * format_prefix(const unsigned char *prefix, unsigned char plen) { static char buf[4][INET6_ADDRSTRLEN + 4]; static int i = 0; int n; i = (i + 1) % 4; if(plen >= 96 && v4mapped(prefix)) { inet_ntop(AF_INET, prefix + 12, buf[i], INET6_ADDRSTRLEN); n = strlen(buf[i]); snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen - 96); } else { inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN); n = strlen(buf[i]); snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen); } return buf[i]; } const char * format_eui64(const unsigned char *eui) { static char buf[4][28]; static int i = 0; i = (i + 1) % 4; snprintf(buf[i], 28, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", eui[0], eui[1], eui[2], eui[3], eui[4], eui[5], eui[6], eui[7]); return buf[i]; } const char *format_bool(const int b) { return b ? "true" : "false"; } int parse_address(const char *address, unsigned char *addr_r, int *af_r) { struct in_addr ina; struct in6_addr ina6; int rc; rc = inet_pton(AF_INET, address, &ina); if(rc > 0) { memcpy(addr_r, v4prefix, 12); memcpy(addr_r + 12, &ina, 4); if(af_r) *af_r = AF_INET; return 0; } rc = inet_pton(AF_INET6, address, &ina6); if(rc > 0) { memcpy(addr_r, &ina6, 16); if(af_r) *af_r = AF_INET6; return 0; } return -1; } int parse_eui64(const char *eui, unsigned char *eui_r) { int n; n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 8) return 0; n = sscanf(eui, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 8) return 0; n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[5], &eui_r[6], &eui_r[7]); if(n == 6) { eui_r[3] = 0xFF; eui_r[4] = 0xFE; return 0; } return -1; } int wait_for_fd(int direction, int fd, int msecs) { fd_set fds; int rc; struct timeval tv; tv.tv_sec = msecs / 1000; tv.tv_usec = (msecs % 1000) * 1000; FD_ZERO(&fds); FD_SET(fd, &fds); if(direction) rc = select(fd + 1, NULL, &fds, NULL, &tv); else rc = select(fd + 1, &fds, NULL, NULL, &tv); return rc; } int martian_prefix(const unsigned char *prefix, int plen) { return (plen >= 8 && prefix[0] == 0xFF) || (plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) || (plen >= 128 && memcmp(prefix, zeroes, 15) == 0 && (prefix[15] == 0 || prefix[15] == 1)) || (plen >= 96 && v4mapped(prefix) && ((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) || (plen >= 100 && (prefix[12] & 0xE0) == 0xE0))); } int linklocal(const unsigned char *address) { return memcmp(address, llprefix, 8) == 0; } int v4mapped(const unsigned char *address) { return memcmp(address, v4prefix, 12) == 0; } void v4tov6(unsigned char *dst, const unsigned char *src) { memcpy(dst, v4prefix, 12); memcpy(dst + 12, src, 4); } void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src) { memcpy(dest, v4prefix, 12); memcpy(dest + 12, src, 4); assert(v4mapped(dest)); } void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src) { assert(v4mapped(src)); memcpy(dest, src + 12, 4); } void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src) { memcpy(dest, src, 16); } void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src) { memcpy(dest, src, 16); } int daemonise() { int rc; fflush(stdout); fflush(stderr); rc = fork(); if(rc < 0) return -1; if(rc > 0) exit(0); rc = setsid(); if(rc < 0) return -1; return 1; } quagga-0.99.24.1/babeld/kernel.c0000644000175000017500000002351712476520570013101 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek Copyright 2011, 2012 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include "babeld.h" #include #include #include #include #include #include #include "prefix.h" #include "zclient.h" #include "kernel.h" #include "privs.h" #include "command.h" #include "vty.h" #include "memory.h" #include "thread.h" #include "util.h" #include "babel_interface.h" #include "babel_zebra.h" static int kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric); static int kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric); int kernel_interface_operational(struct interface *interface) { return if_is_operative(interface); } int kernel_interface_mtu(struct interface *interface) { return MIN(interface->mtu, interface->mtu6); } int kernel_interface_wireless(struct interface *interface) { return 0; } int kernel_route(int operation, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric) { int rc; int ipv4; /* Check that the protocol family is consistent. */ if(plen >= 96 && v4mapped(pref)) { if(!v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 1; } else { if(v4mapped(gate)) { errno = EINVAL; return -1; } ipv4 = 0; } switch (operation) { case ROUTE_ADD: return ipv4 ? kernel_route_v4(1, pref, plen, gate, ifindex, metric): kernel_route_v6(1, pref, plen, gate, ifindex, metric); break; case ROUTE_FLUSH: return ipv4 ? kernel_route_v4(0, pref, plen, gate, ifindex, metric): kernel_route_v6(0, pref, plen, gate, ifindex, metric); break; case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); rc = ipv4 ? kernel_route_v4(0, pref, plen, gate, ifindex, metric): kernel_route_v6(0, pref, plen, gate, ifindex, metric); if (rc < 0) return -1; rc = ipv4 ? kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); return rc; break; default: zlog_err("this should never appens (false value - kernel_route)"); assert(0); exit(1); break; } } static int kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { struct zapi_ipv4 api; /* quagga's communication system */ struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ struct in_addr babel_prefix_addr; /* babeld's prefix addr */ struct in_addr nexthop; /* next router to go */ struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_inaddr(&babel_prefix_addr, pref); uchar_to_inaddr(&nexthop, gate); /* make prefix structure */ memset (&quagga_prefix, 0, sizeof(quagga_prefix)); quagga_prefix.family = AF_INET; IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ apply_mask_ipv4(&quagga_prefix); api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; /* Unlike the native Linux and BSD interfaces, Quagga doesn't like there to be both and IPv4 nexthop and an ifindex. Omit the ifindex, and assume that the connected prefixes be set up correctly. */ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.ifindex_num = 0; if(metric >= KERNEL_INFINITY) { api.flags = ZEBRA_FLAG_BLACKHOLE; api.nexthop_num = 0; } else { api.nexthop_num = 1; api.nexthop = &nexthop_pointer; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; } debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", add ? "adding" : "removing" ); return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : ZEBRA_IPV4_ROUTE_DELETE, zclient, &quagga_prefix, &api); } static int kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv6 api; /* quagga's communication system */ struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ struct in6_addr nexthop; /* next router to go */ struct in6_addr *nexthop_pointer = &nexthop; /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_in6addr(&babel_prefix_addr, pref); uchar_to_in6addr(&nexthop, gate); /* make prefix structure */ memset (&quagga_prefix, 0, sizeof(quagga_prefix)); quagga_prefix.family = AF_INET6; IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); quagga_prefix.prefixlen = plen; apply_mask_ipv6(&quagga_prefix); api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if(metric >= KERNEL_INFINITY) { api.flags = ZEBRA_FLAG_BLACKHOLE; api.nexthop_num = 0; api.ifindex_num = 0; } else { api.nexthop_num = 1; api.nexthop = &nexthop_pointer; SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &tmp_ifindex; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; } debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", add ? "adding" : "removing" ); return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : ZEBRA_IPV6_ROUTE_DELETE, zclient, &quagga_prefix, &api); } int if_eui64(char *ifname, int ifindex, unsigned char *eui) { struct interface *ifp = if_lookup_by_index(ifindex); if (ifp == NULL) { return -1; } #ifdef HAVE_STRUCT_SOCKADDR_DL u_char len = ifp->sdl.sdl_alen; char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; #else u_char len = (u_char) ifp->hw_addr_len; char *tmp = (void*) ifp->hw_addr; #endif if (len == 8) { memcpy(eui, tmp, 8); eui[0] ^= 2; } else if (len == 6) { memcpy(eui, tmp, 3); eui[3] = 0xFF; eui[4] = 0xFE; memcpy(eui+5, tmp+3, 3); } else { return -1; } return 0; } /* Like gettimeofday, but returns monotonic time. If POSIX clocks are not available, falls back to gettimeofday but enforces monotonicity. */ int gettime(struct timeval *tv) { return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv); } /* If /dev/urandom doesn't exist, this will fail with ENOENT, which the caller will deal with gracefully. */ int read_random_bytes(void *buf, size_t len) { int fd; int rc; fd = open("/dev/urandom", O_RDONLY); if(fd < 0) { rc = -1; } else { rc = read(fd, buf, len); if(rc < 0 || (unsigned) rc < len) rc = -1; close(fd); } return rc; } quagga-0.99.24.1/babeld/net.c0000644000175000017500000001361312476520570012403 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "babeld.h" #include "util.h" #include "net.h" int babel_socket(int port) { struct sockaddr_in6 sin6; int s, rc; int saved_errno; int one = 1, zero = 0; const int ds = 0xc0; /* CS6 - Network Control */ s = socket(PF_INET6, SOCK_DGRAM, 0); if(s < 0) return -1; rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one)); if(rc < 0) goto fail; rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &one, sizeof(one)); if(rc < 0) goto fail; #ifdef IPV6_TCLASS rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); #else rc = -1; errno = ENOSYS; #endif if(rc < 0) perror("Couldn't set traffic class"); rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFD, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); if(rc < 0) goto fail; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) goto fail; return s; fail: saved_errno = errno; close(s); errno = saved_errno; return -1; } int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) { struct iovec iovec; struct msghdr msg; int rc; memset(&msg, 0, sizeof(msg)); iovec.iov_base = buf; iovec.iov_len = buflen; msg.msg_name = sin; msg.msg_namelen = slen; msg.msg_iov = &iovec; msg.msg_iovlen = 1; rc = recvmsg(s, &msg, 0); return rc; } int babel_send(int s, void *buf1, int buflen1, void *buf2, int buflen2, struct sockaddr *sin, int slen) { struct iovec iovec[2]; struct msghdr msg; int rc; iovec[0].iov_base = buf1; iovec[0].iov_len = buflen1; iovec[1].iov_base = buf2; iovec[1].iov_len = buflen2; memset(&msg, 0, sizeof(msg)); msg.msg_name = (struct sockaddr*)sin; msg.msg_namelen = slen; msg.msg_iov = iovec; msg.msg_iovlen = 2; again: rc = sendmsg(s, &msg, 0); if(rc < 0) { if(errno == EINTR) goto again; else if(errno == EAGAIN) { int rc2; rc2 = wait_for_fd(1, s, 5); if(rc2 > 0) goto again; errno = EAGAIN; } } return rc; } int tcp_server_socket(int port, int local) { struct sockaddr_in6 sin6; int s, rc, saved_errno; int one = 1; s = socket(PF_INET6, SOCK_STREAM, 0); if(s < 0) return -1; rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); if(rc < 0) goto fail; rc = fcntl(s, F_GETFD, 0); if(rc < 0) goto fail; rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); if(rc < 0) goto fail; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); if(local) { rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr); if(rc < 0) goto fail; } rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) goto fail; rc = listen(s, 2); if(rc < 0) goto fail; return s; fail: saved_errno = errno; close(s); errno = saved_errno; return -1; } quagga-0.99.24.1/babeld/babel_zebra.c0000644000175000017500000002535612476520570014054 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* quagga's includes */ #include #include "command.h" #include "zclient.h" #include "stream.h" /* babel's includes*/ #include "babel_zebra.h" #include "babel_interface.h" #include "xroute.h" #include "util.h" void babelz_zebra_init(void); /* we must use a pointer because of zclient.c's functions (new, free). */ struct zclient *zclient; static int zebra_config_write (struct vty *vty); /* Debug types */ static struct { int type; int str_min_len; const char *str; } debug_type[] = { {BABEL_DEBUG_COMMON, 1, "common"}, {BABEL_DEBUG_KERNEL, 1, "kernel"}, {BABEL_DEBUG_FILTER, 1, "filter"}, {BABEL_DEBUG_TIMEOUT, 1, "timeout"}, {BABEL_DEBUG_IF, 1, "interface"}, {BABEL_DEBUG_ROUTE, 1, "route"}, {BABEL_DEBUG_ALL, 1, "all"}, {0, 0, NULL} }; /* Zebra node structure. */ struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", 1 /* vtysh? yes */ }; /* Zebra route add and delete treatment (ipv6). */ static int babel_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex = -1; struct in6_addr nexthop; struct prefix_ipv6 prefix; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); memset (&api, 0, sizeof(struct zapi_ipv6)); memset (&prefix, 0, sizeof (struct prefix_ipv6)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ prefix.family = AF_INET6; prefix.prefixlen = stream_getc (s); stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, sizeof(nexthop)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop); else babel_ipv6_route_delete(&api, &prefix, ifindex); return 0; } static int babel_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex = -1; struct in_addr nexthop; struct prefix_ipv4 prefix; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in_addr)); memset (&api, 0, sizeof(struct zapi_ipv4)); memset (&prefix, 0, sizeof (struct prefix_ipv4)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ prefix.family = AF_INET; prefix.prefixlen = stream_getc (s); stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, sizeof(nexthop)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) { babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop); } else { babel_ipv4_route_delete(&api, &prefix, ifindex); } return 0; } /* [Babel Command] */ DEFUN (babel_redistribute_type, babel_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_BABELD, "Redistribute\n" QUAGGA_REDIST_HELP_STR_BABELD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) type = proto_redistnum(AFI_IP, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } /* [Babel Command] */ DEFUN (no_babel_redistribute_type, no_babel_redistribute_type_cmd, "no redistribute " QUAGGA_REDIST_STR_BABELD, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_BABELD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) type = proto_redistnum(AFI_IP, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); /* perhaps should we remove xroutes having the same type... */ return CMD_SUCCESS; } #ifndef NO_DEBUG /* [Babel Command] */ DEFUN (debug_babel, debug_babel_cmd, "debug babel (common|kernel|filter|timeout|interface|route|all)", "Enable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") { int i; for(i = 0; debug_type[i].str != NULL; i++) { if (strncmp (debug_type[i].str, argv[0], debug_type[i].str_min_len) == 0) { debug |= debug_type[i].type; return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } /* [Babel Command] */ DEFUN (no_debug_babel, no_debug_babel_cmd, "no debug babel (common|kernel|filter|timeout|interface|route|all)", NO_STR "Disable debug messages for specific or all part.\n" "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" "Timeout messages\n" "Interface messages\n" "Route messages\n" "All messages\n") { int i; for (i = 0; debug_type[i].str; i++) { if (strncmp(debug_type[i].str, argv[0], debug_type[i].str_min_len) == 0) { debug &= ~debug_type[i].type; return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } #endif /* NO_DEBUG */ /* Output "debug" statement lines, if necessary. */ int debug_babel_config_write (struct vty * vty) { #ifdef NO_DEBUG return 0; #else int i, lines = 0; if (debug == BABEL_DEBUG_ALL) { vty_out (vty, "debug babel all%s", VTY_NEWLINE); lines++; } else for (i = 0; debug_type[i].str != NULL; i++) if ( debug_type[i].type != BABEL_DEBUG_ALL && CHECK_FLAG (debug, debug_type[i].type) ) { vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE); lines++; } if (lines) { vty_out (vty, "!%s", VTY_NEWLINE); lines++; } return lines; #endif /* NO_DEBUG */ } void babelz_zebra_init(void) { zclient = zclient_new(); zclient_init(zclient, ZEBRA_ROUTE_BABEL); zclient->interface_add = babel_interface_add; zclient->interface_delete = babel_interface_delete; zclient->interface_up = babel_interface_up; zclient->interface_down = babel_interface_down; zclient->interface_address_add = babel_interface_address_add; zclient->interface_address_delete = babel_interface_address_delete; zclient->ipv4_route_add = babel_zebra_read_ipv4; zclient->ipv4_route_delete = babel_zebra_read_ipv4; zclient->ipv6_route_add = babel_zebra_read_ipv6; zclient->ipv6_route_delete = babel_zebra_read_ipv6; install_node (&zebra_node, zebra_config_write); install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); install_element(ENABLE_NODE, &debug_babel_cmd); install_element(ENABLE_NODE, &no_debug_babel_cmd); install_element(CONFIG_NODE, &debug_babel_cmd); install_element(CONFIG_NODE, &no_debug_babel_cmd); } static int zebra_config_write (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! zclient->redist[ZEBRA_ROUTE_BABEL]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute babel%s", VTY_NEWLINE); return 1; } return 0; } void babel_zebra_close_connexion(void) { zclient_stop(zclient); } quagga-0.99.24.1/babeld/babel_main.h0000644000175000017500000000454512476520570013677 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "vty.h" extern struct timeval babel_now; /* current time */ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; extern int resend_delay; extern unsigned char myid[8]; extern const unsigned char zeroes[16], ones[16]; extern int protocol_port; extern unsigned char protocol_group[16]; extern int protocol_socket; extern int kernel_socket; extern int max_request_hopcount; void babel_load_state_file(void); void show_babel_main_configuration (struct vty *vty); quagga-0.99.24.1/babeld/babel_filter.h0000644000175000017500000000415612476520570014236 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABELD_BABEL_FILTER_H #define BABELD_BABEL_FILTER_H #include #include "prefix.h" #include "babel_interface.h" int babel_filter(int output, const unsigned char *prefix, unsigned short plen, unsigned int index); #endif /* BABELD_BABEL_FILTER_H */ quagga-0.99.24.1/babeld/babeld.h0000644000175000017500000001045412476520570013033 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_BABELD_H #define BABEL_BABELD_H #include #include "vty.h" #define INFINITY ((unsigned short)(~0)) #ifndef RTPROT_BABEL #define RTPROT_BABEL 42 #endif #define RTPROT_BABEL_LOCAL -2 #undef MAX #undef MIN #define MAX(x,y) ((x)<=(y)?(y):(x)) #define MIN(x,y) ((x)<=(y)?(x):(y)) #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* nothing */ #elif defined(__GNUC__) #define inline __inline #if (__GNUC__ >= 3) #define restrict __restrict #else #define restrict /**/ #endif #else #define inline /**/ #define restrict /**/ #endif #if defined(__GNUC__) && (__GNUC__ >= 3) #define ATTRIBUTE(x) __attribute__ (x) #define LIKELY(_x) __builtin_expect(!!(_x), 1) #define UNLIKELY(_x) __builtin_expect(!!(_x), 0) #else #define ATTRIBUTE(x) /**/ #define LIKELY(_x) !!(_x) #define UNLIKELY(_x) !!(_x) #endif #if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) #define COLD __attribute__ ((cold)) #else #define COLD /**/ #endif #ifndef IF_NAMESIZE #include #include #endif #ifdef HAVE_VALGRIND #include #else #ifndef VALGRIND_MAKE_MEM_UNDEFINED #define VALGRIND_MAKE_MEM_UNDEFINED(a, b) do {} while(0) #endif #ifndef VALGRIND_CHECK_MEM_IS_DEFINED #define VALGRIND_CHECK_MEM_IS_DEFINED(a, b) do {} while(0) #endif #endif #define BABEL_VTY_PORT 2609 #define BABEL_DEFAULT_CONFIG "babeld.conf" #define BABEL_VERSION "0.1 for quagga" /* Values in milliseconds */ #define BABEL_DEFAULT_HELLO_INTERVAL 4000 #define BABEL_DEFAULT_UPDATE_INTERVAL 16000 #define BABEL_DEFAULT_RESEND_DELAY 2000 /* Babel socket. */ extern int protocol_socket; /* Babel structure. */ struct babel { /* Babel threads. */ struct thread *t_read; /* on Babel protocol's socket */ struct thread *t_update; /* timers */ }; extern void babeld_quagga_init(void); extern int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, const unsigned char *neigh, unsigned int ifindex); extern int output_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, unsigned int ifindex); extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto); extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); #endif /* BABEL_BABELD_H */ quagga-0.99.24.1/babeld/babel_interface.h0000644000175000017500000001254212476520570014707 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_INTERFACE_H #define BABEL_INTERFACE_H #include #include "zclient.h" #include "vty.h" #define CONFIG_DEFAULT 0 #define CONFIG_NO 1 #define CONFIG_YES 2 /* babeld interface informations */ struct babel_interface { unsigned short flags; /* see below */ unsigned short cost; int channel; struct timeval hello_timeout; struct timeval update_timeout; struct timeval flush_timeout; struct timeval update_flush_timeout; unsigned char *ipv4; int buffered; int bufsize; char have_buffered_hello; char have_buffered_id; char have_buffered_nh; char have_buffered_prefix; unsigned char buffered_id[16]; unsigned char buffered_nh[4]; unsigned char buffered_prefix[16]; unsigned char *sendbuf; struct buffered_update *buffered_updates; int num_buffered_updates; int update_bufsize; time_t bucket_time; unsigned int bucket; time_t last_update_time; unsigned short hello_seqno; unsigned hello_interval; unsigned update_interval; /* For filter type slot. */ #define BABEL_FILTER_IN 0 #define BABEL_FILTER_OUT 1 #define BABEL_FILTER_MAX 2 struct access_list *list[BABEL_FILTER_MAX]; /* Access-list. */ struct prefix_list *prefix[BABEL_FILTER_MAX]; /* Prefix-list. */ }; typedef struct babel_interface babel_interface_nfo; static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) { return ((babel_interface_nfo*) ifp->info); } /* babel_interface_nfo flags */ #define BABEL_IF_IS_UP (1 << 0) #define BABEL_IF_WIRED (1 << 1) #define BABEL_IF_SPLIT_HORIZON (1 << 2) #define BABEL_IF_LQ (1 << 3) #define BABEL_IF_FARAWAY (1 << 4) /* Only INTERFERING can appear on the wire. */ #define BABEL_IF_CHANNEL_UNKNOWN 0 #define BABEL_IF_CHANNEL_INTERFERING 255 #define BABEL_IF_CHANNEL_NONINTERFERING -2 static inline int if_up(struct interface *ifp) { return (if_is_operative(ifp) && ifp->connected != NULL && (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP)); } /* types: struct interface _ifp, struct listnode node */ #define FOR_ALL_INTERFACES(_ifp, _node) \ for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp)) /* types: struct interface *ifp, struct connected *_connected, struct listnode *node */ #define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node) \ for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected)) struct buffered_update { unsigned char id[8]; unsigned char prefix[16]; unsigned char plen; unsigned char pad[3]; }; /* init function */ void babel_if_init(void); /* Callback functions for zebra client */ int babel_interface_up (int, struct zclient *, zebra_size_t); int babel_interface_down (int, struct zclient *, zebra_size_t); int babel_interface_add (int, struct zclient *, zebra_size_t); int babel_interface_delete (int, struct zclient *, zebra_size_t); int babel_interface_address_add (int, struct zclient *, zebra_size_t); int babel_interface_address_delete (int, struct zclient *, zebra_size_t); unsigned jitter(babel_interface_nfo *, int); unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); /* return "true" if "address" is one of our ipv6 addresses */ int is_interface_ll_address(struct interface *ifp, const unsigned char *address); /* Send retraction to all, and reset all interfaces statistics. */ void babel_interface_close_all(void); extern int babel_enable_if_config_write (struct vty *); #endif quagga-0.99.24.1/babeld/resend.h0000644000175000017500000000626412476520570013106 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define REQUEST_TIMEOUT 65000 #define RESEND_MAX 3 #define RESEND_REQUEST 1 #define RESEND_UPDATE 2 struct resend { unsigned char kind; unsigned char max; unsigned short delay; struct timeval time; unsigned char prefix[16]; unsigned char plen; unsigned short seqno; unsigned char id[8]; struct interface *ifp; struct resend *next; }; extern struct timeval resend_time; struct resend *find_request(const unsigned char *prefix, unsigned char plen, struct resend **previous_return); void flush_resends(struct neighbour *neigh); int record_resend(int kind, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay); int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id); int satisfy_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, struct interface *ifp); void expire_resend(void); void recompute_resend_time(void); void do_resend(void); quagga-0.99.24.1/babeld/message.h0000644000175000017500000001106412476520570013244 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_MESSAGE_H #define BABEL_MESSAGE_H #include "babel_interface.h" #define MAX_BUFFERED_UPDATES 200 #define BUCKET_TOKENS_MAX 200 #define BUCKET_TOKENS_PER_SEC 40 #define MESSAGE_PAD1 0 #define MESSAGE_PADN 1 #define MESSAGE_ACK_REQ 2 #define MESSAGE_ACK 3 #define MESSAGE_HELLO 4 #define MESSAGE_IHU 5 #define MESSAGE_ROUTER_ID 6 #define MESSAGE_NH 7 #define MESSAGE_UPDATE 8 #define MESSAGE_REQUEST 9 #define MESSAGE_MH_REQUEST 10 extern unsigned short myseqno; extern struct timeval seqno_time; extern int broadcast_ihu; extern int split_horizon; extern unsigned char packet_header[4]; extern struct neighbour *unicast_neighbour; extern struct timeval unicast_flush_timeout; void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen); void flushbuf(struct interface *ifp); void flushupdates(struct interface *ifp); void send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval); void send_hello_noupdate(struct interface *ifp, unsigned interval); void send_hello(struct interface *ifp); void flush_unicast(int dofree); void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen); void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen); void send_wildcard_retraction(struct interface *ifp); void update_myseqno(void); void send_self_update(struct interface *ifp); void send_ihu(struct neighbour *neigh, struct interface *ifp); void send_marginal_ihu(struct interface *ifp); void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen); void send_unicast_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen); void send_multihop_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count); void send_unicast_multihop_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id, unsigned short hop_count); void send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id); void handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned char hop_count, unsigned short seqno, const unsigned char *id); #endif quagga-0.99.24.1/babeld/xroute.h0000644000175000017500000000544112476520570013150 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ struct xroute { unsigned char prefix[16]; unsigned char plen; unsigned short metric; unsigned int ifindex; int proto; }; struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); void flush_xroute(struct xroute *xroute); int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex, struct in_addr *nexthop); int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex); int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex, struct in6_addr *nexthop); int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex); int xroutes_estimate(void); void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure); quagga-0.99.24.1/babeld/route.h0000644000175000017500000001316412476520570012761 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_ROUTE_H #define BABEL_ROUTE_H #include "babel_interface.h" #include "source.h" #define DIVERSITY_NONE 0 #define DIVERSITY_INTERFACE_1 1 #define DIVERSITY_CHANNEL_1 2 #define DIVERSITY_CHANNEL 3 #define DIVERSITY_HOPS 8 struct babel_route { struct source *src; unsigned short refmetric; unsigned short cost; unsigned short add_metric; unsigned short seqno; struct neighbour *neigh; unsigned char nexthop[16]; time_t time; unsigned short hold_time; /* in seconds */ short installed; unsigned char channels[DIVERSITY_HOPS]; struct babel_route *next; }; extern struct babel_route **routes; extern int kernel_metric, allow_duplicates; extern int diversity_kind, diversity_factor; extern int keep_unfeasible; static inline int route_metric(const struct babel_route *route) { int m = (int)route->refmetric + route->cost + route->add_metric; return MIN(m, INFINITY); } static inline int route_metric_noninterfering(const struct babel_route *route) { int m = (int)route->refmetric + (diversity_factor * route->cost + 128) / 256 + route->add_metric; m = MAX(m, route->refmetric + 1); return MIN(m, INFINITY); } struct babel_route *find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop); struct babel_route *find_installed_route(const unsigned char *prefix, unsigned char plen); int installed_routes_estimate(void); void flush_route(struct babel_route *route); void flush_all_routes(void); void flush_neighbour_routes(struct neighbour *neigh); void flush_interface_routes(struct interface *ifp, int v4only); void for_all_routes(void (*f)(struct babel_route*, void*), void *closure); void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure); void install_route(struct babel_route *route); void uninstall_route(struct babel_route *route); void switch_route(struct babel_route *old, struct babel_route *new); int route_feasible(struct babel_route *route); int route_old(struct babel_route *route); int route_expired(struct babel_route *route); int route_interferes(struct babel_route *route, struct interface *ifp); int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric); struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude); struct babel_route *install_best_route(const unsigned char prefix[16], unsigned char plen); void update_neighbour_metric(struct neighbour *neigh, int change); void update_interface_metric(struct interface *ifp); void update_route_metric(struct babel_route *route); struct babel_route *update_route(const unsigned char *id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop, const unsigned char *channels, int channels_len); void retract_neighbour_routes(struct neighbour *neigh); void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src); void send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric); void route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric); void route_lost(struct source *src, unsigned oldmetric); void expire_routes(void); #endif quagga-0.99.24.1/babeld/neighbour.h0000644000175000017500000000551012476520570013601 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ struct neighbour { struct neighbour *next; /* This is -1 when unknown, so don't make it unsigned */ int hello_seqno; unsigned char address[16]; unsigned short reach; unsigned short txcost; struct timeval hello_time; struct timeval ihu_time; unsigned short hello_interval; /* in centiseconds */ unsigned short ihu_interval; /* in centiseconds */ struct interface *ifp; }; extern struct neighbour *neighs; #define FOR_ALL_NEIGHBOURS(_neigh) \ for(_neigh = neighs; _neigh; _neigh = _neigh->next) int neighbour_valid(struct neighbour *neigh); void flush_neighbour(struct neighbour *neigh); struct neighbour *find_neighbour(const unsigned char *address, struct interface *ifp); int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); unsigned check_neighbours(void); unsigned neighbour_txcost(struct neighbour *neigh); unsigned neighbour_rxcost(struct neighbour *neigh); unsigned neighbour_cost(struct neighbour *neigh); quagga-0.99.24.1/babeld/source.h0000644000175000017500000000517012476520570013121 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_SOURCE_H #define BABEL_SOURCE_H #define SOURCE_GC_TIME 200 struct source { struct source *next; unsigned char id[8]; unsigned char prefix[16]; unsigned char plen; unsigned short seqno; unsigned short metric; unsigned short route_count; time_t time; }; struct source *find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno); struct source *retain_source(struct source *src); void release_source(struct source *src); int flush_source(struct source *src); void update_source(struct source *src, unsigned short seqno, unsigned short metric); void expire_sources(void); void check_sources_released(void); #endif quagga-0.99.24.1/babeld/util.h0000644000175000017500000001462512476520570012603 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "babeld.h" #include "babel_main.h" #include "log.h" #if defined(i386) || defined(__mc68020__) || defined(__x86_64__) #define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) #define DO_NTOHL(_d, _s) do{ _d = ntohl(*(const unsigned*)(_s)); } while(0) #define DO_HTONS(_d, _s) do{ *(unsigned short*)(_d) = htons(_s); } while(0) #define DO_HTONL(_d, _s) do{ *(unsigned*)(_d) = htonl(_s); } while(0) /* Some versions of gcc seem to be buggy, and ignore the packed attribute. Disable this code until the issue is clarified. */ /* #elif defined __GNUC__*/ #elif 0 struct __us { unsigned short x __attribute__((packed)); }; #define DO_NTOHS(_d, _s) \ do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) #define DO_HTONS(_d, _s) \ do { ((struct __us*)(_d))->x = htons(_s); } while(0) #else #define DO_NTOHS(_d, _s) \ do { short _dd; \ memcpy(&(_dd), (_s), 2); \ _d = ntohs(_dd); } while(0) #define DO_HTONS(_d, _s) \ do { unsigned short _dd; \ _dd = htons(_s); \ memcpy((_d), &(_dd), 2); } while(0) #endif static inline int seqno_compare(unsigned short s1, unsigned short s2) { if(s1 == s2) return 0; else return ((s2 - s1) & 0x8000) ? 1 : -1; } static inline short seqno_minus(unsigned short s1, unsigned short s2) { return (short)((s1 - s2) & 0xFFFF); } static inline unsigned short seqno_plus(unsigned short s, int plus) { return ((s + plus) & 0xFFFF); } unsigned roughly(unsigned value); void timeval_minus(struct timeval *d, const struct timeval *s1, const struct timeval *s2); unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) ATTRIBUTE ((pure)); void timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs); void set_timeout (struct timeval *timeout, int msecs); int timeval_compare(const struct timeval *s1, const struct timeval *s2) ATTRIBUTE ((pure)); void timeval_min(struct timeval *d, const struct timeval *s); void timeval_min_sec(struct timeval *d, time_t secs); int parse_msec(const char *string) ATTRIBUTE ((pure)); int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) ATTRIBUTE ((pure)); unsigned char *mask_prefix(unsigned char *restrict ret, const unsigned char *restrict prefix, unsigned char plen); const char *format_address(const unsigned char *address); const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_eui64(const unsigned char *eui); const char *format_bool(const int b); int parse_address(const char *address, unsigned char *addr_r, int *af_r); int parse_eui64(const char *eui, unsigned char *eui_r); int wait_for_fd(int direction, int fd, int msecs); int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure)); int linklocal(const unsigned char *address) ATTRIBUTE ((pure)); int v4mapped(const unsigned char *address) ATTRIBUTE ((pure)); void v4tov6(unsigned char *dst, const unsigned char *src); void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src); void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src); void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src); void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src); int daemonise(void); /* If debugging is disabled, we want to avoid calling format_address for every omitted debugging message. So debug is a macro. But vararg macros are not portable. */ #if defined NO_DEBUG #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(...) do {} while(0) #elif defined __GNUC__ #define debugf(_args...) do {} while(0) #else static inline void debugf(int level, const char *format, ...) { return; } #endif #else /* NO_DEBUG */ /* some levels */ #define BABEL_DEBUG_COMMON (1 << 0) #define BABEL_DEBUG_KERNEL (1 << 1) #define BABEL_DEBUG_FILTER (1 << 2) #define BABEL_DEBUG_TIMEOUT (1 << 3) #define BABEL_DEBUG_IF (1 << 4) #define BABEL_DEBUG_ROUTE (1 << 5) #define BABEL_DEBUG_ALL (0xFFFF) #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(level, ...) \ do { \ if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \ } while(0) #elif defined __GNUC__ #define debugf(level, _args...) \ do { \ if(UNLIKELY(debug & level)) zlog_debug(_args); \ } while(0) #else static inline void debugf(int level, const char *format, ...) { return; } #endif #endif /* NO_DEBUG */ quagga-0.99.24.1/babeld/kernel.h0000644000175000017500000000536112476520570013103 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "babel_main.h" #include "if.h" #define KERNEL_INFINITY 0xFFFF struct kernel_route { unsigned char prefix[16]; int plen; int metric; unsigned int ifindex; int proto; unsigned char gw[16]; }; #define ROUTE_FLUSH 0 #define ROUTE_ADD 1 #define ROUTE_MODIFY 2 extern int export_table, import_table; int kernel_interface_operational(struct interface *interface); int kernel_interface_mtu(struct interface *interface); int kernel_interface_wireless(struct interface *interface); int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric); int if_eui64(char *ifname, int ifindex, unsigned char *eui); int gettime(struct timeval *tv); int read_random_bytes(void *buf, size_t len); quagga-0.99.24.1/babeld/net.h0000644000175000017500000000414512476520570012410 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright (c) 2007, 2008 by Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ int babel_socket(int port); int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen); int babel_send(int s, void *buf1, int buflen1, void *buf2, int buflen2, struct sockaddr *sin, int slen); int tcp_server_socket(int port, int local); quagga-0.99.24.1/babeld/babel_zebra.h0000644000175000017500000000406512476520570014053 00000000000000/* * This file is free software: you may copy, redistribute and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 2 of the License, or (at your * option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * This file incorporates work covered by the following copyright and * permission notice: * Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef BABEL_ZEBRA_H #define BABEL_ZEBRA_H #include "vty.h" extern struct zclient *zclient; void babelz_zebra_init(void); void babel_zebra_close_connexion(void); extern int debug_babel_config_write (struct vty *); #endif quagga-0.99.24.1/babeld/babeld.conf.sample0000644000175000017500000000121712476520570015006 00000000000000debug babel common !debug babel kernel !debug babel filter !debug babel timeout !debug babel interface !debug babel route !debug babel all router babel ! network wlan0 ! network eth0 ! redistribute kernel ! no redistribute static ! The defaults are fine for a wireless interface !interface wlan0 ! A few optimisation tweaks are optional but recommended on a wired interface ! Disable link quality estimation, enable split horizon processing, and ! increase the hello and update intervals. !interface eth0 ! babel wired ! babel split-horizon ! babel hello-interval 12000 ! babel update-interval 36000 ! log file /var/log/quagga/babeld.log log stdout quagga-0.99.24.1/babeld/Makefile.am0000644000175000017500000000147512476520570013510 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbabel.a sbin_PROGRAMS = babeld libbabel_a_SOURCES = \ babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ route.c xroute.c message.c resend.c babel_interface.c babeld.c \ babel_filter.c noinst_HEADERS = \ babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ route.h xroute.h message.h resend.h babel_interface.h babeld.h \ babel_filter.h babel_main.h babeld_SOURCES = \ babel_main.c $(libbabel_a_SOURCES) babeld_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = babeld.conf.sample quagga-0.99.24.1/babeld/Makefile.in0000644000175000017500000006202412476521250013512 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = babeld$(EXEEXT) subdir = babeld DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libbabel_a_AR = $(AR) $(ARFLAGS) libbabel_a_LIBADD = am_libbabel_a_OBJECTS = babel_zebra.$(OBJEXT) net.$(OBJEXT) \ kernel.$(OBJEXT) util.$(OBJEXT) source.$(OBJEXT) \ neighbour.$(OBJEXT) route.$(OBJEXT) xroute.$(OBJEXT) \ message.$(OBJEXT) resend.$(OBJEXT) babel_interface.$(OBJEXT) \ babeld.$(OBJEXT) babel_filter.$(OBJEXT) libbabel_a_OBJECTS = $(am_libbabel_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = babel_zebra.$(OBJEXT) net.$(OBJEXT) kernel.$(OBJEXT) \ util.$(OBJEXT) source.$(OBJEXT) neighbour.$(OBJEXT) \ route.$(OBJEXT) xroute.$(OBJEXT) message.$(OBJEXT) \ resend.$(OBJEXT) babel_interface.$(OBJEXT) babeld.$(OBJEXT) \ babel_filter.$(OBJEXT) am_babeld_OBJECTS = babel_main.$(OBJEXT) $(am__objects_1) babeld_OBJECTS = $(am_babeld_OBJECTS) babeld_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libbabel_a_SOURCES) $(babeld_SOURCES) DIST_SOURCES = $(libbabel_a_SOURCES) $(babeld_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbabel.a libbabel_a_SOURCES = \ babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ route.c xroute.c message.c resend.c babel_interface.c babeld.c \ babel_filter.c noinst_HEADERS = \ babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ route.h xroute.h message.h resend.h babel_interface.h babeld.h \ babel_filter.h babel_main.h babeld_SOURCES = \ babel_main.c $(libbabel_a_SOURCES) babeld_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = babeld.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu babeld/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu babeld/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libbabel.a: $(libbabel_a_OBJECTS) $(libbabel_a_DEPENDENCIES) $(EXTRA_libbabel_a_DEPENDENCIES) $(AM_V_at)-rm -f libbabel.a $(AM_V_AR)$(libbabel_a_AR) libbabel.a $(libbabel_a_OBJECTS) $(libbabel_a_LIBADD) $(AM_V_at)$(RANLIB) libbabel.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list babeld$(EXEEXT): $(babeld_OBJECTS) $(babeld_DEPENDENCIES) $(EXTRA_babeld_DEPENDENCIES) @rm -f babeld$(EXEEXT) $(AM_V_CCLD)$(LINK) $(babeld_OBJECTS) $(babeld_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babel_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/babeld.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/neighbour.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/source.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xroute.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/ospf6d/0000755000175000017500000000000012476521356011520 500000000000000quagga-0.99.24.1/ospf6d/ospf6_main.c0000644000175000017500000002006012476520570013640 00000000000000/* * Copyright (C) 1999 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include "getopt.h" #include "thread.h" #include "log.h" #include "command.h" #include "vty.h" #include "memory.h" #include "if.h" #include "filter.h" #include "prefix.h" #include "plist.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "ospf6d.h" #include "ospf6_top.h" #include "ospf6_message.h" #include "ospf6_asbr.h" #include "ospf6_lsa.h" #include "ospf6_interface.h" #include "ospf6_zebra.h" /* Default configuration file name for ospf6d. */ #define OSPF6_DEFAULT_CONFIG "ospf6d.conf" /* Default port values. */ #define OSPF6_VTY_PORT 2606 /* ospf6d privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ospf6d_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* ospf6d options, we use GNU getopt library. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR OSPF6_DEFAULT_CONFIG; /* ospf6d program name. */ char *progname; /* is daemon? */ int daemon_mode = 0; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_OSPF6D_PID; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\n\ Daemon which manages OSPF version 3.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } static void __attribute__ ((noreturn)) ospf6_exit (int status) { struct listnode *node; struct interface *ifp; if (ospf6) ospf6_delete (ospf6); for (ALL_LIST_ELEMENTS_RO(iflist, node, ifp)) if (ifp->info != NULL) ospf6_interface_delete(ifp->info); ospf6_message_terminate (); ospf6_asbr_terminate (); ospf6_lsa_terminate (); if_terminate (); vty_terminate (); cmd_terminate (); if (zclient) zclient_free (zclient); if (master) thread_master_free (master); if (zlog_default) closezlog (zlog_default); exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal SIGINT"); ospf6_exit (0); } /* SIGTERM handler. */ static void sigterm (void) { zlog_notice ("Terminating on signal SIGTERM"); ospf6_clean(); ospf6_exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_info ("SIGUSR1 received"); zlog_rotate (NULL); } struct quagga_signal_t ospf6_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigterm, }, { .signal = SIGUSR1, .handler = &sigusr1, }, }; /* Main routine of ospf6d. Treatment of argument and starting ospf finite state machine is handled here. */ int main (int argc, char *argv[], char *envp[]) { char *p; int opt; char *vty_addr = NULL; int vty_port = 0; char *config_file = NULL; struct thread thread; int dryrun = 0; /* Set umask before anything for security */ umask (0027); /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* Command line argument treatment. */ while (1) { opt = getopt_long (argc, argv, "df:i:z:hp:A:P:u:g:vC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ospf6d not listening on ospf6d port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF6_VTY_PORT; break; case 'u': ospf6d_privs.user = optarg; break; case 'g': ospf6d_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } if (geteuid () != 0) { errno = EPERM; perror (progname); exit (1); } /* thread master */ master = thread_master_create (); /* Initializations. */ zlog_default = openzlog (progname, ZLOG_OSPF6, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospf6d_privs); /* initialize zebra libraries */ signal_init (master, array_size(ospf6_signals), ospf6_signals); cmd_init (1); vty_init (master); memory_init (); if_init (); access_list_init (); prefix_list_init (); /* initialize ospf6 */ ospf6_init (); /* parse config file */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); if (daemon_mode && daemon (0, 0) < 0) { zlog_err("OSPF6d daemon failed: %s", strerror(errno)); exit (1); } /* pid file create */ pid_output (pid_file); /* Make ospf6 vty socket. */ if (!vty_port) vty_port = OSPF6_VTY_PORT; vty_serv_sock (vty_addr, vty_port, OSPF6_VTYSH_PATH); /* Print start message */ zlog_notice ("OSPF6d (Quagga-%s ospf6d-%s) starts: vty@%d", QUAGGA_VERSION, OSPF6_DAEMON_VERSION,vty_port); /* Start finite state machine, here we go! */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Log in case thread failed */ zlog_warn ("Thread failed"); /* Not reached. */ ospf6_exit (0); } quagga-0.99.24.1/ospf6d/ospf6d.c0000644000175000017500000015662412476520570013020 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "vty.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_network.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_spf.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6_flood.h" #include "ospf6d.h" #ifdef HAVE_SNMP #include "ospf6_snmp.h" #endif /*HAVE_SNMP*/ char ospf6_daemon_version[] = OSPF6_DAEMON_VERSION; struct route_node * route_prev (struct route_node *node) { struct route_node *end; struct route_node *prev = NULL; end = node; node = node->parent; if (node) route_lock_node (node); while (node) { prev = node; node = route_next (node); if (node == end) { route_unlock_node (node); node = NULL; } } route_unlock_node (end); if (prev) route_lock_node (prev); return prev; } /* show database functions */ DEFUN (show_version_ospf6, show_version_ospf6_cmd, "show version ospf6", SHOW_STR "Displays ospf6d version\n" ) { vty_out (vty, "Zebra OSPF6d Version: %s%s", ospf6_daemon_version, VNL); return CMD_SUCCESS; } static struct cmd_node debug_node = { DEBUG_NODE, "", 1 /* VTYSH */ }; static int config_write_ospf6_debug (struct vty *vty) { config_write_ospf6_debug_message (vty); config_write_ospf6_debug_lsa (vty); config_write_ospf6_debug_zebra (vty); config_write_ospf6_debug_interface (vty); config_write_ospf6_debug_neighbor (vty); config_write_ospf6_debug_spf (vty); config_write_ospf6_debug_route (vty); config_write_ospf6_debug_brouter (vty); config_write_ospf6_debug_asbr (vty); config_write_ospf6_debug_abr (vty); config_write_ospf6_debug_flood (vty); vty_out (vty, "!%s", VNL); return 0; } #define AREA_LSDB_TITLE_FORMAT \ "%s Area Scoped Link State Database (Area %s)%s%s" #define IF_LSDB_TITLE_FORMAT \ "%s I/F Scoped Link State Database (I/F %s in Area %s)%s%s" #define AS_LSDB_TITLE_FORMAT \ "%s AS Scoped Link State Database%s%s" static int parse_show_level (int argc, const char *argv[]) { int level = 0; if (argc) { if (! strncmp (argv[0], "de", 2)) level = OSPF6_LSDB_SHOW_LEVEL_DETAIL; else if (! strncmp (argv[0], "du", 2)) level = OSPF6_LSDB_SHOW_LEVEL_DUMP; else if (! strncmp (argv[0], "in", 2)) level = OSPF6_LSDB_SHOW_LEVEL_INTERNAL; } else level = OSPF6_LSDB_SHOW_LEVEL_NORMAL; return level; } static u_int16_t parse_type_spec (int argc, const char *argv[]) { u_int16_t type = 0; assert (argc); if (! strcmp (argv[0], "router")) type = htons (OSPF6_LSTYPE_ROUTER); else if (! strcmp (argv[0], "network")) type = htons (OSPF6_LSTYPE_NETWORK); else if (! strcmp (argv[0], "as-external")) type = htons (OSPF6_LSTYPE_AS_EXTERNAL); else if (! strcmp (argv[0], "intra-prefix")) type = htons (OSPF6_LSTYPE_INTRA_PREFIX); else if (! strcmp (argv[0], "inter-router")) type = htons (OSPF6_LSTYPE_INTER_ROUTER); else if (! strcmp (argv[0], "inter-prefix")) type = htons (OSPF6_LSTYPE_INTER_PREFIX); else if (! strcmp (argv[0], "link")) type = htons (OSPF6_LSTYPE_LINK); return type; } DEFUN (show_ipv6_ospf6_database, show_ipv6_ospf6_database_cmd, "show ipv6 ospf6 database", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; OSPF6_CMD_CHECK_RUNNING (); level = parse_show_level (argc, argv); for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, NULL, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, NULL, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, NULL, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database, show_ipv6_ospf6_database_detail_cmd, "show ipv6 ospf6 database (detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; level = parse_show_level (argc, argv); switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, NULL, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, NULL, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, NULL, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_id_cmd, "show ipv6 ospf6 database * A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int32_t id = 0; OSPF6_CMD_CHECK_RUNNING (); if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link State ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, NULL, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, NULL, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, NULL, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_id_detail_cmd, "show ipv6 ospf6 database * A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) ALIAS (show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_linkstate_id_cmd, "show ipv6 ospf6 database linkstate-id A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) ALIAS (show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_linkstate_id_detail_cmd, "show ipv6 ospf6 database linkstate-id A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_router_cmd, "show ipv6 ospf6 database * * A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_router_detail_cmd, "show ipv6 ospf6 database * * A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) ALIAS (show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_adv_router_cmd, "show ipv6 ospf6 database adv-router A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" ) ALIAS (show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_adv_router_detail_cmd, "show ipv6 ospf6 database adv-router A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t id = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link state ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, NULL, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, NULL, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, NULL, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) ALIAS (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_linkstate_id_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) ALIAS (show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_linkstate_id_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) linkstate-id A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_router, show_ipv6_ospf6_database_type_router_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) * A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_router, show_ipv6_ospf6_database_type_router_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) * A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Any Link state ID\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) ALIAS (show_ipv6_ospf6_database_type_router, show_ipv6_ospf6_database_type_adv_router_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" ) ALIAS (show_ipv6_ospf6_database_type_router, show_ipv6_ospf6_database_type_adv_router_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) adv-router A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_id_router, show_ipv6_ospf6_database_id_router_cmd, "show ipv6 ospf6 database * A.B.C.D A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int32_t id = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link state ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_id_router, show_ipv6_ospf6_database_id_router_detail_cmd, "show ipv6 ospf6 database * A.B.C.D A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Any Link state Type\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_adv_router_linkstate_id, show_ipv6_ospf6_database_adv_router_linkstate_id_cmd, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int32_t id = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link state ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, &id, &adv_router, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_adv_router_linkstate_id, show_ipv6_ospf6_database_adv_router_linkstate_id_detail_cmd, "show ipv6 ospf6 database adv-router A.B.C.D linkstate-id A.B.C.D " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_id_router, show_ipv6_ospf6_database_type_id_router_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t id = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link state ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_id_router, show_ipv6_ospf6_database_type_id_router_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D A.B.C.D " "(dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Specify Advertising Router as IPv4 address notation\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id, show_ipv6_ospf6_database_type_adv_router_linkstate_id_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "adv-router A.B.C.D linkstate-id A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t id = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Advertising Router is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link state ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_adv_router_linkstate_id, show_ipv6_ospf6_database_type_adv_router_linkstate_id_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) " "adv-router A.B.C.D linkstate-id A.B.C.D " "(dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Search by Advertising Router\n" "Specify Advertising Router as IPv4 address notation\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_self_originated, show_ipv6_ospf6_database_self_originated_cmd, "show ipv6 ospf6 database self-originated", SHOW_STR IPV6_STR OSPF6_STR "Display Self-originated LSAs\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); level = parse_show_level (argc, argv); adv_router = o->router_id; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oa->lsdb); } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, oi->lsdb); } } vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, NULL, NULL, &adv_router, o->lsdb); vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_self_originated, show_ipv6_ospf6_database_self_originated_detail_cmd, "show ipv6 ospf6 database self-originated " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Self-originated LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_self_originated, show_ipv6_ospf6_database_type_self_originated_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t adv_router = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; level = parse_show_level (argc, argv); adv_router = o->router_id; switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, NULL, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_self_originated, show_ipv6_ospf6_database_type_self_originated_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_self_originated_linkstate_id, show_ipv6_ospf6_database_type_self_originated_linkstate_id_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "linkstate-id A.B.C.D", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t adv_router = 0; u_int32_t id = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link State ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); adv_router = o->router_id; switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_self_originated_linkstate_id, show_ipv6_ospf6_database_type_self_originated_linkstate_id_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) self-originated " "linkstate-id A.B.C.D (detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_database_type_id_self_originated, show_ipv6_ospf6_database_type_id_self_originated_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Specify Link state ID as IPv4 address notation\n" "Display Self-originated LSAs\n" ) { int level; struct listnode *i, *j; struct ospf6 *o = ospf6; struct ospf6_area *oa; struct ospf6_interface *oi; u_int16_t type = 0; u_int32_t adv_router = 0; u_int32_t id = 0; OSPF6_CMD_CHECK_RUNNING (); type = parse_type_spec (argc, argv); argc--; argv++; if ((inet_pton (AF_INET, argv[0], &id)) != 1) { vty_out (vty, "Link State ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; level = parse_show_level (argc, argv); adv_router = o->router_id; switch (OSPF6_LSA_SCOPE (type)) { case OSPF6_SCOPE_AREA: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { vty_out (vty, AREA_LSDB_TITLE_FORMAT, VNL, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oa->lsdb); } break; case OSPF6_SCOPE_LINKLOCAL: for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { vty_out (vty, IF_LSDB_TITLE_FORMAT, VNL, oi->interface->name, oa->name, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, oi->lsdb); } } break; case OSPF6_SCOPE_AS: vty_out (vty, AS_LSDB_TITLE_FORMAT, VNL, VNL, VNL); ospf6_lsdb_show (vty, level, &type, &id, &adv_router, o->lsdb); break; default: assert (0); break; } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_database_type_id_self_originated, show_ipv6_ospf6_database_type_id_self_originated_detail_cmd, "show ipv6 ospf6 database " "(router|network|inter-prefix|inter-router|as-external|" "group-membership|type-7|link|intra-prefix) A.B.C.D self-originated " "(detail|dump|internal)", SHOW_STR IPV6_STR OSPF6_STR "Display Link state database\n" "Display Router LSAs\n" "Display Network LSAs\n" "Display Inter-Area-Prefix LSAs\n" "Display Inter-Area-Router LSAs\n" "Display As-External LSAs\n" "Display Group-Membership LSAs\n" "Display Type-7 LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display Self-originated LSAs\n" "Search by Link state ID\n" "Specify Link state ID as IPv4 address notation\n" "Display details of LSAs\n" "Dump LSAs\n" "Display LSA's internal information\n" ) DEFUN (show_ipv6_ospf6_border_routers, show_ipv6_ospf6_border_routers_cmd, "show ipv6 ospf6 border-routers", SHOW_STR IP6_STR OSPF6_STR "Display routing table for ABR and ASBR\n" ) { u_int32_t adv_router; void (*showfunc) (struct vty *, struct ospf6_route *); struct ospf6_route *ro; struct prefix prefix; OSPF6_CMD_CHECK_RUNNING (); if (argc && ! strcmp ("detail", argv[0])) { showfunc = ospf6_route_show_detail; argc--; argv++; } else showfunc = ospf6_brouter_show; if (argc) { if ((inet_pton (AF_INET, argv[0], &adv_router)) != 1) { vty_out (vty, "Router ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } ospf6_linkstate_prefix (adv_router, 0, &prefix); ro = ospf6_route_lookup (&prefix, ospf6->brouter_table); if (!ro) { vty_out (vty, "No Route found for Router ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } ospf6_route_show_detail (vty, ro); return CMD_SUCCESS; } if (showfunc == ospf6_brouter_show) ospf6_brouter_show_header (vty); for (ro = ospf6_route_head (ospf6->brouter_table); ro; ro = ospf6_route_next (ro)) (*showfunc) (vty, ro); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_border_routers, show_ipv6_ospf6_border_routers_detail_cmd, "show ipv6 ospf6 border-routers (A.B.C.D|detail)", SHOW_STR IP6_STR OSPF6_STR "Display routing table for ABR and ASBR\n" "Specify Router-ID\n" "Display Detail\n" ) DEFUN (show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_cmd, "show ipv6 ospf6 linkstate", SHOW_STR IP6_STR OSPF6_STR "Display linkstate routing table\n" ) { struct listnode *node; struct ospf6_area *oa; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { vty_out (vty, "%s SPF Result in Area %s%s%s", VNL, oa->name, VNL, VNL); ospf6_linkstate_table_show (vty, argc, argv, oa->spf_table); } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_router_cmd, "show ipv6 ospf6 linkstate router A.B.C.D", SHOW_STR IP6_STR OSPF6_STR "Display linkstate routing table\n" "Display Router Entry\n" "Specify Router ID as IPv4 address notation\n" ) ALIAS (show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_network_cmd, "show ipv6 ospf6 linkstate network A.B.C.D A.B.C.D", SHOW_STR IP6_STR OSPF6_STR "Display linkstate routing table\n" "Display Network Entry\n" "Specify Router ID as IPv4 address notation\n" "Specify Link state ID as IPv4 address notation\n" ) DEFUN (show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd, "show ipv6 ospf6 linkstate detail", SHOW_STR IP6_STR OSPF6_STR "Display linkstate routing table\n" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; struct listnode *node; struct ospf6_area *oa; /* copy argv to sargv and then append "detail" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; sargc = argc; sargv[sargc++] = "detail"; sargv[sargc] = NULL; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { vty_out (vty, "%s SPF Result in Area %s%s%s", VNL, oa->name, VNL, VNL); ospf6_linkstate_table_show (vty, sargc, sargv, oa->spf_table); } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } /* Install ospf related commands. */ void ospf6_init (void) { ospf6_top_init (); ospf6_area_init (); ospf6_interface_init (); ospf6_neighbor_init (); ospf6_zebra_init (); ospf6_lsa_init (); ospf6_spf_init (); ospf6_intra_init (); ospf6_asbr_init (); ospf6_abr_init (); #ifdef HAVE_SNMP ospf6_snmp_init (master); #endif /*HAVE_SNMP*/ install_node (&debug_node, config_write_ospf6_debug); install_element_ospf6_debug_message (); install_element_ospf6_debug_lsa (); install_element_ospf6_debug_interface (); install_element_ospf6_debug_neighbor (); install_element_ospf6_debug_zebra (); install_element_ospf6_debug_spf (); install_element_ospf6_debug_route (); install_element_ospf6_debug_brouter (); install_element_ospf6_debug_asbr (); install_element_ospf6_debug_abr (); install_element_ospf6_debug_flood (); install_element (VIEW_NODE, &show_version_ospf6_cmd); install_element (ENABLE_NODE, &show_version_ospf6_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_border_routers_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_router_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_network_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_router_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_network_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_linkstate_detail_cmd); #define INSTALL(n,c) \ install_element (n ## _NODE, &show_ipv6_ospf6_ ## c) INSTALL (VIEW, database_cmd); INSTALL (VIEW, database_detail_cmd); INSTALL (VIEW, database_type_cmd); INSTALL (VIEW, database_type_detail_cmd); INSTALL (VIEW, database_id_cmd); INSTALL (VIEW, database_id_detail_cmd); INSTALL (VIEW, database_linkstate_id_cmd); INSTALL (VIEW, database_linkstate_id_detail_cmd); INSTALL (VIEW, database_router_cmd); INSTALL (VIEW, database_router_detail_cmd); INSTALL (VIEW, database_adv_router_cmd); INSTALL (VIEW, database_adv_router_detail_cmd); INSTALL (VIEW, database_type_id_cmd); INSTALL (VIEW, database_type_id_detail_cmd); INSTALL (VIEW, database_type_linkstate_id_cmd); INSTALL (VIEW, database_type_linkstate_id_detail_cmd); INSTALL (VIEW, database_type_router_cmd); INSTALL (VIEW, database_type_router_detail_cmd); INSTALL (VIEW, database_type_adv_router_cmd); INSTALL (VIEW, database_type_adv_router_detail_cmd); INSTALL (VIEW, database_adv_router_linkstate_id_cmd); INSTALL (VIEW, database_adv_router_linkstate_id_detail_cmd); INSTALL (VIEW, database_id_router_cmd); INSTALL (VIEW, database_id_router_detail_cmd); INSTALL (VIEW, database_type_id_router_cmd); INSTALL (VIEW, database_type_id_router_detail_cmd); INSTALL (VIEW, database_type_adv_router_linkstate_id_cmd); INSTALL (VIEW, database_type_adv_router_linkstate_id_detail_cmd); INSTALL (VIEW, database_self_originated_cmd); INSTALL (VIEW, database_self_originated_detail_cmd); INSTALL (VIEW, database_type_self_originated_cmd); INSTALL (VIEW, database_type_self_originated_detail_cmd); INSTALL (VIEW, database_type_id_self_originated_cmd); INSTALL (VIEW, database_type_id_self_originated_detail_cmd); INSTALL (VIEW, database_type_self_originated_linkstate_id_cmd); INSTALL (VIEW, database_type_self_originated_linkstate_id_detail_cmd); INSTALL (ENABLE, database_cmd); INSTALL (ENABLE, database_detail_cmd); INSTALL (ENABLE, database_type_cmd); INSTALL (ENABLE, database_type_detail_cmd); INSTALL (ENABLE, database_id_cmd); INSTALL (ENABLE, database_id_detail_cmd); INSTALL (ENABLE, database_linkstate_id_cmd); INSTALL (ENABLE, database_linkstate_id_detail_cmd); INSTALL (ENABLE, database_router_cmd); INSTALL (ENABLE, database_router_detail_cmd); INSTALL (ENABLE, database_adv_router_cmd); INSTALL (ENABLE, database_adv_router_detail_cmd); INSTALL (ENABLE, database_type_id_cmd); INSTALL (ENABLE, database_type_id_detail_cmd); INSTALL (ENABLE, database_type_linkstate_id_cmd); INSTALL (ENABLE, database_type_linkstate_id_detail_cmd); INSTALL (ENABLE, database_type_router_cmd); INSTALL (ENABLE, database_type_router_detail_cmd); INSTALL (ENABLE, database_type_adv_router_cmd); INSTALL (ENABLE, database_type_adv_router_detail_cmd); INSTALL (ENABLE, database_adv_router_linkstate_id_cmd); INSTALL (ENABLE, database_adv_router_linkstate_id_detail_cmd); INSTALL (ENABLE, database_id_router_cmd); INSTALL (ENABLE, database_id_router_detail_cmd); INSTALL (ENABLE, database_type_id_router_cmd); INSTALL (ENABLE, database_type_id_router_detail_cmd); INSTALL (ENABLE, database_type_adv_router_linkstate_id_cmd); INSTALL (ENABLE, database_type_adv_router_linkstate_id_detail_cmd); INSTALL (ENABLE, database_self_originated_cmd); INSTALL (ENABLE, database_self_originated_detail_cmd); INSTALL (ENABLE, database_type_self_originated_cmd); INSTALL (ENABLE, database_type_self_originated_detail_cmd); INSTALL (ENABLE, database_type_id_self_originated_cmd); INSTALL (ENABLE, database_type_id_self_originated_detail_cmd); INSTALL (ENABLE, database_type_self_originated_linkstate_id_cmd); INSTALL (ENABLE, database_type_self_originated_linkstate_id_detail_cmd); /* Make ospf protocol socket. */ ospf6_serv_sock (); thread_add_read (master, ospf6_receive, NULL, ospf6_sock); } void ospf6_clean (void) { if (ospf6->route_table) ospf6_route_remove_all (ospf6->route_table); if (ospf6->brouter_table) ospf6_route_remove_all (ospf6->brouter_table); } quagga-0.99.24.1/ospf6d/ospf6_snmp.c0000644000175000017500000011233312476520570013676 00000000000000/* OSPFv3 SNMP support * Copyright (C) 2004 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "log.h" #include "vty.h" #include "linklist.h" #include "smux.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_message.h" #include "ospf6_neighbor.h" #include "ospf6d.h" #include "ospf6_snmp.h" /* OSPFv3-MIB */ #define OSPFv3MIB 1,3,6,1,2,1,191 /* OSPFv3 MIB General Group values. */ #define OSPFv3ROUTERID 1 #define OSPFv3ADMINSTAT 2 #define OSPFv3VERSIONNUMBER 3 #define OSPFv3AREABDRRTRSTATUS 4 #define OSPFv3ASBDRRTRSTATUS 5 #define OSPFv3ASSCOPELSACOUNT 6 #define OSPFv3ASSCOPELSACHECKSUMSUM 7 #define OSPFv3ORIGINATENEWLSAS 8 #define OSPFv3RXNEWLSAS 9 #define OSPFv3EXTLSACOUNT 10 #define OSPFv3EXTAREALSDBLIMIT 11 #define OSPFv3EXITOVERFLOWINTERVAL 12 #define OSPFv3DEMANDEXTENSIONS 13 #define OSPFv3REFERENCEBANDWIDTH 14 #define OSPFv3RESTARTSUPPORT 15 #define OSPFv3RESTARTINTERVAL 16 #define OSPFv3RESTARTSTRICTLSACHECKING 17 #define OSPFv3RESTARTSTATUS 18 #define OSPFv3RESTARTAGE 19 #define OSPFv3RESTARTEXITREASON 20 #define OSPFv3NOTIFICATIONENABLE 21 #define OSPFv3STUBROUTERSUPPORT 22 #define OSPFv3STUBROUTERADVERTISEMENT 23 #define OSPFv3DISCONTINUITYTIME 24 #define OSPFv3RESTARTTIME 25 /* OSPFv3 MIB Area Table values: ospfv3AreaTable */ #define OSPFv3IMPORTASEXTERN 2 #define OSPFv3AREASPFRUNS 3 #define OSPFv3AREABDRRTRCOUNT 4 #define OSPFv3AREAASBDRRTRCOUNT 5 #define OSPFv3AREASCOPELSACOUNT 6 #define OSPFv3AREASCOPELSACKSUMSUM 7 #define OSPFv3AREASUMMARY 8 #define OSPFv3AREAROWSTATUS 9 #define OSPFv3AREASTUBMETRIC 10 #define OSPFv3AREANSSATRANSLATORROLE 11 #define OSPFv3AREANSSATRANSLATORSTATE 12 #define OSPFv3AREANSSATRANSLATORSTABINTERVAL 13 #define OSPFv3AREANSSATRANSLATOREVENTS 14 #define OSPFv3AREASTUBMETRICTYPE 15 #define OSPFv3AREATEENABLED 16 /* OSPFv3 MIB * Lsdb Table values: ospfv3*LsdbTable */ #define OSPFv3WWLSDBSEQUENCE 1 #define OSPFv3WWLSDBAGE 2 #define OSPFv3WWLSDBCHECKSUM 3 #define OSPFv3WWLSDBADVERTISEMENT 4 #define OSPFv3WWLSDBTYPEKNOWN 5 /* Three first bits are to identify column */ #define OSPFv3WWCOLUMN 0x7 /* Then we use other bits to identify table */ #define OSPFv3WWASTABLE (1 << 3) #define OSPFv3WWAREATABLE (1 << 4) #define OSPFv3WWLINKTABLE (1 << 5) #define OSPFv3WWVIRTLINKTABLE (1 << 6) /* OSPFv3 MIB Host Table values: ospfv3HostTable */ #define OSPFv3HOSTMETRIC 3 #define OSPFv3HOSTROWSTATUS 4 #define OSPFv3HOSTAREAID 5 /* OSPFv3 MIB Interface Table values: ospfv3IfTable */ #define OSPFv3IFAREAID 3 #define OSPFv3IFTYPE 4 #define OSPFv3IFADMINSTATUS 5 #define OSPFv3IFRTRPRIORITY 6 #define OSPFv3IFTRANSITDELAY 7 #define OSPFv3IFRETRANSINTERVAL 8 #define OSPFv3IFHELLOINTERVAL 9 #define OSPFv3IFRTRDEADINTERVAL 10 #define OSPFv3IFPOLLINTERVAL 11 #define OSPFv3IFSTATE 12 #define OSPFv3IFDESIGNATEDROUTER 13 #define OSPFv3IFBACKUPDESIGNATEDROUTER 14 #define OSPFv3IFEVENTS 15 #define OSPFv3IFROWSTATUS 16 #define OSPFv3IFDEMAND 17 #define OSPFv3IFMETRICVALUE 18 #define OSPFv3IFLINKSCOPELSACOUNT 19 #define OSPFv3IFLINKLSACKSUMSUM 20 #define OSPFv3IFDEMANDNBRPROBE 21 #define OSPFv3IFDEMANDNBRPROBERETRANSLIMIT 22 #define OSPFv3IFDEMANDNBRPROBEINTERVAL 23 #define OSPFv3IFTEDISABLED 24 #define OSPFv3IFLINKLSASUPPRESSION 25 /* OSPFv3 MIB Virtual Interface Table values: ospfv3VirtIfTable */ #define OSPFv3VIRTIFINDEX 3 #define OSPFv3VIRTIFINSTID 4 #define OSPFv3VIRTIFTRANSITDELAY 5 #define OSPFv3VIRTIFRETRANSINTERVAL 6 #define OSPFv3VIRTIFHELLOINTERVAL 7 #define OSPFv3VIRTIFRTRDEADINTERVAL 8 #define OSPFv3VIRTIFSTATE 9 #define OSPFv3VIRTIFEVENTS 10 #define OSPFv3VIRTIFROWSTATUS 11 #define OSPFv3VIRTIFLINKSCOPELSACOUNT 12 #define OSPFv3VIRTIFLINKLSACKSUMSUM 13 /* OSPFv3 MIB Neighbors Table values: ospfv3NbrTable */ #define OSPFv3NBRADDRESSTYPE 4 #define OSPFv3NBRADDRESS 5 #define OSPFv3NBROPTIONS 6 #define OSPFv3NBRPRIORITY 7 #define OSPFv3NBRSTATE 8 #define OSPFv3NBREVENTS 9 #define OSPFv3NBRLSRETRANSQLEN 10 #define OSPFv3NBRHELLOSUPPRESSED 11 #define OSPFv3NBRIFID 12 #define OSPFv3NBRRESTARTHELPERSTATUS 13 #define OSPFv3NBRRESTARTHELPERAGE 14 #define OSPFv3NBRRESTARTHELPEREXITREASON 15 /* OSPFv3 MIB Configured Neighbors Table values: ospfv3CfgNbrTable */ #define OSPFv3CFGNBRPRIORITY 5 #define OSPFv3CFGNBRROWSTATUS 6 /* OSPFv3 MIB Virtual Neighbors Table values: ospfv3VirtNbrTable */ #define OSPFv3VIRTNBRIFINDEX 3 #define OSPFv3VIRTNBRIFINSTID 4 #define OSPFv3VIRTNBRADDRESSTYPE 5 #define OSPFv3VIRTNBRADDRESS 6 #define OSPFv3VIRTNBROPTIONS 7 #define OSPFv3VIRTNBRSTATE 8 #define OSPFv3VIRTNBREVENTS 9 #define OSPFv3VIRTNBRLSRETRANSQLEN 10 #define OSPFv3VIRTNBRHELLOSUPPRESSED 11 #define OSPFv3VIRTNBRIFID 12 #define OSPFv3VIRTNBRRESTARTHELPERSTATUS 13 #define OSPFv3VIRTNBRRESTARTHELPERAGE 14 #define OSPFv3VIRTNBRRESTARTHELPEREXITREASON 15 /* OSPFv3 MIB Area Aggregate Table values: ospfv3AreaAggregateTable */ #define OSPFv3AREAAGGREGATEROWSTATUS 6 #define OSPFv3AREAAGGREGATEEFFECT 7 #define OSPFv3AREAAGGREGATEROUTETAG 8 /* SYNTAX Status from OSPF-MIB. */ #define OSPF_STATUS_ENABLED 1 #define OSPF_STATUS_DISABLED 2 /* SNMP value hack. */ #define COUNTER ASN_COUNTER #define INTEGER ASN_INTEGER #define GAUGE ASN_GAUGE #define UNSIGNED ASN_UNSIGNED #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR /* For return values e.g. SNMP_INTEGER macro */ SNMP_LOCAL_VARIABLES /* OSPFv3-MIB instances. */ oid ospfv3_oid [] = { OSPFv3MIB }; oid ospfv3_trap_oid [] = { OSPFv3MIB, 0 }; /* Hook functions. */ static u_char *ospfv3GeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3AreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3WwLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3NbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfv3IfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); struct variable ospfv3_variables[] = { /* OSPF general variables */ {OSPFv3ROUTERID, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 1}}, {OSPFv3ADMINSTAT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 2}}, {OSPFv3VERSIONNUMBER, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 3}}, {OSPFv3AREABDRRTRSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 4}}, {OSPFv3ASBDRRTRSTATUS, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 5}}, {OSPFv3ASSCOPELSACOUNT, GAUGE, RONLY, ospfv3GeneralGroup, 3, {1, 1, 6}}, {OSPFv3ASSCOPELSACHECKSUMSUM,UNSIGNED, RONLY, ospfv3GeneralGroup, 3, {1, 1, 7}}, {OSPFv3ORIGINATENEWLSAS, COUNTER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 8}}, {OSPFv3RXNEWLSAS, COUNTER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 9}}, {OSPFv3EXTLSACOUNT, GAUGE, RONLY, ospfv3GeneralGroup, 3, {1, 1, 10}}, {OSPFv3EXTAREALSDBLIMIT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 11}}, {OSPFv3EXITOVERFLOWINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 12}}, {OSPFv3DEMANDEXTENSIONS, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 13}}, {OSPFv3REFERENCEBANDWIDTH, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 14}}, {OSPFv3RESTARTSUPPORT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 15}}, {OSPFv3RESTARTINTERVAL, UNSIGNED, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 16}}, {OSPFv3RESTARTSTRICTLSACHECKING, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 17}}, {OSPFv3RESTARTSTATUS, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 18}}, {OSPFv3RESTARTAGE, UNSIGNED, RONLY, ospfv3GeneralGroup, 3, {1, 1, 19}}, {OSPFv3RESTARTEXITREASON, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 20}}, {OSPFv3NOTIFICATIONENABLE, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 21}}, {OSPFv3STUBROUTERSUPPORT, INTEGER, RONLY, ospfv3GeneralGroup, 3, {1, 1, 22}}, {OSPFv3STUBROUTERADVERTISEMENT, INTEGER, RWRITE, ospfv3GeneralGroup, 3, {1, 1, 23}}, {OSPFv3DISCONTINUITYTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, 3, {1, 1, 24}}, {OSPFv3RESTARTTIME, TIMETICKS, RONLY, ospfv3GeneralGroup, 3, {1, 1, 25}}, /* OSPFv3 Area Data Structure */ {OSPFv3IMPORTASEXTERN, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 2}}, {OSPFv3AREASPFRUNS, COUNTER, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 3}}, {OSPFv3AREABDRRTRCOUNT, GAUGE, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 4}}, {OSPFv3AREAASBDRRTRCOUNT, GAUGE, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 5}}, {OSPFv3AREASCOPELSACOUNT, GAUGE, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 6}}, {OSPFv3AREASCOPELSACKSUMSUM, UNSIGNED, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 7}}, {OSPFv3AREASUMMARY, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 8}}, {OSPFv3AREAROWSTATUS, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 9}}, {OSPFv3AREASTUBMETRIC, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 10}}, {OSPFv3AREANSSATRANSLATORROLE, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 11}}, {OSPFv3AREANSSATRANSLATORSTATE, INTEGER, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 12}}, {OSPFv3AREANSSATRANSLATORSTABINTERVAL, UNSIGNED, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 13}}, {OSPFv3AREANSSATRANSLATOREVENTS, COUNTER, RONLY, ospfv3AreaEntry, 4, {1, 2, 1, 14}}, {OSPFv3AREASTUBMETRICTYPE, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 15}}, {OSPFv3AREATEENABLED, INTEGER, RWRITE, ospfv3AreaEntry, 4, {1, 2, 1, 16}}, /* OSPFv3 AS LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 4}}, {OSPFv3WWLSDBAGE | OSPFv3WWASTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 5}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 6}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWASTABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 7}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWASTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 3, 1, 8}}, /* OSPFv3 Area LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 5}}, {OSPFv3WWLSDBAGE | OSPFv3WWAREATABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 6}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 7}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWAREATABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 8}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWAREATABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 4, 1, 9}}, /* OSPFv3 Link LSDB */ {OSPFv3WWLSDBSEQUENCE | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 6}}, {OSPFv3WWLSDBAGE | OSPFv3WWLINKTABLE, UNSIGNED, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 7}}, {OSPFv3WWLSDBCHECKSUM | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 8}}, {OSPFv3WWLSDBADVERTISEMENT | OSPFv3WWLINKTABLE, STRING, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 9}}, {OSPFv3WWLSDBTYPEKNOWN | OSPFv3WWLINKTABLE, INTEGER, RONLY, ospfv3WwLsdbEntry, 4, {1, 5, 1, 10}}, /* OSPFv3 interfaces */ {OSPFv3IFAREAID, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 3}}, {OSPFv3IFTYPE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 4}}, {OSPFv3IFADMINSTATUS, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 5}}, {OSPFv3IFRTRPRIORITY, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 6}}, {OSPFv3IFTRANSITDELAY, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 7}}, {OSPFv3IFRETRANSINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 8}}, {OSPFv3IFHELLOINTERVAL, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 9}}, {OSPFv3IFRTRDEADINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 10}}, {OSPFv3IFPOLLINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 11}}, {OSPFv3IFSTATE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 12}}, {OSPFv3IFDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 13}}, {OSPFv3IFBACKUPDESIGNATEDROUTER, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 14}}, {OSPFv3IFEVENTS, COUNTER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 15}}, {OSPFv3IFROWSTATUS, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 16}}, {OSPFv3IFDEMAND, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 17}}, {OSPFv3IFMETRICVALUE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 18}}, {OSPFv3IFLINKSCOPELSACOUNT, GAUGE, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 19}}, {OSPFv3IFLINKLSACKSUMSUM, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 20}}, {OSPFv3IFDEMANDNBRPROBE, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 21}}, {OSPFv3IFDEMANDNBRPROBERETRANSLIMIT, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 22}}, {OSPFv3IFDEMANDNBRPROBEINTERVAL, UNSIGNED, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 23}}, {OSPFv3IFTEDISABLED, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 24}}, {OSPFv3IFLINKLSASUPPRESSION, INTEGER, RONLY, ospfv3IfEntry, 4, {1, 7, 1, 25}}, /* OSPFv3 neighbors */ {OSPFv3NBRADDRESSTYPE, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 4}}, {OSPFv3NBRADDRESS, STRING, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 5}}, {OSPFv3NBROPTIONS, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 6}}, {OSPFv3NBRPRIORITY, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 7}}, {OSPFv3NBRSTATE, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 8}}, {OSPFv3NBREVENTS, COUNTER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 9}}, {OSPFv3NBRLSRETRANSQLEN, GAUGE, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 10}}, {OSPFv3NBRHELLOSUPPRESSED, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 11}}, {OSPFv3NBRIFID, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 12}}, {OSPFv3NBRRESTARTHELPERSTATUS, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 13}}, {OSPFv3NBRRESTARTHELPERAGE, UNSIGNED, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 14}}, {OSPFv3NBRRESTARTHELPEREXITREASON, INTEGER, RONLY, ospfv3NbrEntry, 4, {1, 9, 1, 15}}, }; static u_char * ospfv3GeneralGroup (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { u_int16_t sum; u_int32_t count; struct ospf6_lsa *lsa = NULL; /* Check whether the instance identifier is valid */ if (smux_header_generic (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3ROUTERID: /* Router-ID of this OSPF instance. */ if (ospf6) return SNMP_INTEGER (ntohl (ospf6->router_id)); return SNMP_INTEGER (0); case OSPFv3ADMINSTAT: if (ospf6) return SNMP_INTEGER (CHECK_FLAG (ospf6->flag, OSPF6_DISABLED)? OSPF_STATUS_DISABLED:OSPF_STATUS_ENABLED); return SNMP_INTEGER (OSPF_STATUS_DISABLED); case OSPFv3VERSIONNUMBER: return SNMP_INTEGER (3); case OSPFv3AREABDRRTRSTATUS: if (ospf6) return SNMP_INTEGER (ospf6_is_router_abr (ospf6)?SNMP_TRUE:SNMP_FALSE); return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASBDRRTRSTATUS: if (ospf6) return SNMP_INTEGER (ospf6_asbr_is_asbr (ospf6)?SNMP_TRUE:SNMP_FALSE); return SNMP_INTEGER (SNMP_FALSE); case OSPFv3ASSCOPELSACOUNT: if (ospf6) return SNMP_INTEGER (ospf6->lsdb->count); return SNMP_INTEGER (0); case OSPFv3ASSCOPELSACHECKSUMSUM: if (ospf6) { for (sum = 0, lsa = ospf6_lsdb_head (ospf6->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); } return SNMP_INTEGER (0); case OSPFv3ORIGINATENEWLSAS: return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3RXNEWLSAS: return SNMP_INTEGER (0); /* Don't know where to get this value... */ case OSPFv3EXTLSACOUNT: if (ospf6) { for (count = 0, lsa = ospf6_lsdb_type_head (htons (OSPF6_LSTYPE_AS_EXTERNAL), ospf6->lsdb); lsa; lsa = ospf6_lsdb_type_next (htons (OSPF6_LSTYPE_AS_EXTERNAL), lsa)) count += 1; return SNMP_INTEGER (count); } return SNMP_INTEGER (0); case OSPFv3EXTAREALSDBLIMIT: return SNMP_INTEGER (-1); case OSPFv3EXITOVERFLOWINTERVAL: return SNMP_INTEGER (0); /* Not supported */ case OSPFv3DEMANDEXTENSIONS: return SNMP_INTEGER (0); /* Not supported */ case OSPFv3REFERENCEBANDWIDTH: if (ospf6) return SNMP_INTEGER (ospf6->ref_bandwidth); /* Otherwise, like for "not implemented". */ case OSPFv3RESTARTSUPPORT: case OSPFv3RESTARTINTERVAL: case OSPFv3RESTARTSTRICTLSACHECKING: case OSPFv3RESTARTSTATUS: case OSPFv3RESTARTAGE: case OSPFv3RESTARTEXITREASON: case OSPFv3NOTIFICATIONENABLE: case OSPFv3STUBROUTERSUPPORT: case OSPFv3STUBROUTERADVERTISEMENT: case OSPFv3DISCONTINUITYTIME: case OSPFv3RESTARTTIME: /* TODO: Not implemented */ return NULL; } return NULL; } static u_char * ospfv3AreaEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_area *oa, *area = NULL; struct ospf6_lsa *lsa = NULL; u_int32_t area_id = 0; u_int32_t count; u_int16_t sum; struct listnode *node; unsigned int len; char a[16]; struct ospf6_route *ro; if (ospf6 == NULL) return NULL; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; len = *length - v->namelen; len = (len >= 1 ? 1 : 0); if (exact && len != 1) return NULL; if (len) area_id = htonl (name[v->namelen]); inet_ntop (AF_INET, &area_id, a, sizeof (a)); zlog_debug ("SNMP access by area: %s, exact=%d len=%d length=%lu", a, exact, len, (u_long)*length); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { if (area == NULL) { if (len == 0) /* return first area entry */ area = oa; else if (exact && ntohl (oa->area_id) == ntohl (area_id)) area = oa; else if (ntohl (oa->area_id) > ntohl (area_id)) area = oa; } } if (area == NULL) return NULL; *length = v->namelen + 1; name[v->namelen] = ntohl (area->area_id); inet_ntop (AF_INET, &area->area_id, a, sizeof (a)); zlog_debug ("SNMP found area: %s, exact=%d len=%d length=%lu", a, exact, len, (u_long)*length); switch (v->magic) { case OSPFv3IMPORTASEXTERN: /* No NSSA support */ return SNMP_INTEGER (IS_AREA_STUB(area)?2:1); case OSPFv3AREASPFRUNS: return SNMP_INTEGER (area->spf_calculation); case OSPFv3AREABDRRTRCOUNT: case OSPFv3AREAASBDRRTRCOUNT: count = 0; for (ro = ospf6_route_head (ospf6->brouter_table); ro; ro = ospf6_route_next (ro)) { if (ntohl (ro->path.area_id) != ntohl (area->area_id)) continue; if (v->magic == OSPFv3AREABDRRTRCOUNT && CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_B)) count++; if (v->magic == OSPFv3AREAASBDRRTRCOUNT && CHECK_FLAG (ro->path.router_bits, OSPF6_ROUTER_BIT_E)) count++; } return SNMP_INTEGER (count); case OSPFv3AREASCOPELSACOUNT: return SNMP_INTEGER (area->lsdb->count); case OSPFv3AREASCOPELSACKSUMSUM: for (sum = 0, lsa = ospf6_lsdb_head (area->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); case OSPFv3AREASUMMARY: return SNMP_INTEGER (2); /* sendAreaSummary */ case OSPFv3AREAROWSTATUS: return SNMP_INTEGER (1); /* Active */ case OSPFv3AREASTUBMETRIC: case OSPFv3AREANSSATRANSLATORROLE: case OSPFv3AREANSSATRANSLATORSTATE: case OSPFv3AREANSSATRANSLATORSTABINTERVAL: case OSPFv3AREANSSATRANSLATOREVENTS: case OSPFv3AREASTUBMETRICTYPE: case OSPFv3AREATEENABLED: /* Not implemented. */ return NULL; } return NULL; } static int if_icmp_func (struct interface *ifp1, struct interface *ifp2) { return (ifp1->ifindex - ifp2->ifindex); } static u_char * ospfv3WwLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf6_lsa *lsa = NULL; u_int32_t ifindex, area_id, id, instid, adv_router; u_int16_t type; int len; oid *offset; int offsetlen; char a[16], b[16], c[16]; struct ospf6_area *oa; struct listnode *node; struct interface *iif; struct ospf6_interface *oi = NULL; struct list *ifslist; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; instid = ifindex = area_id = type = id = adv_router = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && (v->magic & OSPFv3WWASTABLE) && offsetlen != 3) return NULL; if (exact && (v->magic & OSPFv3WWAREATABLE) && offsetlen != 4) return NULL; if (exact && (v->magic & OSPFv3WWLINKTABLE) && offsetlen != 5) return NULL; if (v->magic & OSPFv3WWLINKTABLE) { /* Parse ifindex */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; } else if (v->magic & OSPFv3WWAREATABLE) { /* Parse area-id */ len = (offsetlen < 1 ? 0 : 1); if (len) area_id = htonl (*offset); offset += len; offsetlen -= len; } /* Parse type */ len = (offsetlen < 1 ? 0 : 1); if (len) type = htons (*offset); offset += len; offsetlen -= len; /* Parse Router-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) adv_router = htonl (*offset); offset += len; offsetlen -= len; /* Parse LS-ID */ len = (offsetlen < 1 ? 0 : 1); if (len) id = htonl (*offset); offset += len; offsetlen -= len; if (exact) { if (v->magic & OSPFv3WWASTABLE) { lsa = ospf6_lsdb_lookup (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) { oa = ospf6_area_lookup (area_id, ospf6); if (!oa) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oa->lsdb); } else if (v->magic & OSPFv3WWLINKTABLE) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; lsa = ospf6_lsdb_lookup (type, id, adv_router, oi->lsdb); } } else { if (v->magic & OSPFv3WWASTABLE) { if (ospf6->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, ospf6->lsdb); } else if (v->magic & OSPFv3WWAREATABLE) for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { if (oa->area_id < area_id) continue; if (oa->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oa->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; } else if (v->magic & OSPFv3WWLINKTABLE) { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, node, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, node, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; if (iif->ifindex < ifindex) continue; if (oi->instance_id < instid) continue; if (oi->lsdb->count) lsa = ospf6_lsdb_lookup_next (type, id, adv_router, oi->lsdb); if (lsa) break; type = 0; id = 0; adv_router = 0; oi = NULL; } list_delete_all_node (ifslist); } } if (! lsa) return NULL; /* Add indexes */ if (v->magic & OSPFv3WWASTABLE) { *length = v->namelen + 3; offset = name + v->namelen; } else if (v->magic & OSPFv3WWAREATABLE) { *length = v->namelen + 4; offset = name + v->namelen; *offset = ntohl (oa->area_id); offset++; } else if (v->magic & OSPFv3WWLINKTABLE) { *length = v->namelen + 5; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; } *offset = ntohs (lsa->header->type); offset++; *offset = ntohl (lsa->header->adv_router); offset++; *offset = ntohl (lsa->header->id); offset++; /* Return the current value of the variable */ switch (v->magic & OSPFv3WWCOLUMN) { case OSPFv3WWLSDBSEQUENCE: return SNMP_INTEGER (ntohl (lsa->header->seqnum)); break; case OSPFv3WWLSDBAGE: ospf6_lsa_age_current (lsa); return SNMP_INTEGER (ntohs (lsa->header->age)); break; case OSPFv3WWLSDBCHECKSUM: return SNMP_INTEGER (ntohs (lsa->header->checksum)); break; case OSPFv3WWLSDBADVERTISEMENT: *var_len = ntohs (lsa->header->length); return (u_char *) lsa->header; break; case OSPFv3WWLSDBTYPEKNOWN: return SNMP_INTEGER (OSPF6_LSA_IS_KNOWN (lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); break; } return NULL; } static u_char * ospfv3IfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { unsigned int ifindex, instid; struct ospf6_interface *oi = NULL; struct ospf6_lsa *lsa = NULL; struct interface *iif; struct listnode *i; struct list *ifslist; oid *offset; int offsetlen, len; u_int32_t sum; if (smux_header_table (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = instid = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && offsetlen != 2) return NULL; /* Parse if index */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; } else { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; if (iif->ifindex > ifindex || (iif->ifindex == ifindex && (oi->instance_id > instid))) break; oi = NULL; } list_delete_all_node (ifslist); } if (!oi) return NULL; /* Add Index (IfIndex, IfInstId) */ *length = v->namelen + 2; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3IFAREAID: if (oi->area) return SNMP_INTEGER (ntohl (oi->area->area_id)); break; case OSPFv3IFTYPE: if (if_is_broadcast (oi->interface)) return SNMP_INTEGER (1); else if (if_is_pointopoint (oi->interface)) return SNMP_INTEGER (3); else break; /* Unknown, don't put anything */ case OSPFv3IFADMINSTATUS: if (oi->area) return SNMP_INTEGER (OSPF_STATUS_ENABLED); return SNMP_INTEGER (OSPF_STATUS_DISABLED); case OSPFv3IFRTRPRIORITY: return SNMP_INTEGER (oi->priority); case OSPFv3IFTRANSITDELAY: return SNMP_INTEGER (oi->transdelay); case OSPFv3IFRETRANSINTERVAL: return SNMP_INTEGER (oi->rxmt_interval); case OSPFv3IFHELLOINTERVAL: return SNMP_INTEGER (oi->hello_interval); case OSPFv3IFRTRDEADINTERVAL: return SNMP_INTEGER (oi->dead_interval); case OSPFv3IFPOLLINTERVAL: /* No support for NBMA */ break; case OSPFv3IFSTATE: return SNMP_INTEGER (oi->state); case OSPFv3IFDESIGNATEDROUTER: return SNMP_INTEGER (ntohl (oi->drouter)); case OSPFv3IFBACKUPDESIGNATEDROUTER: return SNMP_INTEGER (ntohl (oi->bdrouter)); case OSPFv3IFEVENTS: return SNMP_INTEGER (oi->state_change); case OSPFv3IFROWSTATUS: return SNMP_INTEGER (1); case OSPFv3IFDEMAND: return SNMP_INTEGER (SNMP_FALSE); case OSPFv3IFMETRICVALUE: return SNMP_INTEGER (oi->cost); case OSPFv3IFLINKSCOPELSACOUNT: return SNMP_INTEGER (oi->lsdb->count); case OSPFv3IFLINKLSACKSUMSUM: for (sum = 0, lsa = ospf6_lsdb_head (oi->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) sum += ntohs (lsa->header->checksum); return SNMP_INTEGER (sum); case OSPFv3IFDEMANDNBRPROBE: case OSPFv3IFDEMANDNBRPROBERETRANSLIMIT: case OSPFv3IFDEMANDNBRPROBEINTERVAL: case OSPFv3IFTEDISABLED: case OSPFv3IFLINKLSASUPPRESSION: /* Not implemented. Only works if all the last ones are not implemented! */ return NULL; } /* Try an internal getnext. Some columns are missing in this table. */ if (!exact && (name[*length-1] < MAX_SUBID)) return ospfv3IfEntry(v, name, length, exact, var_len, write_method); return NULL; } static u_char * ospfv3NbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { unsigned int ifindex, instid, rtrid; struct ospf6_interface *oi = NULL; struct ospf6_neighbor *on = NULL; struct interface *iif; struct listnode *i, *j; struct list *ifslist; oid *offset; int offsetlen, len; if (smux_header_table (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = instid = rtrid = 0; /* Check OSPFv3 instance. */ if (ospf6 == NULL) return NULL; /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; if (exact && offsetlen != 3) return NULL; /* Parse if index */ len = (offsetlen < 1 ? 0 : 1); if (len) ifindex = *offset; offset += len; offsetlen -= len; /* Parse instance ID */ len = (offsetlen < 1 ? 0 : 1); if (len) instid = *offset; offset += len; offsetlen -= len; /* Parse router ID */ len = (offsetlen < 1 ? 0 : 1); if (len) rtrid = htonl (*offset); offset += len; offsetlen -= len; if (exact) { oi = ospf6_interface_lookup_by_ifindex (ifindex); if (!oi || oi->instance_id != instid) return NULL; on = ospf6_neighbor_lookup (rtrid, oi); } else { /* We build a sorted list of interfaces */ ifslist = list_new (); if (!ifslist) return NULL; ifslist->cmp = (int (*)(void *, void *))if_icmp_func; for (ALL_LIST_ELEMENTS_RO (iflist, i, iif)) listnode_add_sort (ifslist, iif); for (ALL_LIST_ELEMENTS_RO (ifslist, i, iif)) { if (!iif->ifindex) continue; oi = ospf6_interface_lookup_by_ifindex (iif->ifindex); if (!oi) continue; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { if (iif->ifindex > ifindex || (iif->ifindex == ifindex && (oi->instance_id > instid || (oi->instance_id == instid && ntohl (on->router_id) > ntohl (rtrid))))) break; } if (on) break; oi = NULL; on = NULL; } list_delete_all_node (ifslist); } if (!oi || !on) return NULL; /* Add Index (IfIndex, IfInstId, RtrId) */ *length = v->namelen + 3; offset = name + v->namelen; *offset = oi->interface->ifindex; offset++; *offset = oi->instance_id; offset++; *offset = ntohl (on->router_id); offset++; /* Return the current value of the variable */ switch (v->magic) { case OSPFv3NBRADDRESSTYPE: return SNMP_INTEGER (2); /* IPv6 only */ case OSPFv3NBRADDRESS: *var_len = sizeof (struct in6_addr); return (u_char *) &on->linklocal_addr; case OSPFv3NBROPTIONS: return SNMP_INTEGER (on->options[2]); case OSPFv3NBRPRIORITY: return SNMP_INTEGER (on->priority); case OSPFv3NBRSTATE: return SNMP_INTEGER (on->state); case OSPFv3NBREVENTS: return SNMP_INTEGER (on->state_change); case OSPFv3NBRLSRETRANSQLEN: return SNMP_INTEGER (on->retrans_list->count); case OSPFv3NBRHELLOSUPPRESSED: return SNMP_INTEGER (SNMP_FALSE); case OSPFv3NBRIFID: return SNMP_INTEGER (on->ifindex); case OSPFv3NBRRESTARTHELPERSTATUS: case OSPFv3NBRRESTARTHELPERAGE: case OSPFv3NBRRESTARTHELPEREXITREASON: /* Not implemented. Only works if all the last ones are not implemented! */ return NULL; } return NULL; } /* OSPF Traps. */ #define NBRSTATECHANGE 2 #define IFSTATECHANGE 10 static struct trap_object ospf6NbrTrapList[] = { {-3, {1, 1, OSPFv3ROUTERID}}, {4, {1, 9, 1, OSPFv3NBRADDRESSTYPE}}, {4, {1, 9, 1, OSPFv3NBRADDRESS}}, {4, {1, 9, 1, OSPFv3NBRSTATE}} }; static struct trap_object ospf6IfTrapList[] = { {-3, {1, 1, OSPFv3ROUTERID}}, {4, {1, 7, 1, OSPFv3IFSTATE}}, {4, {1, 7, 1, OSPFv3IFADMINSTATUS}}, {4, {1, 7, 1, OSPFv3IFAREAID}} }; void ospf6TrapNbrStateChange (struct ospf6_neighbor *on) { oid index[3]; index[0] = on->ospf6_if->interface->ifindex; index[1] = on->ospf6_if->instance_id; index[2] = ntohl (on->router_id); smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), index, 3, ospf6NbrTrapList, sizeof ospf6NbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); } void ospf6TrapIfStateChange (struct ospf6_interface *oi) { oid index[2]; index[0] = oi->interface->ifindex; index[1] = oi->instance_id; smux_trap (ospfv3_variables, sizeof ospfv3_variables / sizeof (struct variable), ospfv3_trap_oid, sizeof ospfv3_trap_oid / sizeof (oid), ospfv3_oid, sizeof ospfv3_oid / sizeof (oid), index, 2, ospf6IfTrapList, sizeof ospf6IfTrapList / sizeof (struct trap_object), IFSTATECHANGE); } /* Register OSPFv3-MIB. */ void ospf6_snmp_init (struct thread_master *master) { smux_init (master); REGISTER_MIB ("OSPFv3MIB", ospfv3_variables, variable, ospfv3_oid); } #endif /* HAVE_SNMP */ quagga-0.99.24.1/ospf6d/ospf6_abr.c0000644000175000017500000006747112476520570013501 00000000000000/* * Area Border Router function. * Copyright (C) 2004 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "linklist.h" #include "command.h" #include "thread.h" #include "plist.h" #include "filter.h" #include "ospf6_proto.h" #include "ospf6_route.h" #include "ospf6_lsa.h" #include "ospf6_route.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_flood.h" #include "ospf6_intra.h" #include "ospf6_abr.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_abr; int ospf6_is_router_abr (struct ospf6 *o) { struct listnode *node; struct ospf6_area *oa; int area_count = 0; for (ALL_LIST_ELEMENTS_RO (o->area_list, node, oa)) if (IS_AREA_ENABLED (oa)) area_count++; if (area_count > 1) return 1; return 0; } void ospf6_abr_enable_area (struct ospf6_area *area) { struct ospf6_area *oa; struct ospf6_route *ro; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) { /* update B bit for each area */ OSPF6_ROUTER_LSA_SCHEDULE (oa); /* install other area's configured address range */ if (oa != area) { for (ro = ospf6_route_head (oa->range_table); ro; ro = ospf6_route_next (ro)) { if (CHECK_FLAG (ro->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) ospf6_abr_originate_summary_to_area (ro, area); } } } /* install calculated routes to border routers */ for (ro = ospf6_route_head (area->ospf6->brouter_table); ro; ro = ospf6_route_next (ro)) ospf6_abr_originate_summary_to_area (ro, area); /* install calculated routes to network (may be rejected by ranges) */ for (ro = ospf6_route_head (area->ospf6->route_table); ro; ro = ospf6_route_next (ro)) ospf6_abr_originate_summary_to_area (ro, area); } void ospf6_abr_disable_area (struct ospf6_area *area) { struct ospf6_area *oa; struct ospf6_route *ro; struct ospf6_lsa *old; struct listnode *node, *nnode; /* Withdraw all summary prefixes previously originated */ for (ro = ospf6_route_head (area->summary_prefix); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_prefix); } /* Withdraw all summary router-routes previously originated */ for (ro = ospf6_route_head (area->summary_router); ro; ro = ospf6_route_next (ro)) { old = ospf6_lsdb_lookup (ro->path.origin.type, ro->path.origin.id, area->ospf6->router_id, area->lsdb); if (old) ospf6_lsa_purge (old); ospf6_route_remove (ro, area->summary_router); } /* Schedule Router-LSA for each area (ABR status may change) */ for (ALL_LIST_ELEMENTS (area->ospf6->area_list, node, nnode, oa)) /* update B bit for each area */ OSPF6_ROUTER_LSA_SCHEDULE (oa); } /* RFC 2328 12.4.3. Summary-LSAs */ void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area) { struct ospf6_lsa *lsa, *old = NULL; struct ospf6_interface *oi; struct ospf6_route *summary, *range = NULL; struct ospf6_area *route_area; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; caddr_t p; struct ospf6_inter_prefix_lsa *prefix_lsa; struct ospf6_inter_router_lsa *router_lsa; struct ospf6_route_table *summary_table = NULL; u_int16_t type; char buf[64]; int is_debug = 0; if (route->type == OSPF6_DEST_TYPE_ROUTER) { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_ROUTER)) { is_debug++; inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for ASBR %s", area->name, buf); } summary_table = area->summary_router; } else { if (IS_OSPF6_DEBUG_ABR || IS_OSPF6_DEBUG_ORIGINATE (INTER_PREFIX)) { is_debug++; prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("Originating summary in area %s for %s", area->name, buf); } summary_table = area->summary_prefix; } summary = ospf6_route_lookup (&route->prefix, summary_table); if (summary) old = ospf6_lsdb_lookup (summary->path.origin.type, summary->path.origin.id, area->ospf6->router_id, area->lsdb); /* if this route has just removed, remove corresponding LSA */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) { if (is_debug) zlog_debug ("The route has just removed, purge previous LSA"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Only destination type network, range or ASBR are considered */ if (route->type != OSPF6_DEST_TYPE_NETWORK && route->type != OSPF6_DEST_TYPE_RANGE && (route->type != OSPF6_DEST_TYPE_ROUTER || ! CHECK_FLAG (route->path.router_bits, OSPF6_ROUTER_BIT_E))) { if (is_debug) zlog_debug ("Route type is none of network, range nor ASBR, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* AS External routes are never considered */ if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (is_debug) zlog_debug ("Path type is external, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the path's area is the same as target area */ if (route->path.area_id == area->area_id) { if (is_debug) zlog_debug ("The route is in the area itself, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the nexthops belongs to the target area */ oi = ospf6_interface_lookup_by_ifindex (route->nexthop[0].ifindex); if (oi && oi->area && oi->area == area) { if (is_debug) zlog_debug ("The route's nexthop is in the same area, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* do not generate if the route cost is greater or equal to LSInfinity */ if (route->path.cost >= OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("The cost exceeds LSInfinity, withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* if this is a route to ASBR */ if (route->type == OSPF6_DEST_TYPE_ROUTER) { /* Only the prefered best path is considered */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST)) { if (is_debug) zlog_debug ("This is the secondary path to the ASBR, ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Do not generate if the area is stub */ /* XXX */ } /* if this is an intra-area route, this may be suppressed by aggregation */ if (route->type == OSPF6_DEST_TYPE_NETWORK && route->path.type == OSPF6_PATH_TYPE_INTRA) { /* search for configured address range for the route's area */ route_area = ospf6_area_lookup (route->path.area_id, area->ospf6); assert (route_area); range = ospf6_route_lookup_bestmatch (&route->prefix, route_area->range_table); /* ranges are ignored when originate backbone routes to transit area. Otherwise, if ranges are configured, the route is suppressed. */ if (range && ! CHECK_FLAG (range->flag, OSPF6_ROUTE_REMOVE) && (route->path.area_id != OSPF_AREA_BACKBONE || ! IS_AREA_TRANSIT (area))) { if (is_debug) { prefix2str (&range->prefix, buf, sizeof (buf)); zlog_debug ("Suppressed by range %s of area %s", buf, route_area->name); } if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* If this is a configured address range */ if (route->type == OSPF6_DEST_TYPE_RANGE) { /* If DoNotAdvertise is set */ if (CHECK_FLAG (route->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) { if (is_debug) zlog_debug ("This is the range with DoNotAdvertise set. ignore"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } /* Whether the route have active longer prefix */ if (! CHECK_FLAG (route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) { if (is_debug) zlog_debug ("The range is not active. withdraw"); if (summary) ospf6_route_remove (summary, summary_table); if (old) ospf6_lsa_purge (old); return; } } /* Check export list */ if (EXPORT_NAME (area)) { if (EXPORT_LIST (area) == NULL) EXPORT_LIST (area) = access_list_lookup (AFI_IP6, EXPORT_NAME (area)); if (EXPORT_LIST (area)) if (access_list_apply (EXPORT_LIST (area), &route->prefix) == FILTER_DENY) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof(buf)); zlog_debug ("prefix %s was denied by export list", buf); } return; } } /* Check filter-list */ if (PREFIX_NAME_OUT (area)) { if (PREFIX_LIST_OUT (area) == NULL) PREFIX_LIST_OUT (area) = prefix_list_lookup(AFI_IP6, PREFIX_NAME_OUT (area)); if (PREFIX_LIST_OUT (area)) if (prefix_list_apply (PREFIX_LIST_OUT (area), &route->prefix) != PREFIX_PERMIT) { if (is_debug) { inet_ntop (AF_INET, &(ADV_ROUTER_IN_PREFIX (&route->prefix)), buf, sizeof (buf)); zlog_debug ("prefix %s was denied by filter-list out", buf); } return; } } /* the route is going to be originated. store it in area's summary_table */ if (summary == NULL) { summary = ospf6_route_copy (route); if (route->type == OSPF6_DEST_TYPE_NETWORK || route->type == OSPF6_DEST_TYPE_RANGE) summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_PREFIX); else summary->path.origin.type = htons (OSPF6_LSTYPE_INTER_ROUTER); summary->path.origin.adv_router = area->ospf6->router_id; summary->path.origin.id = ospf6_new_ls_id (summary->path.origin.type, summary->path.origin.adv_router, area->lsdb); summary = ospf6_route_add (summary, summary_table); } else { summary->type = route->type; quagga_gettime (QUAGGA_CLK_MONOTONIC, &summary->changed); } summary->path.router_bits = route->path.router_bits; summary->path.options[0] = route->path.options[0]; summary->path.options[1] = route->path.options[1]; summary->path.options[2] = route->path.options[2]; summary->path.prefix_options = route->path.prefix_options; summary->path.area_id = area->area_id; summary->path.type = OSPF6_PATH_TYPE_INTER; summary->path.cost = route->path.cost; summary->nexthop[0] = route->nexthop[0]; /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; if (route->type == OSPF6_DEST_TYPE_ROUTER) { router_lsa = (struct ospf6_inter_router_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) router_lsa + sizeof (struct ospf6_inter_router_lsa); /* Fill Inter-Area-Router-LSA */ router_lsa->options[0] = route->path.options[0]; router_lsa->options[1] = route->path.options[1]; router_lsa->options[2] = route->path.options[2]; OSPF6_ABR_SUMMARY_METRIC_SET (router_lsa, route->path.cost); router_lsa->router_id = ADV_ROUTER_IN_PREFIX (&route->prefix); type = htons (OSPF6_LSTYPE_INTER_ROUTER); } else { prefix_lsa = (struct ospf6_inter_prefix_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) prefix_lsa + sizeof (struct ospf6_inter_prefix_lsa); /* Fill Inter-Area-Prefix-LSA */ OSPF6_ABR_SUMMARY_METRIC_SET (prefix_lsa, route->path.cost); prefix_lsa->prefix.prefix_length = route->prefix.prefixlen; prefix_lsa->prefix.prefix_options = route->path.prefix_options; /* set Prefix */ memcpy (p, &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); ospf6_prefix_apply_mask (&prefix_lsa->prefix); p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); type = htons (OSPF6_LSTYPE_INTER_PREFIX); } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = type; lsa_header->id = summary->path.origin.id; lsa_header->adv_router = area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, area->lsdb); lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, area); } static void ospf6_abr_range_update (struct ospf6_route *range) { u_int32_t cost = 0; struct ospf6_route *ro; assert (range->type == OSPF6_DEST_TYPE_RANGE); /* update range's cost and active flag */ for (ro = ospf6_route_match_head (&range->prefix, ospf6->route_table); ro; ro = ospf6_route_match_next (&range->prefix, ro)) { if (ro->path.area_id == range->path.area_id && ! CHECK_FLAG (ro->flag, OSPF6_ROUTE_REMOVE)) cost = MAX (cost, ro->path.cost); } if (range->path.cost != cost) { range->path.cost = cost; if (range->path.cost) SET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); else UNSET_FLAG (range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY); ospf6_abr_originate_summary (range); } } void ospf6_abr_originate_summary (struct ospf6_route *route) { struct listnode *node, *nnode; struct ospf6_area *oa; struct ospf6_route *range = NULL; if (route->type == OSPF6_DEST_TYPE_NETWORK) { oa = ospf6_area_lookup (route->path.area_id, ospf6); range = ospf6_route_lookup_bestmatch (&route->prefix, oa->range_table); if (range) ospf6_abr_range_update (range); } for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) ospf6_abr_originate_summary_to_area (route, oa); } /* RFC 2328 16.2. Calculating the inter-area routes */ void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct prefix prefix, abr_prefix; struct ospf6_route_table *table = NULL; struct ospf6_route *range, *route, *old = NULL; struct ospf6_route *abr_entry; u_char type = 0; char options[3] = {0, 0, 0}; u_int8_t prefix_options = 0; u_int32_t cost = 0; u_char router_bits = 0; int i; char buf[64]; int is_debug = 0; struct ospf6_inter_prefix_lsa *prefix_lsa = NULL; struct ospf6_inter_router_lsa *router_lsa = NULL; memset (&prefix, 0, sizeof (prefix)); if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_PREFIX)) { is_debug++; zlog_debug ("Examin %s in area %s", lsa->name, oa->name); } prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, &prefix_lsa->prefix); if (is_debug) prefix2str (&prefix, buf, sizeof (buf)); table = oa->ospf6->route_table; type = OSPF6_DEST_TYPE_NETWORK; prefix_options = prefix_lsa->prefix.prefix_options; cost = OSPF6_ABR_SUMMARY_METRIC (prefix_lsa); } else if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { if (IS_OSPF6_DEBUG_EXAMIN (INTER_ROUTER)) { is_debug++; zlog_debug ("Examin %s in area %s", lsa->name, oa->name); } router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_linkstate_prefix (router_lsa->router_id, htonl (0), &prefix); if (is_debug) inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); table = oa->ospf6->brouter_table; type = OSPF6_DEST_TYPE_ROUTER; options[0] = router_lsa->options[0]; options[1] = router_lsa->options[1]; options[2] = router_lsa->options[2]; cost = OSPF6_ABR_SUMMARY_METRIC (router_lsa); SET_FLAG (router_bits, OSPF6_ROUTER_BIT_E); } else assert (0); /* Find existing route */ route = ospf6_route_lookup (&prefix, table); if (route) ospf6_route_lock (route); while (route && ospf6_route_is_prefix (&prefix, route)) { if (route->path.area_id == oa->area_id && route->path.origin.type == lsa->header->type && route->path.origin.id == lsa->header->id && route->path.origin.adv_router == lsa->header->adv_router && ! CHECK_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED)) old = route; route = ospf6_route_next (route); } /* (1) if cost == LSInfinity or if the LSA is MaxAge */ if (cost == OSPF_LS_INFINITY) { if (is_debug) zlog_debug ("cost is LS_INFINITY, ignore"); if (old) ospf6_route_remove (old, table); return; } if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (is_debug) zlog_debug ("LSA is MaxAge, ignore"); if (old) ospf6_route_remove (old, table); return; } /* (2) if the LSA is self-originated, ignore */ if (lsa->header->adv_router == oa->ospf6->router_id) { if (is_debug) zlog_debug ("LSA is self-originated, ignore"); if (old) ospf6_route_remove (old, table); return; } /* (3) if the prefix is equal to an active configured address range */ /* or if the NU bit is set in the prefix */ if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_PREFIX)) { range = ospf6_route_lookup (&prefix, oa->range_table); if (range) { if (is_debug) zlog_debug ("Prefix is equal to address range, ignore"); if (old) ospf6_route_remove (old, table); return; } if (CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU) || CHECK_FLAG (prefix_lsa->prefix.prefix_options, OSPF6_PREFIX_OPTION_LA)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); return; } } if (lsa->header->type == htons (OSPF6_LSTYPE_INTER_ROUTER)) { /* To pass test suites */ if (! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_R) || ! OSPF6_OPT_ISSET (router_lsa->options, OSPF6_OPT_V6)) { if (is_debug) zlog_debug ("Prefix has NU/LA bit set, ignore"); if (old) ospf6_route_remove (old, table); return; } } /* (4) if the routing table entry for the ABR does not exist */ ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &abr_prefix); abr_entry = ospf6_route_lookup (&abr_prefix, oa->ospf6->brouter_table); if (abr_entry == NULL || abr_entry->path.area_id != oa->area_id || CHECK_FLAG (abr_entry->flag, OSPF6_ROUTE_REMOVE) || ! CHECK_FLAG (abr_entry->path.router_bits, OSPF6_ROUTER_BIT_B)) { if (is_debug) zlog_debug ("ABR router entry does not exist, ignore"); if (old) ospf6_route_remove (old, table); return; } /* Check import list */ if (IMPORT_NAME (oa)) { if (IMPORT_LIST (oa) == NULL) IMPORT_LIST (oa) = access_list_lookup (AFI_IP6, IMPORT_NAME (oa)); if (IMPORT_LIST (oa)) if (access_list_apply (IMPORT_LIST (oa), &prefix) == FILTER_DENY) { if (is_debug) zlog_debug ("Prefix was denied by import-list"); if (old) ospf6_route_remove (old, table); return; } } /* Check input prefix-list */ if (PREFIX_NAME_IN (oa)) { if (PREFIX_LIST_IN (oa) == NULL) PREFIX_LIST_IN (oa) = prefix_list_lookup (AFI_IP6, PREFIX_NAME_IN (oa)); if (PREFIX_LIST_IN (oa)) if (prefix_list_apply (PREFIX_LIST_IN (oa), &prefix) != PREFIX_PERMIT) { if (is_debug) zlog_debug ("Prefix was denied by prefix-list"); if (old) ospf6_route_remove (old, table); return; } } /* (5),(6),(7) the path preference is handled by the sorting in the routing table. Always install the path by substituting old route (if any). */ if (old) route = ospf6_route_copy (old); else route = ospf6_route_create (); route->type = type; route->prefix = prefix; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.router_bits = router_bits; route->path.options[0] = options[0]; route->path.options[1] = options[1]; route->path.options[2] = options[2]; route->path.prefix_options = prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTER; route->path.cost = abr_entry->path.cost + cost; for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) route->nexthop[i] = abr_entry->nexthop[i]; if (is_debug) zlog_debug ("Install route: %s", buf); ospf6_route_add (route, table); } void ospf6_abr_examin_brouter (u_int32_t router_id) { struct ospf6_lsa *lsa; struct ospf6_area *oa; struct listnode *node, *nnode; u_int16_t type; for (ALL_LIST_ELEMENTS (ospf6->area_list, node, nnode, oa)) { type = htons (OSPF6_LSTYPE_INTER_ROUTER); for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) ospf6_abr_examin_summary (lsa, oa); type = htons (OSPF6_LSTYPE_INTER_PREFIX); for (lsa = ospf6_lsdb_type_router_head (type, router_id, oa->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router_id, lsa)) ospf6_abr_examin_summary (lsa, oa); } } void ospf6_abr_reimport (struct ospf6_area *oa) { struct ospf6_lsa *lsa; u_int16_t type; type = htons (OSPF6_LSTYPE_INTER_ROUTER); for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; lsa = ospf6_lsdb_type_next (type, lsa)) ospf6_abr_examin_summary (lsa, oa); type = htons (OSPF6_LSTYPE_INTER_PREFIX); for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; lsa = ospf6_lsdb_type_next (type, lsa)) ospf6_abr_examin_summary (lsa, oa); } /* Display functions */ static char * ospf6_inter_area_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; if (lsa != NULL) { prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_prefix_in6_addr (&in6, &prefix_lsa->prefix); if (buf) { inet_ntop (AF_INET6, &in6, buf, buflen); sprintf (&buf[strlen(buf)], "/%d", prefix_lsa->prefix.prefix_length); } } return (buf); } static int ospf6_inter_area_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_prefix_lsa *prefix_lsa; char buf[INET6_ADDRSTRLEN]; prefix_lsa = (struct ospf6_inter_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (prefix_lsa), VNL); ospf6_prefix_options_printbuf (prefix_lsa->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); vty_out (vty, " Prefix: %s%s", ospf6_inter_area_prefix_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); return 0; } static char * ospf6_inter_area_router_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_inter_router_lsa *router_lsa; if (lsa != NULL) { router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (buf) inet_ntop (AF_INET, &router_lsa->router_id, buf, buflen); } return (buf); } static int ospf6_inter_area_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_inter_router_lsa *router_lsa; char buf[64]; router_lsa = (struct ospf6_inter_router_lsa *) OSPF6_LSA_HEADER_END (lsa->header); ospf6_options_printbuf (router_lsa->options, buf, sizeof (buf)); vty_out (vty, " Options: %s%s", buf, VNL); vty_out (vty, " Metric: %lu%s", (u_long) OSPF6_ABR_SUMMARY_METRIC (router_lsa), VNL); inet_ntop (AF_INET, &router_lsa->router_id, buf, sizeof (buf)); vty_out (vty, " Destination Router ID: %s%s", buf, VNL); return 0; } /* Debug commands */ DEFUN (debug_ospf6_abr, debug_ospf6_abr_cmd, "debug ospf6 abr", DEBUG_STR OSPF6_STR "Debug OSPFv3 ABR function\n" ) { OSPF6_DEBUG_ABR_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_abr, no_debug_ospf6_abr_cmd, "no debug ospf6 abr", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 ABR function\n" ) { OSPF6_DEBUG_ABR_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_abr (struct vty *vty) { if (IS_OSPF6_DEBUG_ABR) vty_out (vty, "debug ospf6 abr%s", VNL); return 0; } void install_element_ospf6_debug_abr (void) { install_element (ENABLE_NODE, &debug_ospf6_abr_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_abr_cmd); install_element (CONFIG_NODE, &debug_ospf6_abr_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_abr_cmd); } struct ospf6_lsa_handler inter_prefix_handler = { OSPF6_LSTYPE_INTER_PREFIX, "Inter-Prefix", "IAP", ospf6_inter_area_prefix_lsa_show, ospf6_inter_area_prefix_lsa_get_prefix_str, }; struct ospf6_lsa_handler inter_router_handler = { OSPF6_LSTYPE_INTER_ROUTER, "Inter-Router", "IAR", ospf6_inter_area_router_lsa_show, ospf6_inter_area_router_lsa_get_prefix_str, }; void ospf6_abr_init (void) { ospf6_install_lsa_handler (&inter_prefix_handler); ospf6_install_lsa_handler (&inter_router_handler); } quagga-0.99.24.1/ospf6d/ospf6_asbr.c0000644000175000017500000011205412476520570013650 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "prefix.h" #include "command.h" #include "vty.h" #include "routemap.h" #include "table.h" #include "plist.h" #include "thread.h" #include "linklist.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_asbr.h" #include "ospf6_intra.h" #include "ospf6_flood.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_asbr = 0; #define ZROUTE_NAME(x) zebra_route_string(x) /* AS External LSA origination */ static void ospf6_as_external_lsa_originate (struct ospf6_route *route) { char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *lsa; struct ospf6_external_info *info = route->route_option; struct ospf6_as_external_lsa *as_external_lsa; char buf[64]; caddr_t p; if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("Originate AS-External-LSA for %s", buf); } /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); p = (caddr_t) ((caddr_t) as_external_lsa + sizeof (struct ospf6_as_external_lsa)); /* Fill AS-External-LSA */ /* Metric type */ if (route->path.metric_type == 2) SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); else UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E); /* forwarding address */ if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) SET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); else UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F); /* external route tag */ UNSET_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T); /* Set metric */ OSPF6_ASBR_METRIC_SET (as_external_lsa, route->path.cost); /* prefixlen */ as_external_lsa->prefix.prefix_length = route->prefix.prefixlen; /* PrefixOptions */ as_external_lsa->prefix.prefix_options = route->path.prefix_options; /* don't use refer LS-type */ as_external_lsa->prefix.prefix_refer_lstype = htons (0); /* set Prefix */ memcpy (p, &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (route->prefix.prefixlen)); ospf6_prefix_apply_mask (&as_external_lsa->prefix); p += OSPF6_PREFIX_SPACE (route->prefix.prefixlen); /* Forwarding address */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) { memcpy (p, &info->forwarding, sizeof (struct in6_addr)); p += sizeof (struct in6_addr); } /* External Route Tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) { /* xxx */ } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_AS_EXTERNAL); lsa_header->id = route->path.origin.id; lsa_header->adv_router = ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, ospf6->lsdb); lsa_header->length = htons ((caddr_t) p - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_process (lsa, ospf6); } void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix asbr_id; struct ospf6_route *asbr_entry, *route; char buf[64]; int i; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Calculate AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore self-originated AS-External-LSA"); return; } if (OSPF6_ASBR_METRIC (external) == OSPF_LS_INFINITY) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with LSInfinity Metric"); return; } if (CHECK_FLAG(external->prefix.prefix_options, OSPF6_PREFIX_OPTION_NU)) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore LSA with NU bit set Metric"); return; } ospf6_linkstate_prefix (lsa->header->adv_router, htonl (0), &asbr_id); asbr_entry = ospf6_route_lookup (&asbr_id, ospf6->brouter_table); if (asbr_entry == NULL || ! CHECK_FLAG (asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&asbr_id, buf, sizeof (buf)); zlog_debug ("ASBR entry not found: %s", buf); } return; } route = ospf6_route_create (); route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; route->prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr (&route->prefix.u.prefix6, &external->prefix); route->path.area_id = asbr_entry->path.area_id; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.prefix_options = external->prefix.prefix_options; if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E)) { route->path.type = OSPF6_PATH_TYPE_EXTERNAL2; route->path.metric_type = 2; route->path.cost = asbr_entry->path.cost; route->path.cost_e2 = OSPF6_ASBR_METRIC (external); } else { route->path.type = OSPF6_PATH_TYPE_EXTERNAL1; route->path.metric_type = 1; route->path.cost = asbr_entry->path.cost + OSPF6_ASBR_METRIC (external); route->path.cost_e2 = 0; } for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &asbr_entry->nexthop[i]); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("AS-External route add: %s", buf); } ospf6_route_add (route, ospf6->route_table); } void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; struct prefix prefix; struct ospf6_route *route; char buf[64]; external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Withdraw AS-External route for %s", lsa->name); if (lsa->header->adv_router == ospf6->router_id) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) zlog_debug ("Ignore self-originated AS-External-LSA"); return; } memset (&prefix, 0, sizeof (struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, &external->prefix); route = ospf6_route_lookup (&prefix, ospf6->route_table); if (route == NULL) { if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&prefix, buf, sizeof (buf)); zlog_debug ("AS-External route %s not found", buf); } return; } for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); route = ospf6_route_next (route)) { if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.origin.type != lsa->header->type) continue; if (route->path.origin.id != lsa->header->id) continue; if (route->path.origin.adv_router != lsa->header->adv_router) continue; if (IS_OSPF6_DEBUG_EXAMIN (AS_EXTERNAL)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("AS-External route remove: %s", buf); } ospf6_route_remove (route, ospf6->route_table); } if (route != NULL) ospf6_route_unlock (route); } void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry) { struct ospf6_lsa *lsa; u_int16_t type; u_int32_t router; if (! CHECK_FLAG (asbr_entry->flag, OSPF6_ROUTE_BEST)) { char buf[16]; inet_ntop (AF_INET, &ADV_ROUTER_IN_PREFIX (&asbr_entry->prefix), buf, sizeof (buf)); zlog_info ("ignore non-best path: lsentry %s add", buf); return; } type = htons (OSPF6_LSTYPE_AS_EXTERNAL); router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) { if (! OSPF6_LSA_IS_MAXAGE (lsa)) ospf6_asbr_lsa_add (lsa); } } void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry) { struct ospf6_lsa *lsa; u_int16_t type; u_int32_t router; type = htons (OSPF6_LSTYPE_AS_EXTERNAL); router = ospf6_linkstate_prefix_adv_router (&asbr_entry->prefix); for (lsa = ospf6_lsdb_type_router_head (type, router, ospf6->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) ospf6_asbr_lsa_remove (lsa); } /* redistribute function */ static void ospf6_asbr_routemap_set (int type, const char *mapname) { if (ospf6->rmap[type].name) free (ospf6->rmap[type].name); ospf6->rmap[type].name = strdup (mapname); ospf6->rmap[type].map = route_map_lookup_by_name (mapname); } static void ospf6_asbr_routemap_unset (int type) { if (ospf6->rmap[type].name) free (ospf6->rmap[type].name); ospf6->rmap[type].name = NULL; ospf6->rmap[type].map = NULL; } static void ospf6_asbr_routemap_update (const char *mapname) { int type; if (ospf6 == NULL) return; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (ospf6->rmap[type].name) ospf6->rmap[type].map = route_map_lookup_by_name (ospf6->rmap[type].name); else ospf6->rmap[type].map = NULL; } } int ospf6_asbr_is_asbr (struct ospf6 *o) { return o->external_table->count; } static void ospf6_asbr_redistribute_set (int type) { ospf6_zebra_redistribute (type); } static void ospf6_asbr_redistribute_unset (int type) { struct ospf6_route *route; struct ospf6_external_info *info; ospf6_zebra_no_redistribute (type); for (route = ospf6_route_head (ospf6->external_table); route; route = ospf6_route_next (route)) { info = route->route_option; if (info->type != type) continue; ospf6_asbr_redistribute_remove (info->type, route->nexthop[0].ifindex, &route->prefix); } ospf6_asbr_routemap_unset (type); } void ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop) { int ret; struct ospf6_route troute; struct ospf6_external_info tinfo; struct ospf6_route *route, *match; struct ospf6_external_info *info; struct prefix prefix_id; struct route_node *node; char pbuf[64], ibuf[16]; struct listnode *lnode, *lnnode; struct ospf6_area *oa; if (! ospf6_zebra_is_redistribute (type)) return; if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("Redistribute %s (%s)", pbuf, ZROUTE_NAME (type)); } /* if route-map was specified but not found, do not advertise */ if (ospf6->rmap[type].name) { if (ospf6->rmap[type].map == NULL) ospf6_asbr_routemap_update (NULL); if (ospf6->rmap[type].map == NULL) { zlog_warn ("route-map \"%s\" not found, suppress redistributing", ospf6->rmap[type].name); return; } } /* apply route-map */ if (ospf6->rmap[type].map) { memset (&troute, 0, sizeof (troute)); memset (&tinfo, 0, sizeof (tinfo)); troute.route_option = &tinfo; tinfo.ifindex = ifindex; ret = route_map_apply (ospf6->rmap[type].map, prefix, RMAP_OSPF6, &troute); if (ret == RMAP_DENYMATCH) { if (IS_OSPF6_DEBUG_ASBR) zlog_debug ("Denied by route-map \"%s\"", ospf6->rmap[type].name); return; } } match = ospf6_route_lookup (prefix, ospf6->external_table); if (match) { info = match->route_option; /* copy result of route-map */ if (ospf6->rmap[type].map) { if (troute.path.metric_type) match->path.metric_type = troute.path.metric_type; if (troute.path.cost) match->path.cost = troute.path.cost; if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) memcpy (&info->forwarding, &tinfo.forwarding, sizeof (struct in6_addr)); } info->type = type; match->nexthop[0].ifindex = ifindex; if (nexthop_num && nexthop) memcpy (&match->nexthop[0].address, nexthop, sizeof (struct in6_addr)); /* create/update binding in external_id_table */ prefix_id.family = AF_INET; prefix_id.prefixlen = 32; prefix_id.u.prefix4.s_addr = htonl (info->id); node = route_node_get (ospf6->external_id_table, &prefix_id); node->info = match; if (IS_OSPF6_DEBUG_ASBR) { inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); zlog_debug ("Advertise as AS-External Id:%s", ibuf); } match->path.origin.id = htonl (info->id); ospf6_as_external_lsa_originate (match); return; } /* create new entry */ route = ospf6_route_create (); route->type = OSPF6_DEST_TYPE_NETWORK; memcpy (&route->prefix, prefix, sizeof (struct prefix)); info = (struct ospf6_external_info *) XCALLOC (MTYPE_OSPF6_EXTERNAL_INFO, sizeof (struct ospf6_external_info)); route->route_option = info; info->id = ospf6->external_id++; /* copy result of route-map */ if (ospf6->rmap[type].map) { if (troute.path.metric_type) route->path.metric_type = troute.path.metric_type; if (troute.path.cost) route->path.cost = troute.path.cost; if (! IN6_IS_ADDR_UNSPECIFIED (&tinfo.forwarding)) memcpy (&info->forwarding, &tinfo.forwarding, sizeof (struct in6_addr)); } info->type = type; route->nexthop[0].ifindex = ifindex; if (nexthop_num && nexthop) memcpy (&route->nexthop[0].address, nexthop, sizeof (struct in6_addr)); /* create/update binding in external_id_table */ prefix_id.family = AF_INET; prefix_id.prefixlen = 32; prefix_id.u.prefix4.s_addr = htonl (info->id); node = route_node_get (ospf6->external_id_table, &prefix_id); node->info = route; route = ospf6_route_add (route, ospf6->external_table); route->route_option = info; if (IS_OSPF6_DEBUG_ASBR) { inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); zlog_debug ("Advertise as AS-External Id:%s", ibuf); } route->path.origin.id = htonl (info->id); ospf6_as_external_lsa_originate (route); /* Router-Bit (ASBR Flag) may have to be updated */ for (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) OSPF6_ROUTER_LSA_SCHEDULE (oa); } void ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix) { struct ospf6_route *match; struct ospf6_external_info *info = NULL; struct route_node *node; struct ospf6_lsa *lsa; struct prefix prefix_id; char pbuf[64], ibuf[16]; struct listnode *lnode, *lnnode; struct ospf6_area *oa; match = ospf6_route_lookup (prefix, ospf6->external_table); if (match == NULL) { if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("No such route %s to withdraw", pbuf); } return; } info = match->route_option; assert (info); if (info->type != type) { if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); zlog_debug ("Original protocol mismatch: %s", pbuf); } return; } if (IS_OSPF6_DEBUG_ASBR) { prefix2str (prefix, pbuf, sizeof (pbuf)); inet_ntop (AF_INET, &prefix_id.u.prefix4, ibuf, sizeof (ibuf)); zlog_debug ("Withdraw %s (AS-External Id:%s)", pbuf, ibuf); } lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_AS_EXTERNAL), htonl (info->id), ospf6->router_id, ospf6->lsdb); if (lsa) ospf6_lsa_purge (lsa); /* remove binding in external_id_table */ prefix_id.family = AF_INET; prefix_id.prefixlen = 32; prefix_id.u.prefix4.s_addr = htonl (info->id); node = route_node_lookup (ospf6->external_id_table, &prefix_id); assert (node); node->info = NULL; route_unlock_node (node); ospf6_route_remove (match, ospf6->external_table); XFREE (MTYPE_OSPF6_EXTERNAL_INFO, info); /* Router-Bit (ASBR Flag) may have to be updated */ for (ALL_LIST_ELEMENTS (ospf6->area_list, lnode, lnnode, oa)) OSPF6_ROUTER_LSA_SCHEDULE (oa); } DEFUN (ospf6_redistribute, ospf6_redistribute_cmd, "redistribute " QUAGGA_REDIST_STR_OSPF6D, "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } DEFUN (ospf6_redistribute_routemap, ospf6_redistribute_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_OSPF6D " route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D "Route map reference\n" "Route map name\n" ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; ospf6_asbr_redistribute_unset (type); ospf6_asbr_routemap_set (type, argv[1]); ospf6_asbr_redistribute_set (type); return CMD_SUCCESS; } DEFUN (no_ospf6_redistribute, no_ospf6_redistribute_cmd, "no redistribute " QUAGGA_REDIST_STR_OSPF6D, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_OSPF6D ) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_OSPF6) return CMD_WARNING; ospf6_asbr_redistribute_unset (type); return CMD_SUCCESS; } int ospf6_redistribute_config_write (struct vty *vty) { int type; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_OSPF6) continue; if (! ospf6_zebra_is_redistribute (type)) continue; if (ospf6->rmap[type].name) vty_out (vty, " redistribute %s route-map %s%s", ZROUTE_NAME (type), ospf6->rmap[type].name, VNL); else vty_out (vty, " redistribute %s%s", ZROUTE_NAME (type), VNL); } return 0; } static void ospf6_redistribute_show_config (struct vty *vty) { int type; int nroute[ZEBRA_ROUTE_MAX]; int total; struct ospf6_route *route; struct ospf6_external_info *info; total = 0; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) nroute[type] = 0; for (route = ospf6_route_head (ospf6->external_table); route; route = ospf6_route_next (route)) { info = route->route_option; nroute[info->type]++; total++; } vty_out (vty, "Redistributing External Routes from:%s", VNL); for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_OSPF6) continue; if (! ospf6_zebra_is_redistribute (type)) continue; if (ospf6->rmap[type].name) vty_out (vty, " %d: %s with route-map \"%s\"%s%s", nroute[type], ZROUTE_NAME (type), ospf6->rmap[type].name, (ospf6->rmap[type].map ? "" : " (not found !)"), VNL); else vty_out (vty, " %d: %s%s", nroute[type], ZROUTE_NAME (type), VNL); } vty_out (vty, "Total %d routes%s", total, VNL); } /* Routemap Functions */ static route_map_result_t ospf6_routemap_rule_match_address_prefixlist (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type != RMAP_OSPF6) return RMAP_NOMATCH; plist = prefix_list_lookup (AFI_IP6, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } static void * ospf6_routemap_rule_match_address_prefixlist_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void ospf6_routemap_rule_match_address_prefixlist_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = { "ipv6 address prefix-list", ospf6_routemap_rule_match_address_prefixlist, ospf6_routemap_rule_match_address_prefixlist_compile, ospf6_routemap_rule_match_address_prefixlist_free, }; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t ospf6_routemap_rule_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct interface *ifp; struct ospf6_external_info *ei; if (type == RMAP_OSPF6) { ei = ((struct ospf6_route *) object)->route_option; ifp = if_lookup_by_name ((char *)rule); if (ifp != NULL && ei->ifindex == ifp->ifindex) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `interface' match statement. `arg' should be interface name. */ static void * ospf6_routemap_rule_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `interface' value. */ static void ospf6_routemap_rule_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for interface matching. */ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = { "interface", ospf6_routemap_rule_match_interface, ospf6_routemap_rule_match_interface_compile, ospf6_routemap_rule_match_interface_free }; static route_map_result_t ospf6_routemap_rule_set_metric_type (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { char *metric_type = rule; struct ospf6_route *route = object; if (type != RMAP_OSPF6) return RMAP_OKAY; if (strcmp (metric_type, "type-2") == 0) route->path.metric_type = 2; else route->path.metric_type = 1; return RMAP_OKAY; } static void * ospf6_routemap_rule_set_metric_type_compile (const char *arg) { if (strcmp (arg, "type-2") && strcmp (arg, "type-1")) return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void ospf6_routemap_rule_set_metric_type_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = { "metric-type", ospf6_routemap_rule_set_metric_type, ospf6_routemap_rule_set_metric_type_compile, ospf6_routemap_rule_set_metric_type_free, }; static route_map_result_t ospf6_routemap_rule_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { char *metric = rule; struct ospf6_route *route = object; if (type != RMAP_OSPF6) return RMAP_OKAY; route->path.cost = atoi (metric); return RMAP_OKAY; } static void * ospf6_routemap_rule_set_metric_compile (const char *arg) { u_int32_t metric; char *endp; metric = strtoul (arg, &endp, 0); if (metric > OSPF_LS_INFINITY || *endp != '\0') return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void ospf6_routemap_rule_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = { "metric", ospf6_routemap_rule_set_metric, ospf6_routemap_rule_set_metric_compile, ospf6_routemap_rule_set_metric_free, }; static route_map_result_t ospf6_routemap_rule_set_forwarding (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { char *forwarding = rule; struct ospf6_route *route = object; struct ospf6_external_info *info = route->route_option; if (type != RMAP_OSPF6) return RMAP_OKAY; if (inet_pton (AF_INET6, forwarding, &info->forwarding) != 1) { memset (&info->forwarding, 0, sizeof (struct in6_addr)); return RMAP_ERROR; } return RMAP_OKAY; } static void * ospf6_routemap_rule_set_forwarding_compile (const char *arg) { struct in6_addr a; if (inet_pton (AF_INET6, arg, &a) != 1) return NULL; return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void ospf6_routemap_rule_set_forwarding_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = { "forwarding-address", ospf6_routemap_rule_set_forwarding, ospf6_routemap_rule_set_forwarding_compile, ospf6_routemap_rule_set_forwarding_free, }; static int route_map_command_status (struct vty *vty, int ret) { if (! ret) return CMD_SUCCESS; switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VNL); break; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VNL); break; default: vty_out (vty, "route-map add set failed.%s", VNL); break; } return CMD_WARNING; } /* add "match address" */ DEFUN (ospf6_routemap_match_address_prefixlist, ospf6_routemap_match_address_prefixlist_cmd, "match ipv6 address prefix-list WORD", "Match values\n" IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") { int ret = route_map_add_match ((struct route_map_index *) vty->index, "ipv6 address prefix-list", argv[0]); return route_map_command_status (vty, ret); } /* delete "match address" */ DEFUN (ospf6_routemap_no_match_address_prefixlist, ospf6_routemap_no_match_address_prefixlist_cmd, "no match ipv6 address prefix-list WORD", NO_STR "Match values\n" IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IPv6 prefix-list name\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "ipv6 address prefix-list", argv[0]); return route_map_command_status (vty, ret); } /* "match interface" */ DEFUN (ospf6_routemap_match_interface, ospf6_routemap_match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return route_map_add_match ((struct route_map_index *) vty->index, "interface", argv[0]); } /* "no match interface WORD" */ DEFUN (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_cmd, "no match interface", MATCH_STR NO_STR "Match first hop interface of route\n") { int ret = route_map_delete_match ((struct route_map_index *) vty->index, "interface", (argc == 0) ? NULL : argv[0]); return route_map_command_status (vty, ret); } ALIAS (ospf6_routemap_no_match_interface, ospf6_routemap_no_match_interface_val_cmd, "no match interface WORD", MATCH_STR NO_STR "Match first hop interface of route\n" "Interface name\n") /* add "set metric-type" */ DEFUN (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, "set metric-type (type-1|type-2)", "Set value\n" "Type of metric\n" "OSPF6 external type 1 metric\n" "OSPF6 external type 2 metric\n") { int ret = route_map_add_set ((struct route_map_index *) vty->index, "metric-type", argv[0]); return route_map_command_status (vty, ret); } /* delete "set metric-type" */ DEFUN (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd, "no set metric-type (type-1|type-2)", NO_STR "Set value\n" "Type of metric\n" "OSPF6 external type 1 metric\n" "OSPF6 external type 2 metric\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "metric-type", argv[0]); return route_map_command_status (vty, ret); } /* add "set metric" */ DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", "Set value\n" "Metric value\n" "Metric value\n") { int ret = route_map_add_set ((struct route_map_index *) vty->index, "metric", argv[0]); return route_map_command_status (vty, ret); } /* delete "set metric" */ DEFUN (no_set_metric, no_set_metric_cmd, "no set metric <0-4294967295>", NO_STR "Set value\n" "Metric\n" "METRIC value\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "metric", argv[0]); return route_map_command_status (vty, ret); } /* add "set forwarding-address" */ DEFUN (ospf6_routemap_set_forwarding, ospf6_routemap_set_forwarding_cmd, "set forwarding-address X:X::X:X", "Set value\n" "Forwarding Address\n" "IPv6 Address\n") { int ret = route_map_add_set ((struct route_map_index *) vty->index, "forwarding-address", argv[0]); return route_map_command_status (vty, ret); } /* delete "set forwarding-address" */ DEFUN (ospf6_routemap_no_set_forwarding, ospf6_routemap_no_set_forwarding_cmd, "no set forwarding-address X:X::X:X", NO_STR "Set value\n" "Forwarding Address\n" "IPv6 Address\n") { int ret = route_map_delete_set ((struct route_map_index *) vty->index, "forwarding-address", argv[0]); return route_map_command_status (vty, ret); } static void ospf6_routemap_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (ospf6_asbr_routemap_update); route_map_delete_hook (ospf6_asbr_routemap_update); route_map_install_match (&ospf6_routemap_rule_match_address_prefixlist_cmd); route_map_install_match (&ospf6_routemap_rule_match_interface_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_type_cmd); route_map_install_set (&ospf6_routemap_rule_set_metric_cmd); route_map_install_set (&ospf6_routemap_rule_set_forwarding_cmd); /* Match address prefix-list */ install_element (RMAP_NODE, &ospf6_routemap_match_address_prefixlist_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_address_prefixlist_cmd); /* Match interface */ install_element (RMAP_NODE, &ospf6_routemap_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_match_interface_val_cmd); /* ASE Metric Type (e.g. Type-1/Type-2) */ install_element (RMAP_NODE, &ospf6_routemap_set_metric_type_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_metric_type_cmd); /* ASE Metric */ install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); /* ASE Metric */ install_element (RMAP_NODE, &ospf6_routemap_set_forwarding_cmd); install_element (RMAP_NODE, &ospf6_routemap_no_set_forwarding_cmd); } /* Display functions */ static char * ospf6_as_external_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_as_external_lsa *external; struct in6_addr in6; int prefix_length = 0; if (lsa) { external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (pos == 0) { ospf6_prefix_in6_addr (&in6, &external->prefix); prefix_length = external->prefix.prefix_length; } else { in6 = *((struct in6_addr *) ((caddr_t) external + sizeof (struct ospf6_as_external_lsa) + OSPF6_PREFIX_SPACE (external->prefix.prefix_length))); } if (buf) { inet_ntop (AF_INET6, &in6, buf, buflen); if (prefix_length) sprintf (&buf[strlen(buf)], "/%d", prefix_length); } } return (buf); } static int ospf6_as_external_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { struct ospf6_as_external_lsa *external; char buf[64]; assert (lsa->header); external = (struct ospf6_as_external_lsa *) OSPF6_LSA_HEADER_END (lsa->header); /* bits */ snprintf (buf, sizeof (buf), "%c%c%c", (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_E) ? 'E' : '-'), (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F) ? 'F' : '-'), (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_T) ? 'T' : '-')); vty_out (vty, " Bits: %s%s", buf, VNL); vty_out (vty, " Metric: %5lu%s", (u_long) OSPF6_ASBR_METRIC (external), VNL); ospf6_prefix_options_printbuf (external->prefix.prefix_options, buf, sizeof (buf)); vty_out (vty, " Prefix Options: %s%s", buf, VNL); vty_out (vty, " Referenced LSType: %d%s", ntohs (external->prefix.prefix_refer_lstype), VNL); vty_out (vty, " Prefix: %s%s", ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 0), VNL); /* Forwarding-Address */ if (CHECK_FLAG (external->bits_metric, OSPF6_ASBR_BIT_F)) { vty_out (vty, " Forwarding-Address: %s%s", ospf6_as_external_lsa_get_prefix_str (lsa, buf, sizeof(buf), 1), VNL); } return 0; } static void ospf6_asbr_external_route_show (struct vty *vty, struct ospf6_route *route) { struct ospf6_external_info *info = route->route_option; char prefix[64], id[16], forwarding[64]; u_int32_t tmp_id; prefix2str (&route->prefix, prefix, sizeof (prefix)); tmp_id = ntohl (info->id); inet_ntop (AF_INET, &tmp_id, id, sizeof (id)); if (! IN6_IS_ADDR_UNSPECIFIED (&info->forwarding)) inet_ntop (AF_INET6, &info->forwarding, forwarding, sizeof (forwarding)); else snprintf (forwarding, sizeof (forwarding), ":: (ifindex %d)", route->nexthop[0].ifindex); vty_out (vty, "%c %-32s %-15s type-%d %5lu %s%s", zebra_route_char(info->type), prefix, id, route->path.metric_type, (u_long) (route->path.metric_type == 2 ? route->path.cost_e2 : route->path.cost), forwarding, VNL); } DEFUN (show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd, "show ipv6 ospf6 redistribute", SHOW_STR IP6_STR OSPF6_STR "redistributing External information\n" ) { struct ospf6_route *route; ospf6_redistribute_show_config (vty); for (route = ospf6_route_head (ospf6->external_table); route; route = ospf6_route_next (route)) ospf6_asbr_external_route_show (vty, route); return CMD_SUCCESS; } struct ospf6_lsa_handler as_external_handler = { OSPF6_LSTYPE_AS_EXTERNAL, "AS-External", "ASE", ospf6_as_external_lsa_show, ospf6_as_external_lsa_get_prefix_str }; void ospf6_asbr_init (void) { ospf6_routemap_init (); ospf6_install_lsa_handler (&as_external_handler); install_element (VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_cmd); install_element (OSPF6_NODE, &ospf6_redistribute_routemap_cmd); install_element (OSPF6_NODE, &no_ospf6_redistribute_cmd); } void ospf6_asbr_redistribute_reset (void) { int type; for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { if (type == ZEBRA_ROUTE_OSPF6) continue; if (ospf6_zebra_is_redistribute (type)) ospf6_asbr_redistribute_unset(type); } } void ospf6_asbr_terminate (void) { route_map_finish (); } DEFUN (debug_ospf6_asbr, debug_ospf6_asbr_cmd, "debug ospf6 asbr", DEBUG_STR OSPF6_STR "Debug OSPFv3 ASBR function\n" ) { OSPF6_DEBUG_ASBR_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_asbr, no_debug_ospf6_asbr_cmd, "no debug ospf6 asbr", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 ASBR function\n" ) { OSPF6_DEBUG_ASBR_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_asbr (struct vty *vty) { if (IS_OSPF6_DEBUG_ASBR) vty_out (vty, "debug ospf6 asbr%s", VNL); return 0; } void install_element_ospf6_debug_asbr () { install_element (ENABLE_NODE, &debug_ospf6_asbr_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_asbr_cmd); install_element (CONFIG_NODE, &debug_ospf6_asbr_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_asbr_cmd); } quagga-0.99.24.1/ospf6d/ospf6_proto.c0000644000175000017500000000474112476520570014067 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "ospf6_proto.h" void ospf6_prefix_apply_mask (struct ospf6_prefix *op) { u_char *pnt, mask; int index, offset; pnt = (u_char *)((caddr_t) op + sizeof (struct ospf6_prefix)); index = op->prefix_length / 8; offset = op->prefix_length % 8; mask = 0xff << (8 - offset); if (index > 16) { zlog_warn ("Prefix length too long: %d", op->prefix_length); return; } /* nonzero mask means no check for this byte because if it contains * prefix bits it must be there for us to write */ if (mask) pnt[index++] &= mask; while (index < OSPF6_PREFIX_SPACE (op->prefix_length)) pnt[index++] = 0; } void ospf6_prefix_options_printbuf (u_int8_t prefix_options, char *buf, int size) { snprintf (buf, size, "xxx"); } void ospf6_capability_printbuf (char capability, char *buf, int size) { char w, v, e, b; w = (capability & OSPF6_ROUTER_BIT_W ? 'W' : '-'); v = (capability & OSPF6_ROUTER_BIT_V ? 'V' : '-'); e = (capability & OSPF6_ROUTER_BIT_E ? 'E' : '-'); b = (capability & OSPF6_ROUTER_BIT_B ? 'B' : '-'); snprintf (buf, size, "----%c%c%c%c", w, v, e, b); } void ospf6_options_printbuf (u_char *options, char *buf, int size) { const char *dc, *r, *n, *mc, *e, *v6; dc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_DC) ? "DC" : "--"); r = (OSPF6_OPT_ISSET (options, OSPF6_OPT_R) ? "R" : "-" ); n = (OSPF6_OPT_ISSET (options, OSPF6_OPT_N) ? "N" : "-" ); mc = (OSPF6_OPT_ISSET (options, OSPF6_OPT_MC) ? "MC" : "--"); e = (OSPF6_OPT_ISSET (options, OSPF6_OPT_E) ? "E" : "-" ); v6 = (OSPF6_OPT_ISSET (options, OSPF6_OPT_V6) ? "V6" : "--"); snprintf (buf, size, "%s|%s|%s|%s|%s|%s", dc, r, n, mc, e, v6); } quagga-0.99.24.1/ospf6d/ospf6_spf.c0000644000175000017500000006361712476520570013523 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* Shortest Path First calculation for OSPFv3 */ #include #include "log.h" #include "memory.h" #include "command.h" #include "vty.h" #include "prefix.h" #include "pqueue.h" #include "linklist.h" #include "thread.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_area.h" #include "ospf6_spf.h" #include "ospf6_intra.h" #include "ospf6_interface.h" #include "ospf6d.h" #include "ospf6_abr.h" unsigned char conf_debug_ospf6_spf = 0; static int ospf6_vertex_cmp (void *a, void *b) { struct ospf6_vertex *va = (struct ospf6_vertex *) a; struct ospf6_vertex *vb = (struct ospf6_vertex *) b; /* ascending order */ if (va->cost != vb->cost) return (va->cost - vb->cost); return (va->hops - vb->hops); } static int ospf6_vertex_id_cmp (void *a, void *b) { struct ospf6_vertex *va = (struct ospf6_vertex *) a; struct ospf6_vertex *vb = (struct ospf6_vertex *) b; int ret = 0; ret = ntohl (ospf6_linkstate_prefix_adv_router (&va->vertex_id)) - ntohl (ospf6_linkstate_prefix_adv_router (&vb->vertex_id)); if (ret) return ret; ret = ntohl (ospf6_linkstate_prefix_id (&va->vertex_id)) - ntohl (ospf6_linkstate_prefix_id (&vb->vertex_id)); return ret; } static struct ospf6_vertex * ospf6_vertex_create (struct ospf6_lsa *lsa) { struct ospf6_vertex *v; int i; v = (struct ospf6_vertex *) XMALLOC (MTYPE_OSPF6_VERTEX, sizeof (struct ospf6_vertex)); /* type */ if (ntohs (lsa->header->type) == OSPF6_LSTYPE_ROUTER) v->type = OSPF6_VERTEX_TYPE_ROUTER; else if (ntohs (lsa->header->type) == OSPF6_LSTYPE_NETWORK) v->type = OSPF6_VERTEX_TYPE_NETWORK; else assert (0); /* vertex_id */ ospf6_linkstate_prefix (lsa->header->adv_router, lsa->header->id, &v->vertex_id); /* name */ ospf6_linkstate_prefix2str (&v->vertex_id, v->name, sizeof (v->name)); /* Associated LSA */ v->lsa = lsa; /* capability bits + options */ v->capability = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header)); v->options[0] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 1); v->options[1] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 2); v->options[2] = *(u_char *)(OSPF6_LSA_HEADER_END (lsa->header) + 3); for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_clear (&v->nexthop[i]); v->parent = NULL; v->child_list = list_new (); v->child_list->cmp = ospf6_vertex_id_cmp; return v; } static void ospf6_vertex_delete (struct ospf6_vertex *v) { list_delete (v->child_list); XFREE (MTYPE_OSPF6_VERTEX, v); } static struct ospf6_lsa * ospf6_lsdesc_lsa (caddr_t lsdesc, struct ospf6_vertex *v) { struct ospf6_lsa *lsa; u_int16_t type = 0; u_int32_t id = 0, adv_router = 0; if (VERTEX_IS_TYPE (NETWORK, v)) { type = htons (OSPF6_LSTYPE_ROUTER); id = htonl (0); adv_router = NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc); } else { if (ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) { type = htons (OSPF6_LSTYPE_ROUTER); id = htonl (0); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc); } else if (ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, lsdesc)) { type = htons (OSPF6_LSTYPE_NETWORK); id = htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)); adv_router = ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc); } } lsa = ospf6_lsdb_lookup (type, id, adv_router, v->area->lsdb); if (IS_OSPF6_DEBUG_SPF (PROCESS)) { char ibuf[16], abuf[16]; inet_ntop (AF_INET, &id, ibuf, sizeof (ibuf)); inet_ntop (AF_INET, &adv_router, abuf, sizeof (abuf)); if (lsa) zlog_debug (" Link to: %s", lsa->name); else zlog_debug (" Link to: [%s Id:%s Adv:%s] No LSA", ospf6_lstype_name (type), ibuf, abuf); } return lsa; } static char * ospf6_lsdesc_backlink (struct ospf6_lsa *lsa, caddr_t lsdesc, struct ospf6_vertex *v) { caddr_t backlink, found = NULL; int size; size = (OSPF6_LSA_IS_TYPE (ROUTER, lsa) ? sizeof (struct ospf6_router_lsdesc) : sizeof (struct ospf6_network_lsdesc)); for (backlink = OSPF6_LSA_HEADER_END (lsa->header) + 4; backlink + size <= OSPF6_LSA_END (lsa->header); backlink += size) { assert (! (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && VERTEX_IS_TYPE (NETWORK, v))); if (OSPF6_LSA_IS_TYPE (NETWORK, lsa) && NETWORK_LSDESC_GET_NBR_ROUTERID (backlink) == v->lsa->header->adv_router) found = backlink; else if (VERTEX_IS_TYPE (NETWORK, v) && ROUTER_LSDESC_IS_TYPE (TRANSIT_NETWORK, backlink) && ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) == v->lsa->header->adv_router && ROUTER_LSDESC_GET_NBR_IFID (backlink) == ntohl (v->lsa->header->id)) found = backlink; else { if (! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, backlink) || ! ROUTER_LSDESC_IS_TYPE (POINTTOPOINT, lsdesc)) continue; if (ROUTER_LSDESC_GET_NBR_IFID (backlink) != ROUTER_LSDESC_GET_IFID (lsdesc) || ROUTER_LSDESC_GET_NBR_IFID (lsdesc) != ROUTER_LSDESC_GET_IFID (backlink)) continue; if (ROUTER_LSDESC_GET_NBR_ROUTERID (backlink) != v->lsa->header->adv_router || ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc) != lsa->header->adv_router) continue; found = backlink; } } if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" Backlink %s", (found ? "OK" : "FAIL")); return found; } static void ospf6_nexthop_calc (struct ospf6_vertex *w, struct ospf6_vertex *v, caddr_t lsdesc) { int i, ifindex; struct ospf6_interface *oi; u_int16_t type; u_int32_t adv_router; struct ospf6_lsa *lsa; struct ospf6_link_lsa *link_lsa; char buf[64]; assert (VERTEX_IS_TYPE (ROUTER, w)); ifindex = (VERTEX_IS_TYPE (NETWORK, v) ? v->nexthop[0].ifindex : ROUTER_LSDESC_GET_IFID (lsdesc)); oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("Can't find interface in SPF: ifindex %d", ifindex); return; } type = htons (OSPF6_LSTYPE_LINK); adv_router = (VERTEX_IS_TYPE (NETWORK, v) ? NETWORK_LSDESC_GET_NBR_ROUTERID (lsdesc) : ROUTER_LSDESC_GET_NBR_ROUTERID (lsdesc)); i = 0; for (lsa = ospf6_lsdb_type_router_head (type, adv_router, oi->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) { if (VERTEX_IS_TYPE (ROUTER, v) && htonl (ROUTER_LSDESC_GET_NBR_IFID (lsdesc)) != lsa->header->id) continue; link_lsa = (struct ospf6_link_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (IS_OSPF6_DEBUG_SPF (PROCESS)) { inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf)); zlog_debug (" nexthop %s from %s", buf, lsa->name); } if (i < OSPF6_MULTI_PATH_LIMIT) { memcpy (&w->nexthop[i].address, &link_lsa->linklocal_addr, sizeof (struct in6_addr)); w->nexthop[i].ifindex = ifindex; i++; } } if (i == 0 && IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("No nexthop for %s found", w->name); } static int ospf6_spf_install (struct ospf6_vertex *v, struct ospf6_route_table *result_table) { struct ospf6_route *route; int i, j; struct ospf6_vertex *prev; if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF install %s hops %d cost %d", v->name, v->hops, v->cost); route = ospf6_route_lookup (&v->vertex_id, result_table); if (route && route->path.cost < v->cost) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" already installed with lower cost (%d), ignore", route->path.cost); ospf6_vertex_delete (v); return -1; } else if (route && route->path.cost == v->cost) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" another path found, merge"); for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { for (j = 0; j < OSPF6_MULTI_PATH_LIMIT; j++) { if (ospf6_nexthop_is_set (&route->nexthop[j])) { if (ospf6_nexthop_is_same (&route->nexthop[j], &v->nexthop[i])) break; else continue; } ospf6_nexthop_copy (&route->nexthop[j], &v->nexthop[i]); break; } } prev = (struct ospf6_vertex *) route->route_option; assert (prev->hops <= v->hops); ospf6_vertex_delete (v); return -1; } /* There should be no case where candidate being installed (variable "v") is closer than the one in the SPF tree (variable "route"). In the case something has gone wrong with the behavior of Priority-Queue. */ /* the case where the route exists already is handled and returned up to here. */ assert (route == NULL); route = ospf6_route_create (); memcpy (&route->prefix, &v->vertex_id, sizeof (struct prefix)); route->type = OSPF6_DEST_TYPE_LINKSTATE; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.origin.type = v->lsa->header->type; route->path.origin.id = v->lsa->header->id; route->path.origin.adv_router = v->lsa->header->adv_router; route->path.metric_type = 1; route->path.cost = v->cost; route->path.cost_e2 = v->hops; route->path.router_bits = v->capability; route->path.options[0] = v->options[0]; route->path.options[1] = v->options[1]; route->path.options[2] = v->options[2]; for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &v->nexthop[i]); if (v->parent) listnode_add_sort (v->parent->child_list, v); route->route_option = v; ospf6_route_add (route, result_table); return 0; } void ospf6_spf_table_finish (struct ospf6_route_table *result_table) { struct ospf6_route *route; struct ospf6_vertex *v; for (route = ospf6_route_head (result_table); route; route = ospf6_route_next (route)) { v = (struct ospf6_vertex *) route->route_option; ospf6_vertex_delete (v); ospf6_route_remove (route, result_table); } } static const char *ospf6_spf_reason_str[] = { "R+", "R-", "N+", "N-", "L+", "L-", "R*", "N*", }; void ospf6_spf_reason_string (unsigned int reason, char *buf, int size) { size_t bit; int len = 0; if (!buf) return; for (bit = 0; bit <= (sizeof(ospf6_spf_reason_str) / sizeof(char *)); bit++) { if ((reason & (1 << bit)) && (len < size)) { len += snprintf((buf + len), (size - len), "%s%s", (len > 0) ? ", " : "", ospf6_spf_reason_str[bit]); } } } /* RFC2328 16.1. Calculating the shortest-path tree for an area */ /* RFC2740 3.8.1. Calculating the shortest path tree for an area */ void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa) { struct pqueue *candidate_list; struct ospf6_vertex *root, *v, *w; int i; int size; caddr_t lsdesc; struct ospf6_lsa *lsa; ospf6_spf_table_finish (result_table); /* Install the calculating router itself as the root of the SPF tree */ /* construct root vertex */ lsa = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_ROUTER), htonl (0), router_id, oa->lsdb); if (lsa == NULL) return; /* initialize */ candidate_list = pqueue_create (); candidate_list->cmp = ospf6_vertex_cmp; root = ospf6_vertex_create (lsa); root->area = oa; root->cost = 0; root->hops = 0; root->nexthop[0].ifindex = 0; /* loopbak I/F is better ... */ inet_pton (AF_INET6, "::1", &root->nexthop[0].address); /* Actually insert root to the candidate-list as the only candidate */ pqueue_enqueue (root, candidate_list); /* Iterate until candidate-list becomes empty */ while (candidate_list->size) { /* get closest candidate from priority queue */ v = pqueue_dequeue (candidate_list); /* installing may result in merging or rejecting of the vertex */ if (ospf6_spf_install (v, result_table) < 0) continue; /* Skip overloaded routers */ if ((OSPF6_LSA_IS_TYPE (ROUTER, v->lsa) && ospf6_router_is_stub_router (v->lsa))) continue; /* For each LS description in the just-added vertex V's LSA */ size = (VERTEX_IS_TYPE (ROUTER, v) ? sizeof (struct ospf6_router_lsdesc) : sizeof (struct ospf6_network_lsdesc)); for (lsdesc = OSPF6_LSA_HEADER_END (v->lsa->header) + 4; lsdesc + size <= OSPF6_LSA_END (v->lsa->header); lsdesc += size) { lsa = ospf6_lsdesc_lsa (lsdesc, v); if (lsa == NULL) continue; if (! ospf6_lsdesc_backlink (lsa, lsdesc, v)) continue; w = ospf6_vertex_create (lsa); w->area = oa; w->parent = v; if (VERTEX_IS_TYPE (ROUTER, v)) { w->cost = v->cost + ROUTER_LSDESC_GET_METRIC (lsdesc); w->hops = v->hops + (VERTEX_IS_TYPE (NETWORK, w) ? 0 : 1); } else /* NETWORK */ { w->cost = v->cost; w->hops = v->hops + 1; } /* nexthop calculation */ if (w->hops == 0) w->nexthop[0].ifindex = ROUTER_LSDESC_GET_IFID (lsdesc); else if (w->hops == 1 && v->hops == 0) ospf6_nexthop_calc (w, v, lsdesc); else { for (i = 0; ospf6_nexthop_is_set (&v->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&w->nexthop[i], &v->nexthop[i]); } /* add new candidate to the candidate_list */ if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug (" New candidate: %s hops %d cost %d", w->name, w->hops, w->cost); pqueue_enqueue (w, candidate_list); } } pqueue_delete (candidate_list); oa->spf_calculation++; } static void ospf6_spf_log_database (struct ospf6_area *oa) { char *p, *end, buffer[256]; struct listnode *node; struct ospf6_interface *oi; p = buffer; end = buffer + sizeof (buffer); snprintf (p, end - p, "SPF on DB (#LSAs):"); p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); snprintf (p, end - p, " Area %s: %d", oa->name, oa->lsdb->count); p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); for (ALL_LIST_ELEMENTS_RO (oa->if_list, node, oi)) { snprintf (p, end - p, " I/F %s: %d", oi->interface->name, oi->lsdb->count); p = (buffer + strlen (buffer) < end ? buffer + strlen (buffer) : end); } zlog_debug ("%s", buffer); } static int ospf6_spf_calculation_thread (struct thread *t) { struct ospf6_area *oa; struct ospf6 *ospf6; struct timeval start, end, runtime; struct listnode *node; struct ospf6_route *route; int areas_processed = 0; char rbuf[32]; ospf6 = (struct ospf6 *)THREAD_ARG (t); ospf6->t_spf_calc = NULL; /* execute SPF calculation */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &start); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { if (oa == ospf6->backbone) continue; if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF calculation for Area %s", oa->name); if (IS_OSPF6_DEBUG_SPF (DATABASE)) ospf6_spf_log_database (oa); ospf6_spf_calculation (ospf6->router_id, oa->spf_table, oa); ospf6_intra_route_calculation (oa); ospf6_intra_brouter_calculation (oa); areas_processed++; } if (ospf6->backbone) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) zlog_debug ("SPF calculation for Backbone area %s", ospf6->backbone->name); if (IS_OSPF6_DEBUG_SPF (DATABASE)) ospf6_spf_log_database(ospf6->backbone); ospf6_spf_calculation(ospf6->router_id, ospf6->backbone->spf_table, ospf6->backbone); ospf6_intra_route_calculation(ospf6->backbone); ospf6_intra_brouter_calculation(ospf6->backbone); areas_processed++; } /* Redo summaries if required */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_abr_originate_summary(route); quagga_gettime (QUAGGA_CLK_MONOTONIC, &end); timersub (&end, &start, &runtime); ospf6->ts_spf_duration = runtime; ospf6_spf_reason_string(ospf6->spf_reason, rbuf, sizeof(rbuf)); if (IS_OSPF6_DEBUG_SPF (PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF runtime: %ld sec %ld usec", runtime.tv_sec, runtime.tv_usec); zlog_info("SPF processing: # Areas: %d, SPF runtime: %ld sec %ld usec, " "Reason: %s\n", areas_processed, runtime.tv_sec, runtime.tv_usec, rbuf); ospf6->last_spf_reason = ospf6->spf_reason; ospf6_reset_spf_reason(ospf6); return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void ospf6_spf_schedule (struct ospf6 *ospf6, unsigned int reason) { unsigned long delay, elapsed, ht; struct timeval now, result; ospf6_set_spf_reason(ospf6, reason); if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) { char rbuf[32]; ospf6_spf_reason_string(reason, rbuf, sizeof(rbuf)); zlog_debug ("SPF: calculation timer scheduled (reason %s)", rbuf); } /* OSPF instance does not exist. */ if (ospf6 == NULL) return; /* SPF calculation timer is already scheduled. */ if (ospf6->t_spf_calc) { if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF: calculation timer is already scheduled: %p", ospf6->t_spf_calc); return; } /* XXX Monotic timers: we only care about relative time here. */ now = recent_relative_time (); timersub (&now, &ospf6->ts_spf, &result); elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); ht = ospf6->spf_holdtime * ospf6->spf_hold_multiplier; if (ht > ospf6->spf_max_holdtime) ht = ospf6->spf_max_holdtime; /* Get SPF calculation delay time. */ if (elapsed < ht) { /* Got an event within the hold time of last SPF. We need to * increase the hold_multiplier, if it's not already at/past * maximum value, and wasn't already increased.. */ if (ht < ospf6->spf_max_holdtime) ospf6->spf_hold_multiplier++; /* always honour the SPF initial delay */ if ( (ht - elapsed) < ospf6->spf_delay) delay = ospf6->spf_delay; else delay = ht - elapsed; } else { /* Event is past required hold-time of last SPF */ delay = ospf6->spf_delay; ospf6->spf_hold_multiplier = 1; } if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF (TIME)) zlog_debug ("SPF: calculation timer delay = %ld", delay); zlog_info ("SPF: Scheduled in %ld msec", delay); ospf6->t_spf_calc = thread_add_timer_msec (master, ospf6_spf_calculation_thread, ospf6, delay); } void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v) { struct listnode *node, *nnode; struct ospf6_vertex *c; char *next_prefix; int len; int restnum; /* "prefix" is the space prefix of the display line */ vty_out (vty, "%s+-%s [%d]%s", prefix, v->name, v->cost, VNL); len = strlen (prefix) + 4; next_prefix = (char *) malloc (len); if (next_prefix == NULL) { vty_out (vty, "malloc failed%s", VNL); return; } snprintf (next_prefix, len, "%s%s", prefix, (rest ? "| " : " ")); restnum = listcount (v->child_list); for (ALL_LIST_ELEMENTS (v->child_list, node, nnode, c)) { restnum--; ospf6_spf_display_subtree (vty, next_prefix, restnum, c); } free (next_prefix); } DEFUN (debug_ospf6_spf_process, debug_ospf6_spf_process_cmd, "debug ospf6 spf process", DEBUG_STR OSPF6_STR "Debug SPF Calculation\n" "Debug Detailed SPF Process\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_PROCESS; OSPF6_DEBUG_SPF_ON (level); return CMD_SUCCESS; } DEFUN (debug_ospf6_spf_time, debug_ospf6_spf_time_cmd, "debug ospf6 spf time", DEBUG_STR OSPF6_STR "Debug SPF Calculation\n" "Measure time taken by SPF Calculation\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_TIME; OSPF6_DEBUG_SPF_ON (level); return CMD_SUCCESS; } DEFUN (debug_ospf6_spf_database, debug_ospf6_spf_database_cmd, "debug ospf6 spf database", DEBUG_STR OSPF6_STR "Debug SPF Calculation\n" "Log number of LSAs at SPF Calculation time\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_DATABASE; OSPF6_DEBUG_SPF_ON (level); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_spf_process, no_debug_ospf6_spf_process_cmd, "no debug ospf6 spf process", NO_STR DEBUG_STR OSPF6_STR "Quit Debugging SPF Calculation\n" "Quit Debugging Detailed SPF Process\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_PROCESS; OSPF6_DEBUG_SPF_OFF (level); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_spf_time, no_debug_ospf6_spf_time_cmd, "no debug ospf6 spf time", NO_STR DEBUG_STR OSPF6_STR "Quit Debugging SPF Calculation\n" "Quit Measuring time taken by SPF Calculation\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_TIME; OSPF6_DEBUG_SPF_OFF (level); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_spf_database, no_debug_ospf6_spf_database_cmd, "no debug ospf6 spf database", NO_STR DEBUG_STR OSPF6_STR "Debug SPF Calculation\n" "Quit Logging number of LSAs at SPF Calculation time\n" ) { unsigned char level = 0; level = OSPF6_DEBUG_SPF_DATABASE; OSPF6_DEBUG_SPF_OFF (level); return CMD_SUCCESS; } static int ospf6_timers_spf_set (struct vty *vty, unsigned int delay, unsigned int hold, unsigned int max) { struct ospf6 *ospf = vty->index; ospf->spf_delay = delay; ospf->spf_holdtime = hold; ospf->spf_max_holdtime = max; return CMD_SUCCESS; } DEFUN (ospf6_timers_throttle_spf, ospf6_timers_throttle_spf_cmd, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") { unsigned int delay, hold, max; if (argc != 3) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000); return ospf6_timers_spf_set (vty, delay, hold, max); } DEFUN (no_ospf6_timers_throttle_spf, no_ospf6_timers_throttle_spf_cmd, "no timers throttle spf", NO_STR "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF6 SPF timers\n") { return ospf6_timers_spf_set (vty, OSPF_SPF_DELAY_DEFAULT, OSPF_SPF_HOLDTIME_DEFAULT, OSPF_SPF_MAX_HOLDTIME_DEFAULT); } int config_write_ospf6_debug_spf (struct vty *vty) { if (IS_OSPF6_DEBUG_SPF (PROCESS)) vty_out (vty, "debug ospf6 spf process%s", VNL); if (IS_OSPF6_DEBUG_SPF (TIME)) vty_out (vty, "debug ospf6 spf time%s", VNL); if (IS_OSPF6_DEBUG_SPF (DATABASE)) vty_out (vty, "debug ospf6 spf database%s", VNL); return 0; } void ospf6_spf_config_write (struct vty *vty) { if (ospf6->spf_delay != OSPF_SPF_DELAY_DEFAULT || ospf6->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || ospf6->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) vty_out (vty, " timers throttle spf %d %d %d%s", ospf6->spf_delay, ospf6->spf_holdtime, ospf6->spf_max_holdtime, VTY_NEWLINE); } void install_element_ospf6_debug_spf (void) { install_element (ENABLE_NODE, &debug_ospf6_spf_process_cmd); install_element (ENABLE_NODE, &debug_ospf6_spf_time_cmd); install_element (ENABLE_NODE, &debug_ospf6_spf_database_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_spf_process_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_spf_time_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_spf_database_cmd); install_element (CONFIG_NODE, &debug_ospf6_spf_process_cmd); install_element (CONFIG_NODE, &debug_ospf6_spf_time_cmd); install_element (CONFIG_NODE, &debug_ospf6_spf_database_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_spf_process_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_spf_time_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_spf_database_cmd); } void ospf6_spf_init (void) { install_element (OSPF6_NODE, &ospf6_timers_throttle_spf_cmd); install_element (OSPF6_NODE, &no_ospf6_timers_throttle_spf_cmd); } quagga-0.99.24.1/ospf6d/ospf6_zebra.c0000644000175000017500000004466612476520570014041 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "vty.h" #include "command.h" #include "prefix.h" #include "stream.h" #include "zclient.h" #include "memory.h" #include "ospf6_proto.h" #include "ospf6_top.h" #include "ospf6_interface.h" #include "ospf6_route.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_asbr.h" #include "ospf6_zebra.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_zebra = 0; /* information about zebra. */ struct zclient *zclient = NULL; struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf6_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length) { struct prefix router_id; struct ospf6 *o = ospf6; zebra_router_id_update_read(zclient->ibuf,&router_id); router_id_zebra = router_id.u.prefix4; if (o == NULL) return 0; if (o->router_id == 0) o->router_id = (u_int32_t) router_id_zebra.s_addr; return 0; } /* redistribute function */ void ospf6_zebra_redistribute (int type) { if (zclient->redist[type]) return; zclient->redist[type] = 1; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); } void ospf6_zebra_no_redistribute (int type) { if (! zclient->redist[type]) return; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); } /* Inteface addition message from zebra. */ static int ospf6_zebra_if_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface add: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); ospf6_interface_if_add (ifp); return 0; } static int ospf6_zebra_if_del (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; if (!(ifp = zebra_interface_state_read(zclient->ibuf))) return 0; if (if_is_up (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface delete: %s index %d mtu %d", ifp->name, ifp->ifindex, ifp->mtu6); #if 0 /* XXX: ospf6_interface_if_del is not the right way to handle this, * because among other thinkable issues, it will also clear all * settings as they are contained in the struct ospf6_interface. */ ospf6_interface_if_del (ifp); #endif /*0*/ ifp->ifindex = IFINDEX_INTERNAL; return 0; } static int ospf6_zebra_if_state_update (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface state change: " "%s index %d flags %llx metric %d mtu %d bandwidth %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6, ifp->bandwidth); ospf6_interface_state_update (ifp); return 0; } static int ospf6_zebra_if_address_update_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (c == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface address add: %s %5s %s/%d", c->ifp->name, prefix_family_str (c->address), inet_ntop (c->address->family, &c->address->u.prefix, buf, sizeof (buf)), c->address->prefixlen); if (c->address->family == AF_INET6) { ospf6_interface_state_update (c->ifp); ospf6_interface_connected_route_update (c->ifp); } return 0; } static int ospf6_zebra_if_address_update_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; char buf[128]; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); if (c == NULL) return 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) zlog_debug ("Zebra Interface address delete: %s %5s %s/%d", c->ifp->name, prefix_family_str (c->address), inet_ntop (c->address->family, &c->address->u.prefix, buf, sizeof (buf)), c->address->prefixlen); if (c->address->family == AF_INET6) { ospf6_interface_connected_route_update (c->ifp); ospf6_interface_state_update (c->ifp); } return 0; } static int ospf6_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct prefix_ipv6 p; struct in6_addr *nexthop; s = zclient->ibuf; ifindex = 0; nexthop = NULL; memset (&api, 0, sizeof (api)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop = (struct in6_addr *) malloc (api.nexthop_num * sizeof (struct in6_addr)); stream_get (nexthop, s, api.nexthop_num * sizeof (struct in6_addr)); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (IS_OSPF6_DEBUG_ZEBRA (RECV)) { char prefixstr[128], nexthopstr[128]; prefix2str ((struct prefix *)&p, prefixstr, sizeof (prefixstr)); if (nexthop) inet_ntop (AF_INET6, nexthop, nexthopstr, sizeof (nexthopstr)); else snprintf (nexthopstr, sizeof (nexthopstr), "::"); zlog_debug ("Zebra Receive route %s: %s %s nexthop %s ifindex %ld", (command == ZEBRA_IPV6_ROUTE_ADD ? "add" : "delete"), zebra_route_string(api.type), prefixstr, nexthopstr, ifindex); } if (command == ZEBRA_IPV6_ROUTE_ADD) ospf6_asbr_redistribute_add (api.type, ifindex, (struct prefix *) &p, api.nexthop_num, nexthop); else ospf6_asbr_redistribute_remove (api.type, ifindex, (struct prefix *) &p); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) free (nexthop); return 0; } DEFUN (show_zebra, show_zebra_cmd, "show zebra", SHOW_STR "Zebra information\n") { int i; if (zclient == NULL) { vty_out (vty, "Not connected to zebra%s", VNL); return CMD_SUCCESS; } vty_out (vty, "Zebra Infomation%s", VNL); vty_out (vty, " enable: %d fail: %d%s", zclient->enable, zclient->fail, VNL); vty_out (vty, " redistribute default: %d%s", zclient->redist_default, VNL); vty_out (vty, " redistribute:"); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (zclient->redist[i]) vty_out (vty, " %s", zebra_route_string(i)); } vty_out (vty, "%s", VNL); return CMD_SUCCESS; } DEFUN (router_zebra, router_zebra_cmd, "router zebra", "Enable a routing process\n" "Make connection to zebra daemon\n") { vty->node = ZEBRA_NODE; zclient->enable = 1; zclient_start (zclient); return CMD_SUCCESS; } DEFUN (no_router_zebra, no_router_zebra_cmd, "no router zebra", NO_STR "Configure routing process\n" "Disable connection to zebra daemon\n") { zclient->enable = 0; zclient_stop (zclient); return CMD_SUCCESS; } /* Zebra configuration write function. */ static int config_write_ospf6_zebra (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VNL); vty_out (vty, "!%s", VNL); } else if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { vty_out (vty, "router zebra%s", VNL); vty_out (vty, " no redistribute ospf6%s", VNL); vty_out (vty, "!%s", VNL); } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-zebra)# ", }; #define ADD 0 #define REM 1 static void ospf6_zebra_route_update (int type, struct ospf6_route *request) { struct zapi_ipv6 api; char buf[64]; int nhcount; struct in6_addr **nexthops; unsigned int *ifindexes; int i, ret = 0; struct prefix_ipv6 *dest; if (IS_OSPF6_DEBUG_ZEBRA (SEND)) { prefix2str (&request->prefix, buf, sizeof (buf)); zlog_debug ("Send %s route: %s", (type == REM ? "remove" : "add"), buf); } if (zclient->sock < 0) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" Not connected to Zebra"); return; } if (request->path.origin.adv_router == ospf6->router_id && (request->path.type == OSPF6_PATH_TYPE_EXTERNAL1 || request->path.type == OSPF6_PATH_TYPE_EXTERNAL2)) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" Ignore self-originated external route"); return; } /* If removing is the best path and if there's another path, treat this request as add the secondary path */ if (type == REM && ospf6_route_is_best (request) && request->next && ospf6_route_is_same (request, request->next)) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" Best-path removal resulted Sencondary addition"); type = ADD; request = request->next; } /* Only the best path will be sent to zebra. */ if (! ospf6_route_is_best (request)) { /* this is not preferred best route, ignore */ if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" Ignore non-best route"); return; } nhcount = 0; for (i = 0; i < OSPF6_MULTI_PATH_LIMIT; i++) if (ospf6_nexthop_is_set (&request->nexthop[i])) nhcount++; if (nhcount == 0) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) zlog_debug (" No nexthop, ignore"); return; } /* allocate memory for nexthop_list */ nexthops = XCALLOC (MTYPE_OSPF6_OTHER, nhcount * sizeof (struct in6_addr *)); if (nexthops == NULL) { zlog_warn ("Can't send route to zebra: malloc failed"); return; } /* allocate memory for ifindex_list */ ifindexes = XCALLOC (MTYPE_OSPF6_OTHER, nhcount * sizeof (unsigned int)); if (ifindexes == NULL) { zlog_warn ("Can't send route to zebra: malloc failed"); XFREE (MTYPE_OSPF6_OTHER, nexthops); return; } for (i = 0; i < nhcount; i++) { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) { char ifname[IFNAMSIZ]; inet_ntop (AF_INET6, &request->nexthop[i].address, buf, sizeof (buf)); if (!if_indextoname(request->nexthop[i].ifindex, ifname)) strlcpy(ifname, "unknown", sizeof(ifname)); zlog_debug (" nexthop: %s%%%.*s(%d)", buf, IFNAMSIZ, ifname, request->nexthop[i].ifindex); } nexthops[i] = &request->nexthop[i].address; ifindexes[i] = request->nexthop[i].ifindex; } api.type = ZEBRA_ROUTE_OSPF6; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = nhcount; api.nexthop = nexthops; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = nhcount; api.ifindex = ifindexes; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = (request->path.metric_type == 2 ? request->path.cost_e2 : request->path.cost); dest = (struct prefix_ipv6 *) &request->prefix; if (type == REM) ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, dest, &api); else ret = zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, dest, &api); if (ret < 0) zlog_err ("zapi_ipv6_route() %s failed: %s", (type == REM ? "delete" : "add"), safe_strerror (errno)); XFREE (MTYPE_OSPF6_OTHER, nexthops); XFREE (MTYPE_OSPF6_OTHER, ifindexes); return; } void ospf6_zebra_route_update_add (struct ospf6_route *request) { if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; return; } ospf6_zebra_route_update (ADD, request); } void ospf6_zebra_route_update_remove (struct ospf6_route *request) { if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) { ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; return; } ospf6_zebra_route_update (REM, request); } DEFUN (redistribute_ospf6, redistribute_ospf6_cmd, "redistribute ospf6", "Redistribute control\n" "OSPF6 route\n") { struct ospf6_route *route; if (zclient->redist[ZEBRA_ROUTE_OSPF6]) return CMD_SUCCESS; zclient->redist[ZEBRA_ROUTE_OSPF6] = 1; if (ospf6 == NULL) return CMD_SUCCESS; /* send ospf6 route to zebra route table */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_zebra_route_update_add (route); ospf6->route_table->hook_add = ospf6_zebra_route_update_add; ospf6->route_table->hook_remove = ospf6_zebra_route_update_remove; return CMD_SUCCESS; } DEFUN (no_redistribute_ospf6, no_redistribute_ospf6_cmd, "no redistribute ospf6", NO_STR "Redistribute control\n" "OSPF6 route\n") { struct ospf6_route *route; if (! zclient->redist[ZEBRA_ROUTE_OSPF6]) return CMD_SUCCESS; zclient->redist[ZEBRA_ROUTE_OSPF6] = 0; if (ospf6 == NULL) return CMD_SUCCESS; ospf6->route_table->hook_add = NULL; ospf6->route_table->hook_remove = NULL; /* withdraw ospf6 route from zebra route table */ for (route = ospf6_route_head (ospf6->route_table); route; route = ospf6_route_next (route)) ospf6_zebra_route_update_remove (route); return CMD_SUCCESS; } void ospf6_zebra_init (void) { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF6); zclient->router_id_update = ospf6_router_id_update_zebra; zclient->interface_add = ospf6_zebra_if_add; zclient->interface_delete = ospf6_zebra_if_del; zclient->interface_up = ospf6_zebra_if_state_update; zclient->interface_down = ospf6_zebra_if_state_update; zclient->interface_address_add = ospf6_zebra_if_address_update_add; zclient->interface_address_delete = ospf6_zebra_if_address_update_delete; zclient->ipv4_route_add = NULL; zclient->ipv4_route_delete = NULL; zclient->ipv6_route_add = ospf6_zebra_read_ipv6; zclient->ipv6_route_delete = ospf6_zebra_read_ipv6; /* redistribute connected route by default */ /* ospf6_zebra_redistribute (ZEBRA_ROUTE_CONNECT); */ /* Install zebra node. */ install_node (&zebra_node, config_write_ospf6_zebra); /* Install command element for zebra node. */ install_element (VIEW_NODE, &show_zebra_cmd); install_element (ENABLE_NODE, &show_zebra_cmd); install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &redistribute_ospf6_cmd); install_element (ZEBRA_NODE, &no_redistribute_ospf6_cmd); return; } /* Debug */ DEFUN (debug_ospf6_zebra_sendrecv, debug_ospf6_zebra_sendrecv_cmd, "debug ospf6 zebra (send|recv)", DEBUG_STR OSPF6_STR "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_ZEBRA_SEND; else if (! strncmp (argv[0], "r", 1)) level = OSPF6_DEBUG_ZEBRA_RECV; } else level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; OSPF6_DEBUG_ZEBRA_ON (level); return CMD_SUCCESS; } ALIAS (debug_ospf6_zebra_sendrecv, debug_ospf6_zebra_cmd, "debug ospf6 zebra", DEBUG_STR OSPF6_STR "Debug connection between zebra\n" ) DEFUN (no_debug_ospf6_zebra_sendrecv, no_debug_ospf6_zebra_sendrecv_cmd, "no debug ospf6 zebra (send|recv)", NO_STR DEBUG_STR OSPF6_STR "Debug connection between zebra\n" "Debug Sending zebra\n" "Debug Receiving zebra\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_ZEBRA_SEND; else if (! strncmp (argv[0], "r", 1)) level = OSPF6_DEBUG_ZEBRA_RECV; } else level = OSPF6_DEBUG_ZEBRA_SEND | OSPF6_DEBUG_ZEBRA_RECV; OSPF6_DEBUG_ZEBRA_OFF (level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_zebra_sendrecv, no_debug_ospf6_zebra_cmd, "no debug ospf6 zebra", NO_STR DEBUG_STR OSPF6_STR "Debug connection between zebra\n" ) int config_write_ospf6_debug_zebra (struct vty *vty) { if (IS_OSPF6_DEBUG_ZEBRA (SEND) && IS_OSPF6_DEBUG_ZEBRA (RECV)) vty_out (vty, "debug ospf6 zebra%s", VNL); else { if (IS_OSPF6_DEBUG_ZEBRA (SEND)) vty_out (vty, "debug ospf6 zebra send%s", VNL); if (IS_OSPF6_DEBUG_ZEBRA (RECV)) vty_out (vty, "debug ospf6 zebra recv%s", VNL); } return 0; } void install_element_ospf6_debug_zebra (void) { install_element (ENABLE_NODE, &debug_ospf6_zebra_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_cmd); install_element (ENABLE_NODE, &debug_ospf6_zebra_sendrecv_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); install_element (CONFIG_NODE, &debug_ospf6_zebra_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_cmd); install_element (CONFIG_NODE, &debug_ospf6_zebra_sendrecv_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_zebra_sendrecv_cmd); } quagga-0.99.24.1/ospf6d/ospf6_intra.c0000644000175000017500000015703312476520570014044 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "linklist.h" #include "thread.h" #include "memory.h" #include "if.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6_flood.h" #include "ospf6d.h" #include "ospf6_spf.h" unsigned char conf_debug_ospf6_brouter = 0; u_int32_t conf_debug_ospf6_brouter_specific_router_id; u_int32_t conf_debug_ospf6_brouter_specific_area_id; /******************************/ /* RFC2740 3.4.3.1 Router-LSA */ /******************************/ static char * ospf6_router_lsa_get_nbr_id (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; char *start, *end; char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN]; if (lsa) { router_lsa = (struct ospf6_router_lsa *) ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); lsdesc = (struct ospf6_router_lsdesc *) (start + pos*(sizeof (struct ospf6_router_lsdesc))); if ((char *)lsdesc < end) { if (buf && (buflen > INET_ADDRSTRLEN*2)) { inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, buf1, sizeof(buf1)); inet_ntop (AF_INET, &lsdesc->neighbor_router_id, buf2, sizeof(buf2)); sprintf (buf, "%s/%s", buf2, buf1); } } else return NULL; } return buf; } static int ospf6_router_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char *start, *end, *current; char buf[32], name[32], bits[16], options[32]; struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; router_lsa = (struct ospf6_router_lsa *) ((char *) lsa->header + sizeof (struct ospf6_lsa_header)); ospf6_capability_printbuf (router_lsa->bits, bits, sizeof (bits)); ospf6_options_printbuf (router_lsa->options, options, sizeof (options)); vty_out (vty, " Bits: %s Options: %s%s", bits, options, VNL); start = (char *) router_lsa + sizeof (struct ospf6_router_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current + sizeof (struct ospf6_router_lsdesc) <= end; current += sizeof (struct ospf6_router_lsdesc)) { lsdesc = (struct ospf6_router_lsdesc *) current; if (lsdesc->type == OSPF6_ROUTER_LSDESC_POINTTOPOINT) snprintf (name, sizeof (name), "Point-To-Point"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK) snprintf (name, sizeof (name), "Transit-Network"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_STUB_NETWORK) snprintf (name, sizeof (name), "Stub-Network"); else if (lsdesc->type == OSPF6_ROUTER_LSDESC_VIRTUAL_LINK) snprintf (name, sizeof (name), "Virtual-Link"); else snprintf (name, sizeof (name), "Unknown (%#x)", lsdesc->type); vty_out (vty, " Type: %s Metric: %d%s", name, ntohs (lsdesc->metric), VNL); vty_out (vty, " Interface ID: %s%s", inet_ntop (AF_INET, &lsdesc->interface_id, buf, sizeof (buf)), VNL); vty_out (vty, " Neighbor Interface ID: %s%s", inet_ntop (AF_INET, &lsdesc->neighbor_interface_id, buf, sizeof (buf)), VNL); vty_out (vty, " Neighbor Router ID: %s%s", inet_ntop (AF_INET, &lsdesc->neighbor_router_id, buf, sizeof (buf)), VNL); } return 0; } int ospf6_router_is_stub_router (struct ospf6_lsa *lsa) { struct ospf6_router_lsa *rtr_lsa; if (lsa != NULL && OSPF6_LSA_IS_TYPE (ROUTER, lsa)) { rtr_lsa = (struct ospf6_router_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_R)) { return (OSPF6_IS_STUB_ROUTER); } else if (!OSPF6_OPT_ISSET (rtr_lsa->options, OSPF6_OPT_V6)) { return (OSPF6_IS_STUB_ROUTER_V6); } } return (OSPF6_NOT_STUB_ROUTER); } int ospf6_router_lsa_originate (struct thread *thread) { struct ospf6_area *oa; char buffer [OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *lsa; u_int32_t link_state_id = 0; struct listnode *node, *nnode; struct listnode *j; struct ospf6_interface *oi; struct ospf6_neighbor *on, *drouter = NULL; struct ospf6_router_lsa *router_lsa; struct ospf6_router_lsdesc *lsdesc; u_int16_t type; u_int32_t router; int count; oa = (struct ospf6_area *) THREAD_ARG (thread); oa->thread_router_lsa = NULL; if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) zlog_debug ("Originate Router-LSA for Area %s", oa->name); memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; router_lsa = (struct ospf6_router_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_E); OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_MC); OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_N); OSPF6_OPT_SET (router_lsa->options, OSPF6_OPT_R); OSPF6_OPT_CLEAR (router_lsa->options, OSPF6_OPT_DC); if (ospf6_is_router_abr (ospf6)) SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); else UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_B); if (ospf6_asbr_is_asbr (ospf6)) SET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); else UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_E); UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_V); UNSET_FLAG (router_lsa->bits, OSPF6_ROUTER_BIT_W); /* describe links for each interfaces */ lsdesc = (struct ospf6_router_lsdesc *) ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { /* Interfaces in state Down or Loopback are not described */ if (oi->state == OSPF6_INTERFACE_DOWN || oi->state == OSPF6_INTERFACE_LOOPBACK) continue; /* Nor are interfaces without any full adjacencies described */ count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) if (on->state == OSPF6_NEIGHBOR_FULL) count++; if (count == 0) continue; /* Multiple Router-LSA instance according to size limit setting */ if ( (oa->router_lsa_size_limit != 0) && ((caddr_t) lsdesc + sizeof (struct ospf6_router_lsdesc) - /* XXX warning: comparison between signed and unsigned */ (caddr_t) buffer > oa->router_lsa_size_limit)) { if ((caddr_t) lsdesc == (caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)) { if (IS_OSPF6_DEBUG_ORIGINATE (ROUTER)) zlog_debug ("Size limit setting for Router-LSA too short"); return 0; } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); lsa_header->id = htonl (link_state_id); lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oa); /* Reset setting for consecutive origination */ memset ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa), 0, (caddr_t) lsdesc - (caddr_t) router_lsa); lsdesc = (struct ospf6_router_lsdesc *) ((caddr_t) router_lsa + sizeof (struct ospf6_router_lsa)); link_state_id ++; } /* Point-to-Point interfaces */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) { for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) { if (on->state != OSPF6_NEIGHBOR_FULL) continue; lsdesc->type = OSPF6_ROUTER_LSDESC_POINTTOPOINT; lsdesc->metric = htons (oi->cost); lsdesc->interface_id = htonl (oi->interface->ifindex); lsdesc->neighbor_interface_id = htonl (on->ifindex); lsdesc->neighbor_router_id = on->router_id; lsdesc++; } } /* Broadcast and NBMA interfaces */ else if (oi->type == OSPF_IFTYPE_BROADCAST) { /* If this router is not DR, and If this router not fully adjacent with DR, this interface is not transit yet: ignore. */ if (oi->state != OSPF6_INTERFACE_DR) { drouter = ospf6_neighbor_lookup (oi->drouter, oi); if (drouter == NULL || drouter->state != OSPF6_NEIGHBOR_FULL) continue; } lsdesc->type = OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK; lsdesc->metric = htons (oi->cost); lsdesc->interface_id = htonl (oi->interface->ifindex); if (oi->state != OSPF6_INTERFACE_DR) { lsdesc->neighbor_interface_id = htonl (drouter->ifindex); lsdesc->neighbor_router_id = drouter->router_id; } else { lsdesc->neighbor_interface_id = htonl (oi->interface->ifindex); lsdesc->neighbor_router_id = oi->area->ospf6->router_id; } lsdesc++; } else { assert (0); /* Unknown interface type */ } /* Virtual links */ /* xxx */ /* Point-to-Multipoint interfaces */ /* xxx */ } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_ROUTER); lsa_header->id = htonl (link_state_id); lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oa); link_state_id ++; /* Do premature-aging of rest, undesired Router-LSAs */ type = ntohs (OSPF6_LSTYPE_ROUTER); router = oa->ospf6->router_id; for (lsa = ospf6_lsdb_type_router_head (type, router, oa->lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, router, lsa)) { if (ntohl (lsa->header->id) < link_state_id) continue; ospf6_lsa_purge (lsa); } return 0; } /*******************************/ /* RFC2740 3.4.3.2 Network-LSA */ /*******************************/ static char * ospf6_network_lsa_get_ar_id (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_network_lsa *network_lsa; struct ospf6_network_lsdesc *lsdesc; if (lsa) { network_lsa = (struct ospf6_network_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start + pos*(sizeof (struct ospf6_network_lsdesc)); if ((current + sizeof(struct ospf6_network_lsdesc)) <= end) { lsdesc = (struct ospf6_network_lsdesc *)current; if (buf) inet_ntop (AF_INET, &lsdesc->router_id, buf, buflen); } else return NULL; } return (buf); } static int ospf6_network_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char *start, *end, *current; struct ospf6_network_lsa *network_lsa; struct ospf6_network_lsdesc *lsdesc; char buf[128], options[32]; network_lsa = (struct ospf6_network_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); ospf6_options_printbuf (network_lsa->options, options, sizeof (options)); vty_out (vty, " Options: %s%s", options, VNL); start = (char *) network_lsa + sizeof (struct ospf6_network_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current + sizeof (struct ospf6_network_lsdesc) <= end; current += sizeof (struct ospf6_network_lsdesc)) { lsdesc = (struct ospf6_network_lsdesc *) current; inet_ntop (AF_INET, &lsdesc->router_id, buf, sizeof (buf)); vty_out (vty, " Attached Router: %s%s", buf, VNL); } return 0; } int ospf6_network_lsa_originate (struct thread *thread) { struct ospf6_interface *oi; char buffer [OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; int count; struct ospf6_lsa *old, *lsa; struct ospf6_network_lsa *network_lsa; struct ospf6_network_lsdesc *lsdesc; struct ospf6_neighbor *on; struct ospf6_link_lsa *link_lsa; struct listnode *i; u_int16_t type; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_network_lsa = NULL; /* The interface must be enabled until here. A Network-LSA of a disabled interface (but was once enabled) should be flushed by ospf6_lsa_refresh (), and does not come here. */ assert (oi->area); old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_NETWORK), htonl (oi->interface->ifindex), oi->area->ospf6->router_id, oi->area->lsdb); /* Do not originate Network-LSA if not DR */ if (oi->state != OSPF6_INTERFACE_DR) { if (old) ospf6_lsa_purge (old); return 0; } if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) zlog_debug ("Originate Network-LSA for Interface %s", oi->interface->name); /* If none of neighbor is adjacent to us */ count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) count++; if (count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (NETWORK)) zlog_debug ("Interface stub, ignore"); if (old) ospf6_lsa_purge (old); return 0; } /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; network_lsa = (struct ospf6_network_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); /* Collect the interface's Link-LSAs to describe network's optional capabilities */ type = htons (OSPF6_LSTYPE_LINK); for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa; lsa = ospf6_lsdb_type_next (type, lsa)) { link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); network_lsa->options[0] |= link_lsa->options[0]; network_lsa->options[1] |= link_lsa->options[1]; network_lsa->options[2] |= link_lsa->options[2]; } lsdesc = (struct ospf6_network_lsdesc *) ((caddr_t) network_lsa + sizeof (struct ospf6_network_lsa)); /* set Link Description to the router itself */ lsdesc->router_id = oi->area->ospf6->router_id; lsdesc++; /* Walk through the neighbors */ for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) { if (on->state != OSPF6_NEIGHBOR_FULL) continue; /* set this neighbor's Router-ID to LSA */ lsdesc->router_id = on->router_id; lsdesc++; } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_NETWORK); lsa_header->id = htonl (oi->interface->ifindex); lsa_header->adv_router = oi->area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oi->area->lsdb); lsa_header->length = htons ((caddr_t) lsdesc - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oi->area); return 0; } /****************************/ /* RFC2740 3.4.3.6 Link-LSA */ /****************************/ static char * ospf6_link_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_link_lsa *link_lsa; struct in6_addr in6; struct ospf6_prefix *prefix; int cnt = 0, prefixnum; if (lsa) { link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); if (pos == 0) { inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, buflen); return (buf); } prefixnum = ntohl (link_lsa->prefix_num); if (pos > prefixnum) return (NULL); start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start; do { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) { return (NULL); } if (cnt < pos) { current = start + pos*OSPF6_PREFIX_SIZE(prefix); cnt++; } else { memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, buflen); return (buf); } } while (current <= end); } return (NULL); } static int ospf6_link_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char *start, *end, *current; struct ospf6_link_lsa *link_lsa; int prefixnum; char buf[128], options[32]; struct ospf6_prefix *prefix; const char *p, *mc, *la, *nu; struct in6_addr in6; link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); ospf6_options_printbuf (link_lsa->options, options, sizeof (options)); inet_ntop (AF_INET6, &link_lsa->linklocal_addr, buf, sizeof (buf)); prefixnum = ntohl (link_lsa->prefix_num); vty_out (vty, " Priority: %d Options: %s%s", link_lsa->priority, options, VNL); vty_out (vty, " LinkLocal Address: %s%s", buf, VNL); vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL); start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) break; p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ? "P" : "--"); mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--"); la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--"); nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--"); vty_out (vty, " Prefix Options: %s|%s|%s|%s%s", p, mc, la, nu, VNL); memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); vty_out (vty, " Prefix: %s/%d%s", buf, prefix->prefix_length, VNL); } return 0; } int ospf6_link_lsa_originate (struct thread *thread) { struct ospf6_interface *oi; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *old, *lsa; struct ospf6_link_lsa *link_lsa; struct ospf6_route *route; struct ospf6_prefix *op; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_link_lsa = NULL; assert (oi->area); /* find previous LSA */ old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_LINK), htonl (oi->interface->ifindex), oi->area->ospf6->router_id, oi->lsdb); if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) { if (old) ospf6_lsa_purge (old); return 0; } if (IS_OSPF6_DEBUG_ORIGINATE (LINK)) zlog_debug ("Originate Link-LSA for Interface %s", oi->interface->name); /* can't make Link-LSA if linklocal address not set */ if (oi->linklocal_addr == NULL) { if (IS_OSPF6_DEBUG_ORIGINATE (LINK)) zlog_debug ("No Linklocal address on %s, defer originating", oi->interface->name); if (old) ospf6_lsa_purge (old); return 0; } /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); /* Fill Link-LSA */ link_lsa->priority = oi->priority; memcpy (link_lsa->options, oi->area->options, 3); memcpy (&link_lsa->linklocal_addr, oi->linklocal_addr, sizeof (struct in6_addr)); link_lsa->prefix_num = htonl (oi->route_connected->count); op = (struct ospf6_prefix *) ((caddr_t) link_lsa + sizeof (struct ospf6_link_lsa)); /* connected prefix to advertise */ for (route = ospf6_route_head (oi->route_connected); route; route = ospf6_route_next (route)) { op->prefix_length = route->prefix.prefixlen; op->prefix_options = route->path.prefix_options; op->prefix_metric = htons (0); memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (op->prefix_length)); op = OSPF6_PREFIX_NEXT (op); } /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_LINK); lsa_header->id = htonl (oi->interface->ifindex); lsa_header->adv_router = oi->area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oi->lsdb); lsa_header->length = htons ((caddr_t) op - (caddr_t) buffer); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_interface (lsa, oi); return 0; } /*****************************************/ /* RFC2740 3.4.3.7 Intra-Area-Prefix-LSA */ /*****************************************/ static char * ospf6_intra_prefix_lsa_get_prefix_str (struct ospf6_lsa *lsa, char *buf, int buflen, int pos) { char *start, *end, *current; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct in6_addr in6; int prefixnum, cnt = 0; struct ospf6_prefix *prefix; if (lsa) { intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); prefixnum = ntohs (intra_prefix_lsa->prefix_num); if (pos > prefixnum) return (NULL); start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); current = start; do { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) { return NULL; } if (cnt < pos) { current = start + pos*OSPF6_PREFIX_SIZE(prefix); cnt++; } else { memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, buflen); sprintf(&buf[strlen(buf)], "/%d", prefix->prefix_length); return (buf); } } while (current <= end); } return (buf); } static int ospf6_intra_prefix_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char *start, *end, *current; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; int prefixnum; char buf[128]; struct ospf6_prefix *prefix; char id[16], adv_router[16]; const char *p, *mc, *la, *nu; struct in6_addr in6; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); prefixnum = ntohs (intra_prefix_lsa->prefix_num); vty_out (vty, " Number of Prefix: %d%s", prefixnum, VNL); inet_ntop (AF_INET, &intra_prefix_lsa->ref_id, id, sizeof (id)); inet_ntop (AF_INET, &intra_prefix_lsa->ref_adv_router, adv_router, sizeof (adv_router)); vty_out (vty, " Reference: %s Id: %s Adv: %s%s", ospf6_lstype_name (intra_prefix_lsa->ref_type), id, adv_router, VNL); start = (char *) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current < end; current += OSPF6_PREFIX_SIZE (prefix)) { prefix = (struct ospf6_prefix *) current; if (prefix->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (prefix) > end) break; p = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_P) ? "P" : "--"); mc = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_MC) ? "MC" : "--"); la = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_LA) ? "LA" : "--"); nu = (CHECK_FLAG (prefix->prefix_options, OSPF6_PREFIX_OPTION_NU) ? "NU" : "--"); vty_out (vty, " Prefix Options: %s|%s|%s|%s%s", p, mc, la, nu, VNL); memset (&in6, 0, sizeof (in6)); memcpy (&in6, OSPF6_PREFIX_BODY (prefix), OSPF6_PREFIX_SPACE (prefix->prefix_length)); inet_ntop (AF_INET6, &in6, buf, sizeof (buf)); vty_out (vty, " Prefix: %s/%d%s", buf, prefix->prefix_length, VNL); } return 0; } int ospf6_intra_prefix_lsa_originate_stub (struct thread *thread) { struct ospf6_area *oa; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *old, *lsa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct ospf6_interface *oi; struct ospf6_neighbor *on; struct ospf6_route *route; struct ospf6_prefix *op; struct listnode *i, *j; int full_count = 0; unsigned short prefix_num = 0; char buf[BUFSIZ]; struct ospf6_route_table *route_advertise; oa = (struct ospf6_area *) THREAD_ARG (thread); oa->thread_intra_prefix_lsa = NULL; /* find previous LSA */ old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX), htonl (0), oa->ospf6->router_id, oa->lsdb); if (! IS_AREA_ENABLED (oa)) { if (old) ospf6_lsa_purge (old); return 0; } if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("Originate Intra-Area-Prefix-LSA for area %s's stub prefix", oa->name); /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_ROUTER); intra_prefix_lsa->ref_id = htonl (0); intra_prefix_lsa->ref_adv_router = oa->ospf6->router_id; route_advertise = ospf6_route_table_create (0, 0); for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi)) { if (oi->state == OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface %s is down, ignore", oi->interface->name); continue; } full_count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, j, on)) if (on->state == OSPF6_NEIGHBOR_FULL) full_count++; if (oi->state != OSPF6_INTERFACE_LOOPBACK && oi->state != OSPF6_INTERFACE_POINTTOPOINT && full_count != 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface %s is not stub, ignore", oi->interface->name); continue; } if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface %s:", oi->interface->name); /* connected prefix to advertise */ for (route = ospf6_route_head (oi->route_connected); route; route = ospf6_route_best_next (route)) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug (" include %s", buf); } ospf6_route_add (ospf6_route_copy (route), route_advertise); } } if (route_advertise->count == 0) { if (old) ospf6_lsa_purge (old); ospf6_route_table_delete (route_advertise); return 0; } /* put prefixes to advertise */ prefix_num = 0; op = (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa)); for (route = ospf6_route_head (route_advertise); route; route = ospf6_route_best_next (route)) { op->prefix_length = route->prefix.prefixlen; op->prefix_options = route->path.prefix_options; op->prefix_metric = htons (route->path.cost); memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (op->prefix_length)); op = OSPF6_PREFIX_NEXT (op); prefix_num++; } ospf6_route_table_delete (route_advertise); if (prefix_num == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("Quit to Advertise Intra-Prefix: no route to advertise"); return 0; } intra_prefix_lsa->prefix_num = htons (prefix_num); /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX); lsa_header->id = htonl (0); lsa_header->adv_router = oa->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oa->lsdb); lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oa); return 0; } int ospf6_intra_prefix_lsa_originate_transit (struct thread *thread) { struct ospf6_interface *oi; char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa_header *lsa_header; struct ospf6_lsa *old, *lsa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct ospf6_neighbor *on; struct ospf6_route *route; struct ospf6_prefix *op; struct listnode *i; int full_count = 0; unsigned short prefix_num = 0; struct ospf6_route_table *route_advertise; struct ospf6_link_lsa *link_lsa; char *start, *end, *current; u_int16_t type; char buf[BUFSIZ]; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_intra_prefix_lsa = NULL; assert (oi->area); /* find previous LSA */ old = ospf6_lsdb_lookup (htons (OSPF6_LSTYPE_INTRA_PREFIX), htonl (oi->interface->ifindex), oi->area->ospf6->router_id, oi->area->lsdb); if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) { if (old) ospf6_lsa_purge (old); return 0; } if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("Originate Intra-Area-Prefix-LSA for interface %s's prefix", oi->interface->name); /* prepare buffer */ memset (buffer, 0, sizeof (buffer)); lsa_header = (struct ospf6_lsa_header *) buffer; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsa_header + sizeof (struct ospf6_lsa_header)); /* Fill Intra-Area-Prefix-LSA */ intra_prefix_lsa->ref_type = htons (OSPF6_LSTYPE_NETWORK); intra_prefix_lsa->ref_id = htonl (oi->interface->ifindex); intra_prefix_lsa->ref_adv_router = oi->area->ospf6->router_id; if (oi->state != OSPF6_INTERFACE_DR) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface is not DR"); if (old) ospf6_lsa_purge (old); return 0; } full_count = 0; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, i, on)) if (on->state == OSPF6_NEIGHBOR_FULL) full_count++; if (full_count == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Interface is stub"); if (old) ospf6_lsa_purge (old); return 0; } /* connected prefix to advertise */ route_advertise = ospf6_route_table_create (0, 0); type = ntohs (OSPF6_LSTYPE_LINK); for (lsa = ospf6_lsdb_type_head (type, oi->lsdb); lsa; lsa = ospf6_lsdb_type_next (type, lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) continue; if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" include prefix from %s", lsa->name); if (lsa->header->adv_router != oi->area->ospf6->router_id) { on = ospf6_neighbor_lookup (lsa->header->adv_router, oi); if (on == NULL || on->state != OSPF6_NEIGHBOR_FULL) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug (" Neighbor not found or not Full, ignore"); continue; } } link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsa->header + sizeof (struct ospf6_lsa_header)); prefix_num = (unsigned short) ntohl (link_lsa->prefix_num); start = (char *) link_lsa + sizeof (struct ospf6_link_lsa); end = (char *) lsa->header + ntohs (lsa->header->length); for (current = start; current < end && prefix_num; current += OSPF6_PREFIX_SIZE (op)) { op = (struct ospf6_prefix *) current; if (op->prefix_length == 0 || current + OSPF6_PREFIX_SIZE (op) > end) break; route = ospf6_route_create (); route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; route->prefix.prefixlen = op->prefix_length; memset (&route->prefix.u.prefix6, 0, sizeof (struct in6_addr)); memcpy (&route->prefix.u.prefix6, OSPF6_PREFIX_BODY (op), OSPF6_PREFIX_SPACE (op->prefix_length)); route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.options[0] = link_lsa->options[0]; route->path.options[1] = link_lsa->options[1]; route->path.options[2] = link_lsa->options[2]; route->path.prefix_options = op->prefix_options; route->path.area_id = oi->area->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug (" include %s", buf); } ospf6_route_add (route, route_advertise); prefix_num--; } if (current != end && IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("Trailing garbage in %s", lsa->name); } op = (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa)); prefix_num = 0; for (route = ospf6_route_head (route_advertise); route; route = ospf6_route_best_next (route)) { op->prefix_length = route->prefix.prefixlen; op->prefix_options = route->path.prefix_options; op->prefix_metric = htons (0); memcpy (OSPF6_PREFIX_BODY (op), &route->prefix.u.prefix6, OSPF6_PREFIX_SPACE (op->prefix_length)); op = OSPF6_PREFIX_NEXT (op); prefix_num++; } ospf6_route_table_delete (route_advertise); if (prefix_num == 0) { if (IS_OSPF6_DEBUG_ORIGINATE (INTRA_PREFIX)) zlog_debug ("Quit to Advertise Intra-Prefix: no route to advertise"); return 0; } intra_prefix_lsa->prefix_num = htons (prefix_num); /* Fill LSA Header */ lsa_header->age = 0; lsa_header->type = htons (OSPF6_LSTYPE_INTRA_PREFIX); lsa_header->id = htonl (oi->interface->ifindex); lsa_header->adv_router = oi->area->ospf6->router_id; lsa_header->seqnum = ospf6_new_ls_seqnum (lsa_header->type, lsa_header->id, lsa_header->adv_router, oi->area->lsdb); lsa_header->length = htons ((caddr_t) op - (caddr_t) lsa_header); /* LSA checksum */ ospf6_lsa_checksum (lsa_header); /* create LSA */ lsa = ospf6_lsa_create (lsa_header); /* Originate */ ospf6_lsa_originate_area (lsa, oi->area); return 0; } void ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa) { struct ospf6_area *oa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct prefix ls_prefix; struct ospf6_route *route, *ls_entry; int i, prefix_num; struct ospf6_prefix *op; char *start, *current, *end; char buf[64]; struct interface *ifp; int direct_connect = 0; if (OSPF6_LSA_IS_MAXAGE (lsa)) return; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("%s found", lsa->name); oa = OSPF6_AREA (lsa->lsdb->data); intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_ROUTER)) ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router, htonl (0), &ls_prefix); else if (intra_prefix_lsa->ref_type == htons (OSPF6_LSTYPE_NETWORK)) ospf6_linkstate_prefix (intra_prefix_lsa->ref_adv_router, intra_prefix_lsa->ref_id, &ls_prefix); else { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Unknown reference LS-type: %#hx", ntohs (intra_prefix_lsa->ref_type)); return; } ls_entry = ospf6_route_lookup (&ls_prefix, oa->spf_table); if (ls_entry == NULL) { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { ospf6_linkstate_prefix2str (&ls_prefix, buf, sizeof (buf)); zlog_debug ("LS entry does not exist: %s", buf); } return; } if (intra_prefix_lsa->ref_adv_router == oa->ospf6->router_id) { /* the intra-prefix are directly connected */ direct_connect = 1; } prefix_num = ntohs (intra_prefix_lsa->prefix_num); start = (caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = OSPF6_LSA_END (lsa->header); for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op)) { op = (struct ospf6_prefix *) current; if (prefix_num == 0) break; if (end < current + OSPF6_PREFIX_SIZE (op)) break; /* Appendix A.4.1.1 */ if (CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_NU) || CHECK_FLAG(op->prefix_options, OSPF6_PREFIX_OPTION_LA)) { if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { ospf6_linkstate_prefix2str ((struct prefix *)OSPF6_PREFIX_BODY(op), buf, sizeof (buf)); zlog_debug ("%s: Skipping Prefix %s has NU/LA option set", __func__, buf); } continue; } route = ospf6_route_create (); memset (&route->prefix, 0, sizeof (struct prefix)); route->prefix.family = AF_INET6; route->prefix.prefixlen = op->prefix_length; ospf6_prefix_in6_addr (&route->prefix.u.prefix6, op); route->type = OSPF6_DEST_TYPE_NETWORK; route->path.origin.type = lsa->header->type; route->path.origin.id = lsa->header->id; route->path.origin.adv_router = lsa->header->adv_router; route->path.prefix_options = op->prefix_options; route->path.area_id = oa->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.metric_type = 1; route->path.cost = ls_entry->path.cost + ntohs (op->prefix_metric); if (direct_connect) { ifp = if_lookup_prefix(&route->prefix); if (ifp) route->nexthop[0].ifindex = ifp->ifindex; } else { for (i = 0; ospf6_nexthop_is_set (&ls_entry->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) ospf6_nexthop_copy (&route->nexthop[i], &ls_entry->nexthop[i]); } if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug (" add %s", buf); } ospf6_route_add (route, oa->route_table); prefix_num--; } if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Trailing garbage ignored"); } void ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa) { struct ospf6_area *oa; struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct prefix prefix; struct ospf6_route *route; int prefix_num; struct ospf6_prefix *op; char *start, *current, *end; char buf[64]; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("%s disappearing", lsa->name); oa = OSPF6_AREA (lsa->lsdb->data); intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) OSPF6_LSA_HEADER_END (lsa->header); prefix_num = ntohs (intra_prefix_lsa->prefix_num); start = (caddr_t) intra_prefix_lsa + sizeof (struct ospf6_intra_prefix_lsa); end = OSPF6_LSA_END (lsa->header); for (current = start; current < end; current += OSPF6_PREFIX_SIZE (op)) { op = (struct ospf6_prefix *) current; if (prefix_num == 0) break; if (end < current + OSPF6_PREFIX_SIZE (op)) break; prefix_num--; memset (&prefix, 0, sizeof (struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = op->prefix_length; ospf6_prefix_in6_addr (&prefix.u.prefix6, op); route = ospf6_route_lookup (&prefix, oa->route_table); if (route == NULL) continue; for (ospf6_route_lock (route); route && ospf6_route_is_prefix (&prefix, route); route = ospf6_route_next (route)) { if (route->type != OSPF6_DEST_TYPE_NETWORK) continue; if (route->path.area_id != oa->area_id) continue; if (route->path.type != OSPF6_PATH_TYPE_INTRA) continue; if (route->path.origin.type != lsa->header->type || route->path.origin.id != lsa->header->id || route->path.origin.adv_router != lsa->header->adv_router) continue; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) { prefix2str (&route->prefix, buf, sizeof (buf)); zlog_debug ("remove %s", buf); } ospf6_route_remove (route, oa->route_table); } if (route) ospf6_route_unlock (route); } if (current != end && IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Trailing garbage ignored"); } void ospf6_intra_route_calculation (struct ospf6_area *oa) { struct ospf6_route *route; u_int16_t type; struct ospf6_lsa *lsa; void (*hook_add) (struct ospf6_route *) = NULL; void (*hook_remove) (struct ospf6_route *) = NULL; if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Re-examin intra-routes for area %s", oa->name); hook_add = oa->route_table->hook_add; hook_remove = oa->route_table->hook_remove; oa->route_table->hook_add = NULL; oa->route_table->hook_remove = NULL; for (route = ospf6_route_head (oa->route_table); route; route = ospf6_route_next (route)) route->flag = OSPF6_ROUTE_REMOVE; type = htons (OSPF6_LSTYPE_INTRA_PREFIX); for (lsa = ospf6_lsdb_type_head (type, oa->lsdb); lsa; lsa = ospf6_lsdb_type_next (type, lsa)) ospf6_intra_prefix_lsa_add (lsa); oa->route_table->hook_add = hook_add; oa->route_table->hook_remove = hook_remove; for (route = ospf6_route_head (oa->route_table); route; route = ospf6_route_next (route)) { if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) && CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD)) { UNSET_FLAG (route->flag, OSPF6_ROUTE_REMOVE); UNSET_FLAG (route->flag, OSPF6_ROUTE_ADD); } if (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE)) ospf6_route_remove (route, oa->route_table); else if (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) || CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE)) { if (hook_add) (*hook_add) (route); } route->flag = 0; } if (IS_OSPF6_DEBUG_EXAMIN (INTRA_PREFIX)) zlog_debug ("Re-examin intra-routes for area %s: Done", oa->name); } static void ospf6_brouter_debug_print (struct ospf6_route *brouter) { u_int32_t brouter_id; char brouter_name[16]; char area_name[16]; char destination[64]; char installed[16], changed[16]; struct timeval now, res; char id[16], adv_router[16]; char capa[16], options[16]; brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); inet_ntop (AF_INET, &brouter->path.area_id, area_name, sizeof (area_name)); ospf6_linkstate_prefix2str (&brouter->prefix, destination, sizeof (destination)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &brouter->installed, &res); timerstring (&res, installed, sizeof (installed)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &brouter->changed, &res); timerstring (&res, changed, sizeof (changed)); inet_ntop (AF_INET, &brouter->path.origin.id, id, sizeof (id)); inet_ntop (AF_INET, &brouter->path.origin.adv_router, adv_router, sizeof (adv_router)); ospf6_options_printbuf (brouter->path.options, options, sizeof (options)); ospf6_capability_printbuf (brouter->path.router_bits, capa, sizeof (capa)); zlog_info ("Brouter: %s via area %s", brouter_name, area_name); zlog_info (" memory: prev: %p this: %p next: %p parent rnode: %p", brouter->prev, brouter, brouter->next, brouter->rnode); zlog_info (" type: %d prefix: %s installed: %s changed: %s", brouter->type, destination, installed, changed); zlog_info (" lock: %d flags: %s%s%s%s", brouter->lock, (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_BEST) ? "B" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) ? "A" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"), (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-")); zlog_info (" path type: %s ls-origin %s id: %s adv-router %s", OSPF6_PATH_TYPE_NAME (brouter->path.type), ospf6_lstype_name (brouter->path.origin.type), id, adv_router); zlog_info (" options: %s router-bits: %s metric-type: %d metric: %d/%d", options, capa, brouter->path.metric_type, brouter->path.cost, brouter->path.cost_e2); } void ospf6_intra_brouter_calculation (struct ospf6_area *oa) { struct ospf6_route *brouter, *copy; void (*hook_add) (struct ospf6_route *) = NULL; void (*hook_remove) (struct ospf6_route *) = NULL; u_int32_t brouter_id; char brouter_name[16]; if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("border-router calculation for area %s", oa->name); hook_add = oa->ospf6->brouter_table->hook_add; hook_remove = oa->ospf6->brouter_table->hook_remove; oa->ospf6->brouter_table->hook_add = NULL; oa->ospf6->brouter_table->hook_remove = NULL; /* withdraw the previous router entries for the area */ for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; brouter = ospf6_route_next (brouter)) { brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->path.area_id != oa->area_id) continue; brouter->flag = OSPF6_ROUTE_REMOVE; if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: mark as removing: area %s brouter %s", brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } for (brouter = ospf6_route_head (oa->spf_table); brouter; brouter = ospf6_route_next (brouter)) { brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->type != OSPF6_DEST_TYPE_LINKSTATE) continue; if (ospf6_linkstate_prefix_id (&brouter->prefix) != htonl (0)) continue; if (! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_E) && ! CHECK_FLAG (brouter->path.router_bits, OSPF6_ROUTER_BIT_B)) continue; if (! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_V6) || ! OSPF6_OPT_ISSET (brouter->path.options, OSPF6_OPT_R)) continue; copy = ospf6_route_copy (brouter); copy->type = OSPF6_DEST_TYPE_ROUTER; copy->path.area_id = oa->area_id; ospf6_route_add (copy, oa->ospf6->brouter_table); if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_ROUTE (MEMORY)) { zlog_info ("%p: transfer: area %s brouter %s", brouter, oa->name, brouter_name); ospf6_brouter_debug_print (brouter); } } oa->ospf6->brouter_table->hook_add = hook_add; oa->ospf6->brouter_table->hook_remove = hook_remove; for (brouter = ospf6_route_head (oa->ospf6->brouter_table); brouter; brouter = ospf6_route_next (brouter)) { brouter_id = ADV_ROUTER_IN_PREFIX (&brouter->prefix); inet_ntop (AF_INET, &brouter_id, brouter_name, sizeof (brouter_name)); if (brouter->path.area_id != oa->area_id) continue; if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_WAS_REMOVED)) continue; if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE) && CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD)) { UNSET_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE); UNSET_FLAG (brouter->flag, OSPF6_ROUTE_ADD); } if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_REMOVE)) { if (IS_OSPF6_DEBUG_BROUTER || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s disappears via area %s", brouter_name, oa->name); ospf6_route_remove (brouter, oa->ospf6->brouter_table); } else if (CHECK_FLAG (brouter->flag, OSPF6_ROUTE_ADD) || CHECK_FLAG (brouter->flag, OSPF6_ROUTE_CHANGE)) { if (IS_OSPF6_DEBUG_BROUTER || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s appears via area %s", brouter_name, oa->name); /* newly added */ if (hook_add) (*hook_add) (brouter); } else { if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID (brouter_id) || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("brouter %s still exists via area %s", brouter_name, oa->name); } brouter->flag = 0; } if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID (oa->area_id)) zlog_info ("border-router calculation for area %s: done", oa->name); } struct ospf6_lsa_handler router_handler = { OSPF6_LSTYPE_ROUTER, "Router", "Rtr", ospf6_router_lsa_show, ospf6_router_lsa_get_nbr_id }; struct ospf6_lsa_handler network_handler = { OSPF6_LSTYPE_NETWORK, "Network", "Net", ospf6_network_lsa_show, ospf6_network_lsa_get_ar_id }; struct ospf6_lsa_handler link_handler = { OSPF6_LSTYPE_LINK, "Link", "Lnk", ospf6_link_lsa_show, ospf6_link_lsa_get_prefix_str }; struct ospf6_lsa_handler intra_prefix_handler = { OSPF6_LSTYPE_INTRA_PREFIX, "Intra-Prefix", "INP", ospf6_intra_prefix_lsa_show, ospf6_intra_prefix_lsa_get_prefix_str }; void ospf6_intra_init (void) { ospf6_install_lsa_handler (&router_handler); ospf6_install_lsa_handler (&network_handler); ospf6_install_lsa_handler (&link_handler); ospf6_install_lsa_handler (&intra_prefix_handler); } DEFUN (debug_ospf6_brouter, debug_ospf6_brouter_cmd, "debug ospf6 border-routers", DEBUG_STR OSPF6_STR "Debug border router\n" ) { OSPF6_DEBUG_BROUTER_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter, no_debug_ospf6_brouter_cmd, "no debug ospf6 border-routers", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" ) { OSPF6_DEBUG_BROUTER_OFF (); return CMD_SUCCESS; } DEFUN (debug_ospf6_brouter_router, debug_ospf6_brouter_router_cmd, "debug ospf6 border-routers router-id A.B.C.D", DEBUG_STR OSPF6_STR "Debug border router\n" "Debug specific border router\n" "Specify border-router's router-id\n" ) { u_int32_t router_id; inet_pton (AF_INET, argv[0], &router_id); OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON (router_id); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter_router, no_debug_ospf6_brouter_router_cmd, "no debug ospf6 border-routers router-id", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" "Debug specific border router\n" ) { OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF (); return CMD_SUCCESS; } DEFUN (debug_ospf6_brouter_area, debug_ospf6_brouter_area_cmd, "debug ospf6 border-routers area-id A.B.C.D", DEBUG_STR OSPF6_STR "Debug border router\n" "Debug border routers in specific Area\n" "Specify Area-ID\n" ) { u_int32_t area_id; inet_pton (AF_INET, argv[0], &area_id); OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON (area_id); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_brouter_area, no_debug_ospf6_brouter_area_cmd, "no debug ospf6 border-routers area-id", NO_STR DEBUG_STR OSPF6_STR "Debug border router\n" "Debug border routers in specific Area\n" ) { OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_brouter (struct vty *vty) { char buf[16]; if (IS_OSPF6_DEBUG_BROUTER) vty_out (vty, "debug ospf6 border-routers%s", VNL); if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) { inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_router_id, buf, sizeof (buf)); vty_out (vty, "debug ospf6 border-routers router-id %s%s", buf, VNL); } if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) { inet_ntop (AF_INET, &conf_debug_ospf6_brouter_specific_area_id, buf, sizeof (buf)); vty_out (vty, "debug ospf6 border-routers area-id %s%s", buf, VNL); } return 0; } void install_element_ospf6_debug_brouter (void) { install_element (ENABLE_NODE, &debug_ospf6_brouter_cmd); install_element (ENABLE_NODE, &debug_ospf6_brouter_router_cmd); install_element (ENABLE_NODE, &debug_ospf6_brouter_area_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_router_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_brouter_area_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_router_cmd); install_element (CONFIG_NODE, &debug_ospf6_brouter_area_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_router_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_brouter_area_cmd); } quagga-0.99.24.1/ospf6d/ospf6_route.c0000644000175000017500000011437012476520570014062 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "command.h" #include "linklist.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_route = 0; static char * ospf6_route_table_name (struct ospf6_route_table *table) { static char name[32]; switch (table->scope_type) { case OSPF6_SCOPE_TYPE_GLOBAL: { switch (table->table_type) { case OSPF6_TABLE_TYPE_ROUTES: snprintf (name, sizeof (name), "global route table"); break; case OSPF6_TABLE_TYPE_BORDER_ROUTERS: snprintf (name, sizeof (name), "global brouter table"); break; case OSPF6_TABLE_TYPE_EXTERNAL_ROUTES: snprintf (name, sizeof (name), "global external table"); break; default: snprintf (name, sizeof (name), "global unknown table"); break; } } break; case OSPF6_SCOPE_TYPE_AREA: { struct ospf6_area *oa = (struct ospf6_area *) table->scope; switch (table->table_type) { case OSPF6_TABLE_TYPE_SPF_RESULTS: snprintf (name, sizeof (name), "area %s spf table", oa->name); break; case OSPF6_TABLE_TYPE_ROUTES: snprintf (name, sizeof (name), "area %s route table", oa->name); break; case OSPF6_TABLE_TYPE_PREFIX_RANGES: snprintf (name, sizeof (name), "area %s range table", oa->name); break; case OSPF6_TABLE_TYPE_SUMMARY_PREFIXES: snprintf (name, sizeof (name), "area %s summary prefix table", oa->name); break; case OSPF6_TABLE_TYPE_SUMMARY_ROUTERS: snprintf (name, sizeof (name), "area %s summary router table", oa->name); break; default: snprintf (name, sizeof (name), "area %s unknown table", oa->name); break; } } break; case OSPF6_SCOPE_TYPE_INTERFACE: { struct ospf6_interface *oi = (struct ospf6_interface *) table->scope; switch (table->table_type) { case OSPF6_TABLE_TYPE_CONNECTED_ROUTES: snprintf (name, sizeof (name), "interface %s connected table", oi->interface->name); break; default: snprintf (name, sizeof (name), "interface %s unknown table", oi->interface->name); break; } } break; default: { switch (table->table_type) { case OSPF6_TABLE_TYPE_SPF_RESULTS: snprintf (name, sizeof (name), "temporary spf table"); break; default: snprintf (name, sizeof (name), "temporary unknown table"); break; } } break; } return name; } void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, struct prefix *prefix) { memset (prefix, 0, sizeof (struct prefix)); prefix->family = AF_INET6; prefix->prefixlen = 64; memcpy (&prefix->u.prefix6.s6_addr[0], &adv_router, 4); memcpy (&prefix->u.prefix6.s6_addr[4], &id, 4); } void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size) { u_int32_t adv_router, id; char adv_router_str[16], id_str[16]; memcpy (&adv_router, &prefix->u.prefix6.s6_addr[0], 4); memcpy (&id, &prefix->u.prefix6.s6_addr[4], 4); inet_ntop (AF_INET, &adv_router, adv_router_str, sizeof (adv_router_str)); inet_ntop (AF_INET, &id, id_str, sizeof (id_str)); if (ntohl (id)) snprintf (buf, size, "%s Net-ID: %s", adv_router_str, id_str); else snprintf (buf, size, "%s", adv_router_str); } /* Global strings for logging */ const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX] = { "Unknown", "Router", "Network", "Discard", "Linkstate", "AddressRange", }; const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX] = { "?", "R", "N", "D", "L", "A", }; const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX] = { "Unknown", "Intra-Area", "Inter-Area", "External-1", "External-2", }; const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX] = { "??", "IA", "IE", "E1", "E2", }; struct ospf6_route * ospf6_route_create (void) { struct ospf6_route *route; route = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route)); return route; } void ospf6_route_delete (struct ospf6_route *route) { XFREE (MTYPE_OSPF6_ROUTE, route); } struct ospf6_route * ospf6_route_copy (struct ospf6_route *route) { struct ospf6_route *new; new = ospf6_route_create (); memcpy (new, route, sizeof (struct ospf6_route)); new->rnode = NULL; new->prev = NULL; new->next = NULL; new->table = NULL; new->lock = 0; return new; } void ospf6_route_lock (struct ospf6_route *route) { route->lock++; } void ospf6_route_unlock (struct ospf6_route *route) { assert (route->lock > 0); route->lock--; if (route->lock == 0) { /* Can't detach from the table until here because ospf6_route_next () will use the 'route->table' pointer for logging */ route->table = NULL; ospf6_route_delete (route); } } /* Route compare function. If ra is more preferred, it returns less than 0. If rb is more preferred returns greater than 0. Otherwise (neither one is preferred), returns 0 */ static int ospf6_route_cmp (struct ospf6_route *ra, struct ospf6_route *rb) { assert (ospf6_route_is_same (ra, rb)); assert (OSPF6_PATH_TYPE_NONE < ra->path.type && ra->path.type < OSPF6_PATH_TYPE_MAX); assert (OSPF6_PATH_TYPE_NONE < rb->path.type && rb->path.type < OSPF6_PATH_TYPE_MAX); if (ra->type != rb->type) return (ra->type - rb->type); if (ra->path.area_id != rb->path.area_id) return (ntohl (ra->path.area_id) - ntohl (rb->path.area_id)); if (ra->path.type != rb->path.type) return (ra->path.type - rb->path.type); if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) { if (ra->path.cost_e2 != rb->path.cost_e2) return (ra->path.cost_e2 - rb->path.cost_e2); } else { if (ra->path.cost != rb->path.cost) return (ra->path.cost - rb->path.cost); } return 0; } struct ospf6_route * ospf6_route_lookup (struct prefix *prefix, struct ospf6_route_table *table) { struct route_node *node; struct ospf6_route *route; node = route_node_lookup (table->table, prefix); if (node == NULL) return NULL; route = (struct ospf6_route *) node->info; return route; } struct ospf6_route * ospf6_route_lookup_identical (struct ospf6_route *route, struct ospf6_route_table *table) { struct ospf6_route *target; for (target = ospf6_route_lookup (&route->prefix, table); target; target = target->next) { if (ospf6_route_is_identical (target, route)) return target; } return NULL; } struct ospf6_route * ospf6_route_lookup_bestmatch (struct prefix *prefix, struct ospf6_route_table *table) { struct route_node *node; struct ospf6_route *route; node = route_node_match (table->table, prefix); if (node == NULL) return NULL; route_unlock_node (node); route = (struct ospf6_route *) node->info; return route; } #ifdef DEBUG static void route_table_assert (struct ospf6_route_table *table) { struct ospf6_route *prev, *r, *next; char buf[64]; unsigned int link_error = 0, num = 0; r = ospf6_route_head (table); prev = NULL; while (r) { if (r->prev != prev) link_error++; next = ospf6_route_next (r); if (r->next != next) link_error++; prev = r; r = next; } for (r = ospf6_route_head (table); r; r = ospf6_route_next (r)) num++; if (link_error == 0 && num == table->count) return; zlog_err ("PANIC !!"); zlog_err ("Something has gone wrong with ospf6_route_table[%p]", table); zlog_debug ("table count = %d, real number = %d", table->count, num); zlog_debug ("DUMP START"); for (r = ospf6_route_head (table); r; r = ospf6_route_next (r)) { prefix2str (&r->prefix, buf, sizeof (buf)); zlog_info ("%p<-[%p]->%p : %s", r->prev, r, r->next, buf); } zlog_debug ("DUMP END"); assert (link_error == 0 && num == table->count); } #define ospf6_route_table_assert(t) (route_table_assert (t)) #else #define ospf6_route_table_assert(t) ((void) 0) #endif /*DEBUG*/ struct ospf6_route * ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table) { struct route_node *node, *nextnode, *prevnode; struct ospf6_route *current = NULL; struct ospf6_route *prev = NULL, *old = NULL, *next = NULL; char buf[64]; struct timeval now; assert (route->rnode == NULL); assert (route->lock == 0); assert (route->next == NULL); assert (route->prev == NULL); if (route->type == OSPF6_DEST_TYPE_LINKSTATE) ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); else prefix2str (&route->prefix, buf, sizeof (buf)); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: %s", ospf6_route_table_name (table), table, route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: %s", ospf6_route_table_name (table), buf); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); node = route_node_get (table->table, &route->prefix); route->rnode = node; /* find place to insert */ for (current = node->info; current; current = current->next) { if (! ospf6_route_is_same (current, route)) next = current; else if (current->type != route->type) prev = current; else if (ospf6_route_is_same_origin (current, route)) old = current; else if (ospf6_route_cmp (current, route) > 0) next = current; else prev = current; if (old || next) break; } if (old) { /* if route does not actually change, return unchanged */ if (ospf6_route_is_identical (old, route)) { if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: needless update of %p", ospf6_route_table_name (table), table, route, old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: needless update", ospf6_route_table_name (table)); ospf6_route_delete (route); SET_FLAG (old->flag, OSPF6_ROUTE_ADD); ospf6_route_table_assert (table); return old; } if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: update of %p", ospf6_route_table_name (table), table, route, old); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: update", ospf6_route_table_name (table)); /* replace old one if exists */ if (node->info == old) { node->info = route; SET_FLAG (route->flag, OSPF6_ROUTE_BEST); } if (old->prev) old->prev->next = route; route->prev = old->prev; if (old->next) old->next->prev = route; route->next = old->next; route->installed = old->installed; route->changed = now; assert (route->table == NULL); route->table = table; ospf6_route_unlock (old); /* will be deleted later */ ospf6_route_lock (route); SET_FLAG (route->flag, OSPF6_ROUTE_CHANGE); ospf6_route_table_assert (table); if (table->hook_add) (*table->hook_add) (route); return route; } /* insert if previous or next node found */ if (prev || next) { if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: another path: prev %p, next %p", ospf6_route_table_name (table), table, route, prev, next); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: another path found", ospf6_route_table_name (table)); if (prev == NULL) prev = next->prev; if (next == NULL) next = prev->next; if (prev) prev->next = route; route->prev = prev; if (next) next->prev = route; route->next = next; if (node->info == next) { assert (next->rnode == node); node->info = route; UNSET_FLAG (next->flag, OSPF6_ROUTE_BEST); SET_FLAG (route->flag, OSPF6_ROUTE_BEST); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route add %p: replacing previous best: %p", ospf6_route_table_name (table), table, route, next); } route->installed = now; route->changed = now; assert (route->table == NULL); route->table = table; ospf6_route_lock (route); table->count++; ospf6_route_table_assert (table); SET_FLAG (route->flag, OSPF6_ROUTE_ADD); if (table->hook_add) (*table->hook_add) (route); return route; } /* Else, this is the brand new route regarding to the prefix */ if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route add %p: brand new route", ospf6_route_table_name (table), table, route); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route add: brand new route", ospf6_route_table_name (table)); assert (node->info == NULL); node->info = route; SET_FLAG (route->flag, OSPF6_ROUTE_BEST); ospf6_route_lock (route); route->installed = now; route->changed = now; assert (route->table == NULL); route->table = table; /* lookup real existing next route */ nextnode = node; route_lock_node (nextnode); do { nextnode = route_next (nextnode); } while (nextnode && nextnode->info == NULL); /* set next link */ if (nextnode == NULL) route->next = NULL; else { route_unlock_node (nextnode); next = nextnode->info; route->next = next; next->prev = route; } /* lookup real existing prev route */ prevnode = node; route_lock_node (prevnode); do { prevnode = route_prev (prevnode); } while (prevnode && prevnode->info == NULL); /* set prev link */ if (prevnode == NULL) route->prev = NULL; else { route_unlock_node (prevnode); prev = prevnode->info; while (prev->next && ospf6_route_is_same (prev, prev->next)) prev = prev->next; route->prev = prev; prev->next = route; } table->count++; ospf6_route_table_assert (table); SET_FLAG (route->flag, OSPF6_ROUTE_ADD); if (table->hook_add) (*table->hook_add) (route); return route; } void ospf6_route_remove (struct ospf6_route *route, struct ospf6_route_table *table) { struct route_node *node; struct ospf6_route *current; char buf[64]; if (route->type == OSPF6_DEST_TYPE_LINKSTATE) ospf6_linkstate_prefix2str (&route->prefix, buf, sizeof (buf)); else prefix2str (&route->prefix, buf, sizeof (buf)); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_debug ("%s %p: route remove %p: %s", ospf6_route_table_name (table), table, route, buf); else if (IS_OSPF6_DEBUG_ROUTE (TABLE)) zlog_debug ("%s: route remove: %s", ospf6_route_table_name (table), buf); node = route_node_lookup (table->table, &route->prefix); assert (node); /* find the route to remove, making sure that the route pointer is from the route table. */ current = node->info; while (current && ospf6_route_is_same (current, route)) { if (current == route) break; current = current->next; } assert (current == route); /* adjust doubly linked list */ if (route->prev) route->prev->next = route->next; if (route->next) route->next->prev = route->prev; if (node->info == route) { if (route->next && ospf6_route_is_same (route->next, route)) { node->info = route->next; SET_FLAG (route->next->flag, OSPF6_ROUTE_BEST); } else node->info = NULL; /* should unlock route_node here ? */ } table->count--; ospf6_route_table_assert (table); SET_FLAG (route->flag, OSPF6_ROUTE_WAS_REMOVED); if (table->hook_remove) (*table->hook_remove) (route); ospf6_route_unlock (route); } struct ospf6_route * ospf6_route_head (struct ospf6_route_table *table) { struct route_node *node; struct ospf6_route *route; node = route_top (table->table); if (node == NULL) return NULL; /* skip to the real existing entry */ while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; route_unlock_node (node); assert (node->info); route = (struct ospf6_route *) node->info; assert (route->prev == NULL); assert (route->table == table); ospf6_route_lock (route); if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route head: %p<-[%p]->%p", ospf6_route_table_name (table), table, route->prev, route, route->next); return route; } struct ospf6_route * ospf6_route_next (struct ospf6_route *route) { struct ospf6_route *next = route->next; if (IS_OSPF6_DEBUG_ROUTE (MEMORY)) zlog_info ("%s %p: route next: %p<-[%p]->%p", ospf6_route_table_name (route->table), route->table, route->prev, route, route->next); ospf6_route_unlock (route); if (next) ospf6_route_lock (next); return next; } struct ospf6_route * ospf6_route_best_next (struct ospf6_route *route) { struct route_node *rnode; struct ospf6_route *next; ospf6_route_unlock (route); rnode = route->rnode; route_lock_node (rnode); rnode = route_next (rnode); while (rnode && rnode->info == NULL) rnode = route_next (rnode); if (rnode == NULL) return NULL; route_unlock_node (rnode); assert (rnode->info); next = (struct ospf6_route *) rnode->info; ospf6_route_lock (next); return next; } struct ospf6_route * ospf6_route_match_head (struct prefix *prefix, struct ospf6_route_table *table) { struct route_node *node; struct ospf6_route *route; /* Walk down tree. */ node = table->table->top; while (node && node->p.prefixlen < prefix->prefixlen && prefix_match (&node->p, prefix)) node = node->link[prefix_bit(&prefix->u.prefix, node->p.prefixlen)]; if (node) route_lock_node (node); while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; route_unlock_node (node); if (! prefix_match (prefix, &node->p)) return NULL; route = node->info; ospf6_route_lock (route); return route; } struct ospf6_route * ospf6_route_match_next (struct prefix *prefix, struct ospf6_route *route) { struct ospf6_route *next; next = ospf6_route_next (route); if (next && ! prefix_match (prefix, &next->prefix)) { ospf6_route_unlock (next); next = NULL; } return next; } void ospf6_route_remove_all (struct ospf6_route_table *table) { struct ospf6_route *route; for (route = ospf6_route_head (table); route; route = ospf6_route_next (route)) ospf6_route_remove (route, table); } struct ospf6_route_table * ospf6_route_table_create (int s, int t) { struct ospf6_route_table *new; new = XCALLOC (MTYPE_OSPF6_ROUTE, sizeof (struct ospf6_route_table)); new->table = route_table_init (); new->scope_type = s; new->table_type = t; return new; } void ospf6_route_table_delete (struct ospf6_route_table *table) { ospf6_route_remove_all (table); route_table_finish (table->table); XFREE (MTYPE_OSPF6_ROUTE, table); } /* VTY commands */ void ospf6_route_show (struct vty *vty, struct ospf6_route *route) { int i; char destination[64], nexthop[64]; char duration[16], ifname[IFNAMSIZ]; struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &route->changed, &res); timerstring (&res, duration, sizeof (duration)); /* destination */ if (route->type == OSPF6_DEST_TYPE_LINKSTATE) ospf6_linkstate_prefix2str (&route->prefix, destination, sizeof (destination)); else if (route->type == OSPF6_DEST_TYPE_ROUTER) inet_ntop (route->prefix.family, &route->prefix.u.prefix, destination, sizeof (destination)); else prefix2str (&route->prefix, destination, sizeof (destination)); /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[0].address, nexthop, sizeof (nexthop)); if (! if_indextoname (route->nexthop[0].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[0].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", (ospf6_route_is_best (route) ? '*' : ' '), OSPF6_DEST_TYPE_SUBSTR (route->type), OSPF6_PATH_TYPE_SUBSTR (route->path.type), destination, nexthop, IFNAMSIZ, ifname, duration, VNL); for (i = 1; ospf6_nexthop_is_set (&route->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); if (! if_indextoname (route->nexthop[i].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); vty_out (vty, "%c%1s %2s %-30s %-25s %6.*s %s%s", ' ', "", "", "", nexthop, IFNAMSIZ, ifname, "", VNL); } } void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route) { char destination[64], nexthop[64], ifname[IFNAMSIZ]; char area_id[16], id[16], adv_router[16], capa[16], options[16]; struct timeval now, res; char duration[16]; int i; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); /* destination */ if (route->type == OSPF6_DEST_TYPE_LINKSTATE) ospf6_linkstate_prefix2str (&route->prefix, destination, sizeof (destination)); else if (route->type == OSPF6_DEST_TYPE_ROUTER) inet_ntop (route->prefix.family, &route->prefix.u.prefix, destination, sizeof (destination)); else prefix2str (&route->prefix, destination, sizeof (destination)); vty_out (vty, "Destination: %s%s", destination, VNL); /* destination type */ vty_out (vty, "Destination type: %s%s", OSPF6_DEST_TYPE_NAME (route->type), VNL); /* Time */ timersub (&now, &route->installed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, "Installed Time: %s ago%s", duration, VNL); timersub (&now, &route->changed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " Changed Time: %s ago%s", duration, VNL); /* Debugging info */ vty_out (vty, "Lock: %d Flags: %s%s%s%s%s", route->lock, (CHECK_FLAG (route->flag, OSPF6_ROUTE_BEST) ? "B" : "-"), (CHECK_FLAG (route->flag, OSPF6_ROUTE_ADD) ? "A" : "-"), (CHECK_FLAG (route->flag, OSPF6_ROUTE_REMOVE) ? "R" : "-"), (CHECK_FLAG (route->flag, OSPF6_ROUTE_CHANGE) ? "C" : "-"), VNL); vty_out (vty, "Memory: prev: %p this: %p next: %p%s", route->prev, route, route->next, VNL); /* Path section */ /* Area-ID */ inet_ntop (AF_INET, &route->path.area_id, area_id, sizeof (area_id)); vty_out (vty, "Associated Area: %s%s", area_id, VNL); /* Path type */ vty_out (vty, "Path Type: %s%s", OSPF6_PATH_TYPE_NAME (route->path.type), VNL); /* LS Origin */ inet_ntop (AF_INET, &route->path.origin.id, id, sizeof (id)); inet_ntop (AF_INET, &route->path.origin.adv_router, adv_router, sizeof (adv_router)); vty_out (vty, "LS Origin: %s Id: %s Adv: %s%s", ospf6_lstype_name (route->path.origin.type), id, adv_router, VNL); /* Options */ ospf6_options_printbuf (route->path.options, options, sizeof (options)); vty_out (vty, "Options: %s%s", options, VNL); /* Router Bits */ ospf6_capability_printbuf (route->path.router_bits, capa, sizeof (capa)); vty_out (vty, "Router Bits: %s%s", capa, VNL); /* Prefix Options */ vty_out (vty, "Prefix Options: xxx%s", VNL); /* Metrics */ vty_out (vty, "Metric Type: %d%s", route->path.metric_type, VNL); vty_out (vty, "Metric: %d (%d)%s", route->path.cost, route->path.cost_e2, VNL); /* Nexthops */ vty_out (vty, "Nexthop:%s", VNL); for (i = 0; ospf6_nexthop_is_set (&route->nexthop[i]) && i < OSPF6_MULTI_PATH_LIMIT; i++) { /* nexthop */ inet_ntop (AF_INET6, &route->nexthop[i].address, nexthop, sizeof (nexthop)); if (! if_indextoname (route->nexthop[i].ifindex, ifname)) snprintf (ifname, sizeof (ifname), "%d", route->nexthop[i].ifindex); vty_out (vty, " %s %.*s%s", nexthop, IFNAMSIZ, ifname, VNL); } vty_out (vty, "%s", VNL); } static void ospf6_route_show_table_summary (struct vty *vty, struct ospf6_route_table *table) { struct ospf6_route *route, *prev = NULL; int i, pathtype[OSPF6_PATH_TYPE_MAX]; unsigned int number = 0; int nhinval = 0, ecmp = 0; int alternative = 0, destination = 0; for (i = 0; i < OSPF6_PATH_TYPE_MAX; i++) pathtype[i] = 0; for (route = ospf6_route_head (table); route; route = ospf6_route_next (route)) { if (prev == NULL || ! ospf6_route_is_same (prev, route)) destination++; else alternative++; if (! ospf6_nexthop_is_set (&route->nexthop[0])) nhinval++; else if (ospf6_nexthop_is_set (&route->nexthop[1])) ecmp++; pathtype[route->path.type]++; number++; prev = route; } assert (number == table->count); vty_out (vty, "Number of OSPFv3 routes: %d%s", number, VNL); vty_out (vty, "Number of Destination: %d%s", destination, VNL); vty_out (vty, "Number of Alternative routes: %d%s", alternative, VNL); vty_out (vty, "Number of Equal Cost Multi Path: %d%s", ecmp, VNL); for (i = OSPF6_PATH_TYPE_INTRA; i <= OSPF6_PATH_TYPE_EXTERNAL2; i++) { vty_out (vty, "Number of %s routes: %d%s", OSPF6_PATH_TYPE_NAME (i), pathtype[i], VNL); } } static void ospf6_route_show_table_prefix (struct vty *vty, struct prefix *prefix, struct ospf6_route_table *table) { struct ospf6_route *route; route = ospf6_route_lookup (prefix, table); if (route == NULL) return; ospf6_route_lock (route); while (route && ospf6_route_is_prefix (prefix, route)) { /* Specifying a prefix will always display details */ ospf6_route_show_detail (vty, route); route = ospf6_route_next (route); } if (route) ospf6_route_unlock (route); } static void ospf6_route_show_table_address (struct vty *vty, struct prefix *prefix, struct ospf6_route_table *table) { struct ospf6_route *route; route = ospf6_route_lookup_bestmatch (prefix, table); if (route == NULL) return; prefix = &route->prefix; ospf6_route_lock (route); while (route && ospf6_route_is_prefix (prefix, route)) { /* Specifying a prefix will always display details */ ospf6_route_show_detail (vty, route); route = ospf6_route_next (route); } if (route) ospf6_route_unlock (route); } static void ospf6_route_show_table_match (struct vty *vty, int detail, struct prefix *prefix, struct ospf6_route_table *table) { struct ospf6_route *route; assert (prefix->family); route = ospf6_route_match_head (prefix, table); while (route) { if (detail) ospf6_route_show_detail (vty, route); else ospf6_route_show (vty, route); route = ospf6_route_match_next (prefix, route); } } static void ospf6_route_show_table_type (struct vty *vty, int detail, u_char type, struct ospf6_route_table *table) { struct ospf6_route *route; route = ospf6_route_head (table); while (route) { if (route->path.type == type) { if (detail) ospf6_route_show_detail (vty, route); else ospf6_route_show (vty, route); } route = ospf6_route_next (route); } } static void ospf6_route_show_table (struct vty *vty, int detail, struct ospf6_route_table *table) { struct ospf6_route *route; route = ospf6_route_head (table); while (route) { if (detail) ospf6_route_show_detail (vty, route); else ospf6_route_show (vty, route); route = ospf6_route_next (route); } } int ospf6_route_table_show (struct vty *vty, int argc, const char *argv[], struct ospf6_route_table *table) { int summary = 0; int match = 0; int detail = 0; int slash = 0; int isprefix = 0; int i, ret; struct prefix prefix; u_char type = 0; memset (&prefix, 0, sizeof (struct prefix)); for (i = 0; i < argc; i++) { if (! strcmp (argv[i], "summary")) { summary++; continue; } if (! strcmp (argv[i], "intra-area")) { type = OSPF6_PATH_TYPE_INTRA; continue; } if (! strcmp (argv[i], "inter-area")) { type = OSPF6_PATH_TYPE_INTER; continue; } if (! strcmp (argv[i], "external-1")) { type = OSPF6_PATH_TYPE_EXTERNAL1; continue; } if (! strcmp (argv[i], "external-2")) { type = OSPF6_PATH_TYPE_EXTERNAL2; continue; } if (! strcmp (argv[i], "detail")) { detail++; continue; } if (! strcmp (argv[i], "match")) { match++; continue; } ret = str2prefix (argv[i], &prefix); if (ret == 1 && prefix.family == AF_INET6) { isprefix++; if (strchr (argv[i], '/')) slash++; continue; } vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); return CMD_SUCCESS; } /* Give summary of this route table */ if (summary) { ospf6_route_show_table_summary (vty, table); return CMD_SUCCESS; } /* Give exact prefix-match route */ if (isprefix && ! match) { /* If exact address, give best matching route */ if (! slash) ospf6_route_show_table_address (vty, &prefix, table); else ospf6_route_show_table_prefix (vty, &prefix, table); return CMD_SUCCESS; } if (match) ospf6_route_show_table_match (vty, detail, &prefix, table); else if (type) ospf6_route_show_table_type (vty, detail, type, table); else ospf6_route_show_table (vty, detail, table); return CMD_SUCCESS; } static void ospf6_linkstate_show_header (struct vty *vty) { vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %s%s", "Type", "Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost", VNL); } static void ospf6_linkstate_show (struct vty *vty, struct ospf6_route *route) { u_int32_t router, id; char routername[16], idname[16], rbits[16], options[16]; router = ospf6_linkstate_prefix_adv_router (&route->prefix); inet_ntop (AF_INET, &router, routername, sizeof (routername)); id = ospf6_linkstate_prefix_id (&route->prefix); inet_ntop (AF_INET, &id, idname, sizeof (idname)); ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); ospf6_options_printbuf (route->path.options, options, sizeof (options)); if (ntohl (id)) vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", "Network", routername, idname, rbits, options, (unsigned long) route->path.cost, VNL); else vty_out (vty, "%-7s %-15s %-15s %-8s %-14s %lu%s", "Router", routername, idname, rbits, options, (unsigned long) route->path.cost, VNL); } static void ospf6_linkstate_show_table_exact (struct vty *vty, struct prefix *prefix, struct ospf6_route_table *table) { struct ospf6_route *route; route = ospf6_route_lookup (prefix, table); if (route == NULL) return; ospf6_route_lock (route); while (route && ospf6_route_is_prefix (prefix, route)) { /* Specifying a prefix will always display details */ ospf6_route_show_detail (vty, route); route = ospf6_route_next (route); } if (route) ospf6_route_unlock (route); } static void ospf6_linkstate_show_table (struct vty *vty, int detail, struct ospf6_route_table *table) { struct ospf6_route *route; if (! detail) ospf6_linkstate_show_header (vty); route = ospf6_route_head (table); while (route) { if (detail) ospf6_route_show_detail (vty, route); else ospf6_linkstate_show (vty, route); route = ospf6_route_next (route); } } int ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[], struct ospf6_route_table *table) { int detail = 0; int is_id = 0; int is_router = 0; int i, ret; struct prefix router, id, prefix; memset (&router, 0, sizeof (struct prefix)); memset (&id, 0, sizeof (struct prefix)); memset (&prefix, 0, sizeof (struct prefix)); for (i = 0; i < argc; i++) { if (! strcmp (argv[i], "detail")) { detail++; continue; } if (! is_router) { ret = str2prefix (argv[i], &router); if (ret == 1 && router.family == AF_INET) { is_router++; continue; } vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); return CMD_SUCCESS; } if (! is_id) { ret = str2prefix (argv[i], &id); if (ret == 1 && id.family == AF_INET) { is_id++; continue; } vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); return CMD_SUCCESS; } vty_out (vty, "Malformed argument: %s%s", argv[i], VNL); return CMD_SUCCESS; } if (is_router) ospf6_linkstate_prefix (router.u.prefix4.s_addr, id.u.prefix4.s_addr, &prefix); if (prefix.family) ospf6_linkstate_show_table_exact (vty, &prefix, table); else ospf6_linkstate_show_table (vty, detail, table); return CMD_SUCCESS; } void ospf6_brouter_show_header (struct vty *vty) { vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); } void ospf6_brouter_show (struct vty *vty, struct ospf6_route *route) { u_int32_t adv_router; char adv[16], rbits[16], options[16], area[16]; adv_router = ospf6_linkstate_prefix_adv_router (&route->prefix); inet_ntop (AF_INET, &adv_router, adv, sizeof (adv)); ospf6_capability_printbuf (route->path.router_bits, rbits, sizeof (rbits)); ospf6_options_printbuf (route->path.options, options, sizeof (options)); inet_ntop (AF_INET, &route->path.area_id, area, sizeof (area)); /* vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", "Router-ID", "Rtr-Bits", "Options", "Path-Type", "Area", VNL); */ vty_out (vty, "%-15s %-8s %-14s %-10s %-15s%s", adv, rbits, options, OSPF6_PATH_TYPE_NAME (route->path.type), area, VNL); } DEFUN (debug_ospf6_route, debug_ospf6_route_cmd, "debug ospf6 route (table|intra-area|inter-area|memory)", DEBUG_STR OSPF6_STR "Debug route table calculation\n" "Debug detail\n" "Debug intra-area route calculation\n" "Debug inter-area route calculation\n" "Debug route memory use\n" ) { unsigned char level = 0; if (! strncmp (argv[0], "table", 5)) level = OSPF6_DEBUG_ROUTE_TABLE; else if (! strncmp (argv[0], "intra", 5)) level = OSPF6_DEBUG_ROUTE_INTRA; else if (! strncmp (argv[0], "inter", 5)) level = OSPF6_DEBUG_ROUTE_INTER; else if (! strncmp (argv[0], "memor", 5)) level = OSPF6_DEBUG_ROUTE_MEMORY; OSPF6_DEBUG_ROUTE_ON (level); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_route, no_debug_ospf6_route_cmd, "no debug ospf6 route (table|intra-area|inter-area|memory)", NO_STR DEBUG_STR OSPF6_STR "Debug route table calculation\n" "Debug intra-area route calculation\n" "Debug route memory use\n") { unsigned char level = 0; if (! strncmp (argv[0], "table", 5)) level = OSPF6_DEBUG_ROUTE_TABLE; else if (! strncmp (argv[0], "intra", 5)) level = OSPF6_DEBUG_ROUTE_INTRA; else if (! strncmp (argv[0], "inter", 5)) level = OSPF6_DEBUG_ROUTE_INTER; else if (! strncmp (argv[0], "memor", 5)) level = OSPF6_DEBUG_ROUTE_MEMORY; OSPF6_DEBUG_ROUTE_OFF (level); return CMD_SUCCESS; } int config_write_ospf6_debug_route (struct vty *vty) { if (IS_OSPF6_DEBUG_ROUTE (TABLE)) vty_out (vty, "debug ospf6 route table%s", VNL); if (IS_OSPF6_DEBUG_ROUTE (INTRA)) vty_out (vty, "debug ospf6 route intra-area%s", VNL); if (IS_OSPF6_DEBUG_ROUTE (INTER)) vty_out (vty, "debug ospf6 route inter-area%s", VNL); return 0; } void install_element_ospf6_debug_route (void) { install_element (ENABLE_NODE, &debug_ospf6_route_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_route_cmd); install_element (CONFIG_NODE, &debug_ospf6_route_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_route_cmd); } quagga-0.99.24.1/ospf6d/ospf6_flood.c0000644000175000017500000007546112476520570014036 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "command.h" #include "ospf6d.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_spf.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_flood.h" unsigned char conf_debug_ospf6_flooding; struct ospf6_lsdb * ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa) { struct ospf6_lsdb *lsdb = NULL; switch (OSPF6_LSA_SCOPE (lsa->header->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb; break; case OSPF6_SCOPE_AREA: lsdb = OSPF6_AREA (lsa->lsdb->data)->lsdb; break; case OSPF6_SCOPE_AS: lsdb = OSPF6_PROCESS (lsa->lsdb->data)->lsdb; break; default: assert (0); break; } return lsdb; } struct ospf6_lsdb * ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa) { struct ospf6_lsdb *lsdb_self = NULL; switch (OSPF6_LSA_SCOPE (lsa->header->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb_self = OSPF6_INTERFACE (lsa->lsdb->data)->lsdb_self; break; case OSPF6_SCOPE_AREA: lsdb_self = OSPF6_AREA (lsa->lsdb->data)->lsdb_self; break; case OSPF6_SCOPE_AS: lsdb_self = OSPF6_PROCESS (lsa->lsdb->data)->lsdb_self; break; default: assert (0); break; } return lsdb_self; } void ospf6_lsa_originate (struct ospf6_lsa *lsa) { struct ospf6_lsa *old; struct ospf6_lsdb *lsdb_self; /* find previous LSA */ old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsa->lsdb); /* if the new LSA does not differ from previous, suppress this update of the LSA */ if (old && ! OSPF6_LSA_IS_DIFFER (lsa, old)) { if (IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) zlog_debug ("Suppress updating LSA: %s", lsa->name); ospf6_lsa_delete (lsa); return; } /* store it in the LSDB for self-originated LSAs */ lsdb_self = ospf6_get_scoped_lsdb_self (lsa); ospf6_lsdb_add (ospf6_lsa_copy (lsa), lsdb_self); lsa->refresh = thread_add_timer (master, ospf6_lsa_refresh, lsa, OSPF_LS_REFRESH_TIME); if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_ORIGINATE_TYPE (lsa->header->type)) { zlog_debug ("LSA Originate:"); ospf6_lsa_header_print (lsa); } ospf6_install_lsa (lsa); ospf6_flood (NULL, lsa); } void ospf6_lsa_originate_process (struct ospf6_lsa *lsa, struct ospf6 *process) { lsa->lsdb = process->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_originate_area (struct ospf6_lsa *lsa, struct ospf6_area *oa) { lsa->lsdb = oa->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi) { lsa->lsdb = oi->lsdb; ospf6_lsa_originate (lsa); } void ospf6_lsa_purge (struct ospf6_lsa *lsa) { struct ospf6_lsa *self; struct ospf6_lsdb *lsdb_self; /* remove it from the LSDB for self-originated LSAs */ lsdb_self = ospf6_get_scoped_lsdb_self (lsa); self = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb_self); if (self) { THREAD_OFF (self->expire); THREAD_OFF (self->refresh); ospf6_lsdb_remove (self, lsdb_self); } ospf6_lsa_premature_aging (lsa); } void ospf6_increment_retrans_count (struct ospf6_lsa *lsa) { /* The LSA must be the original one (see the description in ospf6_decrement_retrans_count () below) */ lsa->retrans_count++; } void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa) { struct ospf6_lsdb *lsdb; struct ospf6_lsa *orig; /* The LSA must be on the retrans-list of a neighbor. It means the "lsa" is a copied one, and we have to decrement the retransmission count of the original one (instead of this "lsa"'s). In order to find the original LSA, first we have to find appropriate LSDB that have the original LSA. */ lsdb = ospf6_get_scoped_lsdb (lsa); /* Find the original LSA of which the retrans_count should be decremented */ orig = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsdb); if (orig) { orig->retrans_count--; assert (orig->retrans_count >= 0); } } /* RFC2328 section 13.2 Installing LSAs in the database */ void ospf6_install_lsa (struct ospf6_lsa *lsa) { struct timeval now; struct ospf6_lsa *old; if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type) || IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) zlog_debug ("Install LSA: %s", lsa->name); /* Remove the old instance from all neighbors' Link state retransmission list (RFC2328 13.2 last paragraph) */ old = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsa->lsdb); if (old) { THREAD_OFF (old->expire); THREAD_OFF (old->refresh); ospf6_flood_clear (old); } quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (! OSPF6_LSA_IS_MAXAGE (lsa)) lsa->expire = thread_add_timer (master, ospf6_lsa_expire, lsa, OSPF_LSA_MAXAGE + lsa->birth.tv_sec - now.tv_sec); else lsa->expire = NULL; if (OSPF6_LSA_IS_SEQWRAP(lsa) && ! (CHECK_FLAG(lsa->flag,OSPF6_LSA_SEQWRAPPED) && lsa->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))) { if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) zlog_debug("lsa install wrapping: sequence 0x%x", ntohl(lsa->header->seqnum)); SET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); /* in lieu of premature_aging, since we do not want to recreate this lsa * and/or mess with timers etc, we just want to wrap the sequence number * and reflood the lsa before continuing. * NOTE: Flood needs to be called right after this function call, by the * caller */ lsa->header->seqnum = htonl (OSPF_MAX_SEQUENCE_NUMBER); lsa->header->age = htons (OSPF_LSA_MAXAGE); ospf6_lsa_checksum (lsa->header); } /* actually install */ lsa->installed = now; ospf6_lsdb_add (lsa, lsa->lsdb); return; } /* RFC2740 section 3.5.2. Sending Link State Update packets */ /* RFC2328 section 13.3 Next step in the flooding procedure */ static void ospf6_flood_interface (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; struct ospf6_lsa *req; int retrans_added = 0; int is_debug = 0; if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) { is_debug++; zlog_debug ("Flooding on %s: %s", oi->interface->name, lsa->name); } /* (1) For each neighbor */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { if (is_debug) zlog_debug ("To neighbor %s", on->name); /* (a) if neighbor state < Exchange, examin next */ if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (is_debug) zlog_debug ("Neighbor state less than ExChange, next neighbor"); continue; } /* (b) if neighbor not yet Full, check request-list */ if (on->state != OSPF6_NEIGHBOR_FULL) { if (is_debug) zlog_debug ("Neighbor not yet Full"); req = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, on->request_list); if (req == NULL) { if (is_debug) zlog_debug ("Not on request-list for this neighbor"); /* fall through */ } else { /* If new LSA less recent, examin next neighbor */ if (ospf6_lsa_compare (lsa, req) > 0) { if (is_debug) zlog_debug ("Requesting is older, next neighbor"); continue; } /* If the same instance, delete from request-list and examin next neighbor */ if (ospf6_lsa_compare (lsa, req) == 0) { if (is_debug) zlog_debug ("Requesting the same, remove it, next neighbor"); if (req == on->last_ls_req) { ospf6_lsa_unlock (req); on->last_ls_req = NULL; } ospf6_lsdb_remove (req, on->request_list); ospf6_check_nbr_loading (on); continue; } /* If the new LSA is more recent, delete from request-list */ if (ospf6_lsa_compare (lsa, req) < 0) { if (is_debug) zlog_debug ("Received is newer, remove requesting"); if (req == on->last_ls_req) { ospf6_lsa_unlock (req); on->last_ls_req = NULL; } ospf6_lsdb_remove (req, on->request_list); ospf6_check_nbr_loading (on); /* fall through */ } } } /* (c) If the new LSA was received from this neighbor, examin next neighbor */ if (from == on) { if (is_debug) zlog_debug ("Received is from the neighbor, next neighbor"); continue; } /* (d) add retrans-list, schedule retransmission */ if (is_debug) zlog_debug ("Add retrans-list of this neighbor"); ospf6_increment_retrans_count (lsa); ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); if (on->thread_send_lsupdate == NULL) on->thread_send_lsupdate = thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, on->ospf6_if->rxmt_interval); retrans_added++; } /* (2) examin next interface if not added to retrans-list */ if (retrans_added == 0) { if (is_debug) zlog_debug ("No retransmission scheduled, next interface"); return; } /* (3) If the new LSA was received on this interface, and it was from DR or BDR, examin next interface */ if (from && from->ospf6_if == oi && (from->router_id == oi->drouter || from->router_id == oi->bdrouter)) { if (is_debug) zlog_debug ("Received is from the I/F's DR or BDR, next interface"); return; } /* (4) If the new LSA was received on this interface, and the interface state is BDR, examin next interface */ if (from && from->ospf6_if == oi) { if (oi->state == OSPF6_INTERFACE_BDR) { if (is_debug) zlog_debug ("Received is from the I/F, itself BDR, next interface"); return; } SET_FLAG(lsa->flag, OSPF6_LSA_FLOODBACK); } /* (5) flood the LSA out the interface. */ if (is_debug) zlog_debug ("Schedule flooding for the interface"); if ((oi->type == OSPF_IFTYPE_BROADCAST) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsupdate_list); if (oi->thread_send_lsupdate == NULL) oi->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); } else { /* reschedule retransmissions to all neighbors */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { THREAD_OFF (on->thread_send_lsupdate); on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } } } static void ospf6_flood_area (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && oi != OSPF6_INTERFACE (lsa->lsdb->data)) continue; #if 0 if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && ospf6_is_interface_virtual_link (oi)) continue; #endif/*0*/ ospf6_flood_interface (from, lsa, oi); } } static void ospf6_flood_process (struct ospf6_neighbor *from, struct ospf6_lsa *lsa, struct ospf6 *process) { struct listnode *node, *nnode; struct ospf6_area *oa; for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa)) { if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA && oa != OSPF6_AREA (lsa->lsdb->data)) continue; if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && oa != OSPF6_INTERFACE (lsa->lsdb->data)->area) continue; if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && IS_AREA_STUB (oa)) continue; ospf6_flood_area (from, lsa, oa); } } void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa) { ospf6_flood_process (from, lsa, ospf6); } static void ospf6_flood_clear_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; struct ospf6_lsa *rem; for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { rem = ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, on->retrans_list); if (rem && ! ospf6_lsa_compare (rem, lsa)) { if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) zlog_debug ("Remove %s from retrans_list of %s", rem->name, on->name); ospf6_decrement_retrans_count (rem); ospf6_lsdb_remove (rem, on->retrans_list); } } } static void ospf6_flood_clear_area (struct ospf6_lsa *lsa, struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) { if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && oi != OSPF6_INTERFACE (lsa->lsdb->data)) continue; #if 0 if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AS && ospf6_is_interface_virtual_link (oi)) continue; #endif/*0*/ ospf6_flood_clear_interface (lsa, oi); } } static void ospf6_flood_clear_process (struct ospf6_lsa *lsa, struct ospf6 *process) { struct listnode *node, *nnode; struct ospf6_area *oa; for (ALL_LIST_ELEMENTS (process->area_list, node, nnode, oa)) { if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_AREA && oa != OSPF6_AREA (lsa->lsdb->data)) continue; if (OSPF6_LSA_SCOPE (lsa->header->type) == OSPF6_SCOPE_LINKLOCAL && oa != OSPF6_INTERFACE (lsa->lsdb->data)->area) continue; if (ntohs (lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && IS_AREA_STUB (oa)) continue; ospf6_flood_clear_area (lsa, oa); } } void ospf6_flood_clear (struct ospf6_lsa *lsa) { ospf6_flood_clear_process (lsa, ospf6); } /* RFC2328 13.5 (Table 19): Sending link state acknowledgements. */ static void ospf6_acknowledge_lsa_bdrouter (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; int is_debug = 0; if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) is_debug++; assert (from && from->ospf6_if); oi = from->ospf6_if; /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent if advertisement received from Designated Router, otherwide do nothing. */ if (ismore_recent < 0) { if (oi->drouter == from->router_id) { if (is_debug) zlog_debug ("Delayed acknowledgement (BDR & MoreRecent & from DR)"); /* Delayed acknowledgement */ ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); } else { if (is_debug) zlog_debug ("No acknowledgement (BDR & MoreRecent & ! from DR)"); } return; } /* LSA is a duplicate, and was treated as an implied acknowledgement. Delayed acknowledgement sent if advertisement received from Designated Router, otherwise do nothing */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (oi->drouter == from->router_id) { if (is_debug) zlog_debug ("Delayed acknowledgement (BDR & Duplicate & ImpliedAck & from DR)"); /* Delayed acknowledgement */ ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); } else { if (is_debug) zlog_debug ("No acknowledgement (BDR & Duplicate & ImpliedAck & ! from DR)"); } return; } /* LSA is a duplicate, and was not treated as an implied acknowledgement. Direct acknowledgement sent */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (is_debug) zlog_debug ("Direct acknowledgement (BDR & Duplicate)"); ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); return; } /* LSA's LS age is equal to Maxage, and there is no current instance of the LSA in the link state database, and none of router's neighbors are in states Exchange or Loading */ /* Direct acknowledgement sent, but this case is handled in early of ospf6_receive_lsa () */ } static void ospf6_acknowledge_lsa_allother (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; int is_debug = 0; if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (lsa->header->type)) is_debug++; assert (from && from->ospf6_if); oi = from->ospf6_if; /* LSA has been flood back out receiving interface. No acknowledgement sent. */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_FLOODBACK)) { if (is_debug) zlog_debug ("No acknowledgement (AllOther & FloodBack)"); return; } /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgement sent. */ if (ismore_recent < 0) { if (is_debug) zlog_debug ("Delayed acknowledgement (AllOther & MoreRecent)"); /* Delayed acknowledgement */ ospf6_lsdb_add (ospf6_lsa_copy (lsa), oi->lsack_list); if (oi->thread_send_lsack == NULL) oi->thread_send_lsack = thread_add_timer (master, ospf6_lsack_send_interface, oi, 3); return; } /* LSA is a duplicate, and was treated as an implied acknowledgement. No acknowledgement sent. */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (is_debug) zlog_debug ("No acknowledgement (AllOther & Duplicate & ImpliedAck)"); return; } /* LSA is a duplicate, and was not treated as an implied acknowledgement. Direct acknowledgement sent */ if (CHECK_FLAG (lsa->flag, OSPF6_LSA_DUPLICATE) && ! CHECK_FLAG (lsa->flag, OSPF6_LSA_IMPLIEDACK)) { if (is_debug) zlog_debug ("Direct acknowledgement (AllOther & Duplicate)"); ospf6_lsdb_add (ospf6_lsa_copy (lsa), from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); return; } /* LSA's LS age is equal to Maxage, and there is no current instance of the LSA in the link state database, and none of router's neighbors are in states Exchange or Loading */ /* Direct acknowledgement sent, but this case is handled in early of ospf6_receive_lsa () */ } static void ospf6_acknowledge_lsa (struct ospf6_lsa *lsa, int ismore_recent, struct ospf6_neighbor *from) { struct ospf6_interface *oi; assert (from && from->ospf6_if); oi = from->ospf6_if; if (oi->state == OSPF6_INTERFACE_BDR) ospf6_acknowledge_lsa_bdrouter (lsa, ismore_recent, from); else ospf6_acknowledge_lsa_allother (lsa, ismore_recent, from); } /* RFC2328 section 13 (4): if MaxAge LSA and if we have no instance, and no neighbor is in states Exchange or Loading returns 1 if match this case, else returns 0 */ static int ospf6_is_maxage_lsa_drop (struct ospf6_lsa *lsa, struct ospf6_neighbor *from) { struct ospf6_neighbor *on; struct ospf6_interface *oi; struct ospf6_area *oa; struct ospf6 *process = NULL; struct listnode *i, *j, *k; int count = 0; if (! OSPF6_LSA_IS_MAXAGE (lsa)) return 0; if (ospf6_lsdb_lookup (lsa->header->type, lsa->header->id, lsa->header->adv_router, lsa->lsdb)) return 0; process = from->ospf6_if->area->ospf6; for (ALL_LIST_ELEMENTS_RO (process->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) if (on->state == OSPF6_NEIGHBOR_EXCHANGE || on->state == OSPF6_NEIGHBOR_LOADING) count++; if (count == 0) return 1; return 0; } /* RFC2328 section 13 The Flooding Procedure */ void ospf6_receive_lsa (struct ospf6_neighbor *from, struct ospf6_lsa_header *lsa_header) { struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL; int ismore_recent; int is_debug = 0; ismore_recent = 1; assert (from); /* make lsa structure for received lsa */ new = ospf6_lsa_create (lsa_header); if (IS_OSPF6_DEBUG_FLOODING || IS_OSPF6_DEBUG_FLOOD_TYPE (new->header->type)) { is_debug++; zlog_debug ("LSA Receive from %s", from->name); ospf6_lsa_header_print (new); } /* (1) LSA Checksum */ if (! ospf6_lsa_checksum_valid (new->header)) { if (is_debug) zlog_debug ("Wrong LSA Checksum, discard"); ospf6_lsa_delete (new); return; } /* (2) Examine the LSA's LS type. RFC2470 3.5.1. Receiving Link State Update packets */ if (IS_AREA_STUB (from->ospf6_if->area) && OSPF6_LSA_SCOPE (new->header->type) == OSPF6_SCOPE_AS) { if (is_debug) zlog_debug ("AS-External-LSA (or AS-scope LSA) in stub area, discard"); ospf6_lsa_delete (new); return; } /* (3) LSA which have reserved scope is discarded RFC2470 3.5.1. Receiving Link State Update packets */ /* Flooding scope check. LSAs with unknown scope are discarded here. Set appropriate LSDB for the LSA */ switch (OSPF6_LSA_SCOPE (new->header->type)) { case OSPF6_SCOPE_LINKLOCAL: new->lsdb = from->ospf6_if->lsdb; break; case OSPF6_SCOPE_AREA: new->lsdb = from->ospf6_if->area->lsdb; break; case OSPF6_SCOPE_AS: new->lsdb = from->ospf6_if->area->ospf6->lsdb; break; default: if (is_debug) zlog_debug ("LSA has reserved scope, discard"); ospf6_lsa_delete (new); return; } /* (4) if MaxAge LSA and if we have no instance, and no neighbor is in states Exchange or Loading */ if (ospf6_is_maxage_lsa_drop (new, from)) { /* log */ if (is_debug) zlog_debug ("Drop MaxAge LSA with direct acknowledgement."); /* a) Acknowledge back to neighbor (Direct acknowledgement, 13.5) */ ospf6_lsdb_add (ospf6_lsa_copy (new), from->lsack_list); if (from->thread_send_lsack == NULL) from->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, from, 0); /* b) Discard */ ospf6_lsa_delete (new); return; } /* (5) */ /* lookup the same database copy in lsdb */ old = ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, new->lsdb); if (old) { ismore_recent = ospf6_lsa_compare (new, old); if (ntohl (new->header->seqnum) == ntohl (old->header->seqnum)) { if (is_debug) zlog_debug ("Received is duplicated LSA"); SET_FLAG (new->flag, OSPF6_LSA_DUPLICATE); } } /* if no database copy or received is more recent */ if (old == NULL || ismore_recent < 0) { /* in case we have no database copy */ ismore_recent = -1; /* (a) MinLSArrival check */ if (old) { struct timeval now, res; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &old->installed, &res); if (res.tv_sec < OSPF_MIN_LS_ARRIVAL) { if (is_debug) zlog_debug ("LSA can't be updated within MinLSArrival, discard"); ospf6_lsa_delete (new); return; /* examin next lsa */ } } quagga_gettime (QUAGGA_CLK_MONOTONIC, &new->received); if (is_debug) zlog_debug ("Install, Flood, Possibly acknowledge the received LSA"); /* Remove older copies of this LSA from retx lists */ if (old) ospf6_flood_clear (old); /* (b) immediately flood and (c) remove from all retrans-list */ /* Prevent self-originated LSA to be flooded. this is to make reoriginated instance of the LSA not to be rejected by other routers due to MinLSArrival. */ if (new->header->adv_router != from->ospf6_if->area->ospf6->router_id) ospf6_flood (from, new); /* (d), installing lsdb, which may cause routing table calculation (replacing database copy) */ ospf6_install_lsa (new); /* (e) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); /* (f) Self Originated LSA, section 13.4 */ if (new->header->adv_router == from->ospf6_if->area->ospf6->router_id) { /* Self-originated LSA (newer than ours) is received from another router. We have to make a new instance of the LSA or have to flush this LSA. */ if (is_debug) { zlog_debug ("Newer instance of the self-originated LSA"); zlog_debug ("Schedule reorigination"); } new->refresh = thread_add_event (master, ospf6_lsa_refresh, new, 0); } return; } /* (6) if there is instance on sending neighbor's request list */ if (ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, from->request_list)) { /* if no database copy, should go above state (5) */ assert (old); if (is_debug) { zlog_debug ("Received is not newer, on the neighbor's request-list"); zlog_debug ("BadLSReq, discard the received LSA"); } /* BadLSReq */ thread_add_event (master, bad_lsreq, from, 0); ospf6_lsa_delete (new); return; } /* (7) if neither one is more recent */ if (ismore_recent == 0) { if (is_debug) zlog_debug ("The same instance as database copy (neither recent)"); /* (a) if on retrans-list, Treat this LSA as an Ack: Implied Ack */ rem = ospf6_lsdb_lookup (new->header->type, new->header->id, new->header->adv_router, from->retrans_list); if (rem) { if (is_debug) { zlog_debug ("It is on the neighbor's retrans-list."); zlog_debug ("Treat as an Implied acknowledgement"); } SET_FLAG (new->flag, OSPF6_LSA_IMPLIEDACK); ospf6_decrement_retrans_count (rem); ospf6_lsdb_remove (rem, from->retrans_list); } if (is_debug) zlog_debug ("Possibly acknowledge and then discard"); /* (b) possibly acknowledge */ ospf6_acknowledge_lsa (new, ismore_recent, from); ospf6_lsa_delete (new); return; } /* (8) previous database copy is more recent */ { assert (old); /* If database copy is in 'Seqnumber Wrapping', simply discard the received LSA */ if (OSPF6_LSA_IS_MAXAGE (old) && old->header->seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)) { if (is_debug) { zlog_debug ("The LSA is in Seqnumber Wrapping"); zlog_debug ("MaxAge & MaxSeqNum, discard"); } ospf6_lsa_delete (new); return; } /* Otherwise, Send database copy of this LSA to this neighbor */ { if (is_debug) { zlog_debug ("Database copy is more recent."); zlog_debug ("Send back directly and then discard"); } /* XXX, MinLSArrival check !? RFC 2328 13 (8) */ ospf6_lsdb_add (ospf6_lsa_copy (old), from->lsupdate_list); if (from->thread_send_lsupdate == NULL) from->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, from, 0); ospf6_lsa_delete (new); return; } return; } } DEFUN (debug_ospf6_flooding, debug_ospf6_flooding_cmd, "debug ospf6 flooding", DEBUG_STR OSPF6_STR "Debug OSPFv3 flooding function\n" ) { OSPF6_DEBUG_FLOODING_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_flooding, no_debug_ospf6_flooding_cmd, "no debug ospf6 flooding", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 flooding function\n" ) { OSPF6_DEBUG_FLOODING_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_flood (struct vty *vty) { if (IS_OSPF6_DEBUG_FLOODING) vty_out (vty, "debug ospf6 flooding%s", VNL); return 0; } void install_element_ospf6_debug_flood (void) { install_element (ENABLE_NODE, &debug_ospf6_flooding_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_flooding_cmd); install_element (CONFIG_NODE, &debug_ospf6_flooding_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_flooding_cmd); } quagga-0.99.24.1/ospf6d/ospf6_neighbor.c0000644000175000017500000007220212476520570014516 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "thread.h" #include "linklist.h" #include "vty.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_flood.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_neighbor = 0; const char *ospf6_neighbor_state_str[] = { "None", "Down", "Attempt", "Init", "Twoway", "ExStart", "ExChange", "Loading", "Full", NULL }; static const char *ospf6_neighbor_event_str[] = { "NoEvent", "HelloReceived", "2-WayReceived", "NegotiationDone", "ExchangeDone", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "BadLSReq", "1-WayReceived", "InactivityTimer", }; static const char * ospf6_neighbor_event_string (int event) { #define OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING "UnknownEvent" if (event < OSPF6_NEIGHBOR_EVENT_MAX_EVENT) return ospf6_neighbor_event_str[event]; return OSPF6_NEIGHBOR_UNKNOWN_EVENT_STRING; } int ospf6_neighbor_cmp (void *va, void *vb) { struct ospf6_neighbor *ona = (struct ospf6_neighbor *) va; struct ospf6_neighbor *onb = (struct ospf6_neighbor *) vb; return (ntohl (ona->router_id) < ntohl (onb->router_id) ? -1 : 1); } struct ospf6_neighbor * ospf6_neighbor_lookup (u_int32_t router_id, struct ospf6_interface *oi) { struct listnode *n; struct ospf6_neighbor *on; for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, n, on)) if (on->router_id == router_id) return on; return (struct ospf6_neighbor *) NULL; } /* create ospf6_neighbor */ struct ospf6_neighbor * ospf6_neighbor_create (u_int32_t router_id, struct ospf6_interface *oi) { struct ospf6_neighbor *on; char buf[16]; on = (struct ospf6_neighbor *) XMALLOC (MTYPE_OSPF6_NEIGHBOR, sizeof (struct ospf6_neighbor)); if (on == NULL) { zlog_warn ("neighbor: malloc failed"); return NULL; } memset (on, 0, sizeof (struct ospf6_neighbor)); inet_ntop (AF_INET, &router_id, buf, sizeof (buf)); snprintf (on->name, sizeof (on->name), "%s%%%s", buf, oi->interface->name); on->ospf6_if = oi; on->state = OSPF6_NEIGHBOR_DOWN; on->state_change = 0; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); on->router_id = router_id; on->summary_list = ospf6_lsdb_create (on); on->request_list = ospf6_lsdb_create (on); on->retrans_list = ospf6_lsdb_create (on); on->dbdesc_list = ospf6_lsdb_create (on); on->lsupdate_list = ospf6_lsdb_create (on); on->lsack_list = ospf6_lsdb_create (on); listnode_add_sort (oi->neighbor_list, on); return on; } void ospf6_neighbor_delete (struct ospf6_neighbor *on) { struct ospf6_lsa *lsa; ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } ospf6_lsdb_remove_all (on->dbdesc_list); ospf6_lsdb_remove_all (on->lsupdate_list); ospf6_lsdb_remove_all (on->lsack_list); ospf6_lsdb_delete (on->summary_list); ospf6_lsdb_delete (on->request_list); ospf6_lsdb_delete (on->retrans_list); ospf6_lsdb_delete (on->dbdesc_list); ospf6_lsdb_delete (on->lsupdate_list); ospf6_lsdb_delete (on->lsack_list); THREAD_OFF (on->inactivity_timer); THREAD_OFF (on->thread_send_dbdesc); THREAD_OFF (on->thread_send_lsreq); THREAD_OFF (on->thread_send_lsupdate); THREAD_OFF (on->thread_send_lsack); XFREE (MTYPE_OSPF6_NEIGHBOR, on); } static void ospf6_neighbor_state_change (u_char next_state, struct ospf6_neighbor *on, int event) { u_char prev_state; prev_state = on->state; on->state = next_state; if (prev_state == next_state) return; on->state_change++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &on->last_changed); /* log */ if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) { zlog_debug ("Neighbor state change %s: [%s]->[%s] (%s)", on->name, ospf6_neighbor_state_str[prev_state], ospf6_neighbor_state_str[next_state], ospf6_neighbor_event_string(event)); } /* Optionally notify about adjacency changes */ if (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(on->ospf6_if->area->ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL) || (next_state == OSPF6_NEIGHBOR_FULL) || (next_state < prev_state))) zlog_notice("AdjChg: Nbr %s: %s -> %s (%s)", on->name, ospf6_neighbor_state_str[prev_state], ospf6_neighbor_state_str[next_state], ospf6_neighbor_event_string(event)); if (prev_state == OSPF6_NEIGHBOR_FULL || next_state == OSPF6_NEIGHBOR_FULL) { OSPF6_ROUTER_LSA_SCHEDULE (on->ospf6_if->area); if (on->ospf6_if->state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (on->ospf6_if); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (on->ospf6_if); } OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (on->ospf6_if->area); } if ((prev_state == OSPF6_NEIGHBOR_EXCHANGE || prev_state == OSPF6_NEIGHBOR_LOADING) && (next_state != OSPF6_NEIGHBOR_EXCHANGE && next_state != OSPF6_NEIGHBOR_LOADING)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); #ifdef HAVE_SNMP /* Terminal state or regression */ if ((next_state == OSPF6_NEIGHBOR_FULL) || (next_state == OSPF6_NEIGHBOR_TWOWAY) || (next_state < prev_state)) ospf6TrapNbrStateChange (on); #endif } /* RFC2328 section 10.4 */ static int need_adjacency (struct ospf6_neighbor *on) { if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT || on->ospf6_if->state == OSPF6_INTERFACE_DR || on->ospf6_if->state == OSPF6_INTERFACE_BDR) return 1; if (on->ospf6_if->drouter == on->router_id || on->ospf6_if->bdrouter == on->router_id) return 1; return 0; } int hello_received (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *HelloReceived*", on->name); /* reset Inactivity Timer */ THREAD_OFF (on->inactivity_timer); on->inactivity_timer = thread_add_timer (master, inactivity_timer, on, on->ospf6_if->dead_interval); if (on->state <= OSPF6_NEIGHBOR_DOWN) ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on, OSPF6_NEIGHBOR_EVENT_HELLO_RCVD); return 0; } int twoway_received (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state > OSPF6_NEIGHBOR_INIT) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *2Way-Received*", on->name); thread_add_event (master, neighbor_change, on->ospf6_if, 0); if (! need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on, OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); return 0; } ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int negotiation_done (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state != OSPF6_NEIGHBOR_EXSTART) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *NegotiationDone*", on->name); /* clear ls-list */ ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } /* Interface scoped LSAs */ for (lsa = ospf6_lsdb_head (on->ospf6_if->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) { ospf6_increment_retrans_count (lsa); ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); } else ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); } /* Area scoped LSAs */ for (lsa = ospf6_lsdb_head (on->ospf6_if->area->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) { ospf6_increment_retrans_count (lsa); ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); } else ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); } /* AS scoped LSAs */ for (lsa = ospf6_lsdb_head (on->ospf6_if->area->ospf6->lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) { ospf6_increment_retrans_count (lsa); ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->retrans_list); } else ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->summary_list); } UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXCHANGE, on, OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE); return 0; } int exchange_done (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state != OSPF6_NEIGHBOR_EXCHANGE) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *ExchangeDone*", on->name); THREAD_OFF (on->thread_send_dbdesc); ospf6_lsdb_remove_all (on->dbdesc_list); /* XXX thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on, on->ospf6_if->dead_interval); */ if (on->request_list->count == 0) ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on, OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); else { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_LOADING, on, OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE); if (on->thread_send_lsreq == NULL) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); } return 0; } /* Check loading state. */ void ospf6_check_nbr_loading (struct ospf6_neighbor *on) { /* RFC2328 Section 10.9: When the neighbor responds to these requests with the proper Link State Update packet(s), the Link state request list is truncated and a new Link State Request packet is sent. */ if ((on->state == OSPF6_NEIGHBOR_LOADING) || (on->state == OSPF6_NEIGHBOR_EXCHANGE)) { if (on->request_list->count == 0) thread_add_event (master, loading_done, on, 0); else if (on->last_ls_req == NULL) { if (on->thread_send_lsreq != NULL) THREAD_OFF (on->thread_send_lsreq); on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); } } } int loading_done (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state != OSPF6_NEIGHBOR_LOADING) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *LoadingDone*", on->name); assert (on->request_list->count == 0); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_FULL, on, OSPF6_NEIGHBOR_EVENT_LOADING_DONE); return 0; } int adj_ok (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *AdjOK?*", on->name); if (on->state == OSPF6_NEIGHBOR_TWOWAY && need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_ADJ_OK); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && ! need_adjacency (on)) { ospf6_neighbor_state_change (OSPF6_NEIGHBOR_TWOWAY, on, OSPF6_NEIGHBOR_EVENT_ADJ_OK); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } } return 0; } int seqnumber_mismatch (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *SeqNumberMismatch*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int bad_lsreq (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *BadLSReq*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_EXSTART, on, OSPF6_NEIGHBOR_EVENT_BAD_LSREQ); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); SET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */ on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return 0; } int oneway_received (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (on->state < OSPF6_NEIGHBOR_TWOWAY) return 0; if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *1Way-Received*", on->name); ospf6_neighbor_state_change (OSPF6_NEIGHBOR_INIT, on, OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD); thread_add_event (master, neighbor_change, on->ospf6_if, 0); ospf6_lsdb_remove_all (on->summary_list); ospf6_lsdb_remove_all (on->request_list); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_decrement_retrans_count (lsa); ospf6_lsdb_remove (lsa, on->retrans_list); } THREAD_OFF (on->thread_send_dbdesc); THREAD_OFF (on->thread_send_lsreq); THREAD_OFF (on->thread_send_lsupdate); THREAD_OFF (on->thread_send_lsack); return 0; } int inactivity_timer (struct thread *thread) { struct ospf6_neighbor *on; on = (struct ospf6_neighbor *) THREAD_ARG (thread); assert (on); if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) zlog_debug ("Neighbor Event %s: *InactivityTimer*", on->name); on->inactivity_timer = NULL; on->drouter = on->prev_drouter = 0; on->bdrouter = on->prev_bdrouter = 0; ospf6_neighbor_state_change (OSPF6_NEIGHBOR_DOWN, on, OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER); thread_add_event (master, neighbor_change, on->ospf6_if, 0); listnode_delete (on->ospf6_if->neighbor_list, on); ospf6_neighbor_delete (on); return 0; } /* vty functions */ /* show neighbor structure */ static void ospf6_neighbor_show (struct vty *vty, struct ospf6_neighbor *on) { char router_id[16]; char duration[16]; struct timeval now, res; char nstate[16]; char deadtime[16]; long h, m, s; /* Router-ID (Name) */ inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id)); #ifdef HAVE_GETNAMEINFO { } #endif /*HAVE_GETNAMEINFO*/ quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); /* Dead time */ h = m = s = 0; if (on->inactivity_timer) { s = on->inactivity_timer->u.sands.tv_sec - recent_relative_time().tv_sec; h = s / 3600; s -= h * 3600; m = s / 60; s -= m * 60; } snprintf (deadtime, sizeof (deadtime), "%02ld:%02ld:%02ld", h, m, s); /* Neighbor State */ if (if_is_pointopoint (on->ospf6_if->interface)) snprintf (nstate, sizeof (nstate), "PointToPoint"); else { if (on->router_id == on->drouter) snprintf (nstate, sizeof (nstate), "DR"); else if (on->router_id == on->bdrouter) snprintf (nstate, sizeof (nstate), "BDR"); else snprintf (nstate, sizeof (nstate), "DROther"); } /* Duration */ timersub (&now, &on->last_changed, &res); timerstring (&res, duration, sizeof (duration)); /* vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s", "Neighbor ID", "Pri", "DeadTime", "State", "", "Duration", "I/F", "State", VNL); */ vty_out (vty, "%-15s %3d %11s %6s/%-12s %11s %s[%s]%s", router_id, on->priority, deadtime, ospf6_neighbor_state_str[on->state], nstate, duration, on->ospf6_if->interface->name, ospf6_interface_state_str[on->ospf6_if->state], VNL); } static void ospf6_neighbor_show_drchoice (struct vty *vty, struct ospf6_neighbor *on) { char router_id[16]; char drouter[16], bdrouter[16]; char duration[16]; struct timeval now, res; /* vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", "RouterID", "State", "Duration", "DR", "BDR", "I/F", "State", VNL); */ inet_ntop (AF_INET, &on->router_id, router_id, sizeof (router_id)); inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter)); inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &on->last_changed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", router_id, ospf6_neighbor_state_str[on->state], duration, drouter, bdrouter, on->ospf6_if->interface->name, ospf6_interface_state_str[on->ospf6_if->state], VNL); } static void ospf6_neighbor_show_detail (struct vty *vty, struct ospf6_neighbor *on) { char drouter[16], bdrouter[16]; char linklocal_addr[64], duration[32]; struct timeval now, res; struct ospf6_lsa *lsa; inet_ntop (AF_INET6, &on->linklocal_addr, linklocal_addr, sizeof (linklocal_addr)); inet_ntop (AF_INET, &on->drouter, drouter, sizeof (drouter)); inet_ntop (AF_INET, &on->bdrouter, bdrouter, sizeof (bdrouter)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &on->last_changed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " Neighbor %s%s", on->name, VNL); vty_out (vty, " Area %s via interface %s (ifindex %d)%s", on->ospf6_if->area->name, on->ospf6_if->interface->name, on->ospf6_if->interface->ifindex, VNL); vty_out (vty, " His IfIndex: %d Link-local address: %s%s", on->ifindex, linklocal_addr, VNL); vty_out (vty, " State %s for a duration of %s%s", ospf6_neighbor_state_str[on->state], duration, VNL); vty_out (vty, " His choice of DR/BDR %s/%s, Priority %d%s", drouter, bdrouter, on->priority, VNL); vty_out (vty, " DbDesc status: %s%s%s SeqNum: %#lx%s", (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) ? "Initial " : ""), (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT) ? "More " : ""), (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) ? "Master" : "Slave"), (u_long) ntohl (on->dbdesc_seqnum), VNL); vty_out (vty, " Summary-List: %d LSAs%s", on->summary_list->count, VNL); for (lsa = ospf6_lsdb_head (on->summary_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); vty_out (vty, " Request-List: %d LSAs%s", on->request_list->count, VNL); for (lsa = ospf6_lsdb_head (on->request_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); vty_out (vty, " Retrans-List: %d LSAs%s", on->retrans_list->count, VNL); for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_dbdesc) timersub (&on->thread_send_dbdesc->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for DbDesc in Time %s [thread %s]%s", on->dbdesc_list->count, duration, (on->thread_send_dbdesc ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_lsreq) timersub (&on->thread_send_lsreq->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSReq in Time %s [thread %s]%s", on->request_list->count, duration, (on->thread_send_lsreq ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->request_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_lsupdate) timersub (&on->thread_send_lsupdate->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]%s", on->lsupdate_list->count, duration, (on->thread_send_lsupdate ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (on->thread_send_lsack) timersub (&on->thread_send_lsack->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSAck in Time %s [thread %s]%s", on->lsack_list->count, duration, (on->thread_send_lsack ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); } DEFUN (show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, "show ipv6 ospf6 neighbor", SHOW_STR IP6_STR OSPF6_STR "Neighbor list\n" ) { struct ospf6_neighbor *on; struct ospf6_interface *oi; struct ospf6_area *oa; struct listnode *i, *j, *k; void (*showfunc) (struct vty *, struct ospf6_neighbor *); OSPF6_CMD_CHECK_RUNNING (); showfunc = ospf6_neighbor_show; if (argc) { if (! strncmp (argv[0], "de", 2)) showfunc = ospf6_neighbor_show_detail; else if (! strncmp (argv[0], "dr", 2)) showfunc = ospf6_neighbor_show_drchoice; } if (showfunc == ospf6_neighbor_show) vty_out (vty, "%-15s %3s %11s %6s/%-12s %11s %s[%s]%s", "Neighbor ID", "Pri", "DeadTime", "State", "IfState", "Duration", "I/F", "State", VNL); else if (showfunc == ospf6_neighbor_show_drchoice) vty_out (vty, "%-15s %6s/%-11s %-15s %-15s %s[%s]%s", "RouterID", "State", "Duration", "DR", "BDR", "I/F", "State", VNL); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) (*showfunc) (vty, on); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_detail_cmd, "show ipv6 ospf6 neighbor (detail|drchoice)", SHOW_STR IP6_STR OSPF6_STR "Neighbor list\n" "Display details\n" "Display DR choices\n" ) DEFUN (show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd, "show ipv6 ospf6 neighbor A.B.C.D", SHOW_STR IP6_STR OSPF6_STR "Neighbor list\n" "Specify Router-ID as IPv4 address notation\n" ) { struct ospf6_neighbor *on; struct ospf6_interface *oi; struct ospf6_area *oa; struct listnode *i, *j, *k; void (*showfunc) (struct vty *, struct ospf6_neighbor *); u_int32_t router_id; OSPF6_CMD_CHECK_RUNNING (); showfunc = ospf6_neighbor_show_detail; if ((inet_pton (AF_INET, argv[0], &router_id)) != 1) { vty_out (vty, "Router-ID is not parsable: %s%s", argv[0], VNL); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) (*showfunc) (vty, on); return CMD_SUCCESS; } void ospf6_neighbor_init (void) { install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_neighbor_detail_cmd); } DEFUN (debug_ospf6_neighbor, debug_ospf6_neighbor_cmd, "debug ospf6 neighbor", DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_NEIGHBOR_STATE; if (! strncmp (argv[0], "e", 1)) level = OSPF6_DEBUG_NEIGHBOR_EVENT; } else level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; OSPF6_DEBUG_NEIGHBOR_ON (level); return CMD_SUCCESS; } ALIAS (debug_ospf6_neighbor, debug_ospf6_neighbor_detail_cmd, "debug ospf6 neighbor (state|event)", DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) DEFUN (no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_cmd, "no debug ospf6 neighbor", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" ) { unsigned char level = 0; if (argc) { if (! strncmp (argv[0], "s", 1)) level = OSPF6_DEBUG_NEIGHBOR_STATE; if (! strncmp (argv[0], "e", 1)) level = OSPF6_DEBUG_NEIGHBOR_EVENT; } else level = OSPF6_DEBUG_NEIGHBOR_STATE | OSPF6_DEBUG_NEIGHBOR_EVENT; OSPF6_DEBUG_NEIGHBOR_OFF (level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_neighbor, no_debug_ospf6_neighbor_detail_cmd, "no debug ospf6 neighbor (state|event)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Neighbor\n" "Debug OSPFv3 Neighbor State Change\n" "Debug OSPFv3 Neighbor Event\n" ) int config_write_ospf6_debug_neighbor (struct vty *vty) { if (IS_OSPF6_DEBUG_NEIGHBOR (STATE) && IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) vty_out (vty, "debug ospf6 neighbor%s", VNL); else if (IS_OSPF6_DEBUG_NEIGHBOR (STATE)) vty_out (vty, "debug ospf6 neighbor state%s", VNL); else if (IS_OSPF6_DEBUG_NEIGHBOR (EVENT)) vty_out (vty, "debug ospf6 neighbor event%s", VNL); return 0; } void install_element_ospf6_debug_neighbor (void) { install_element (ENABLE_NODE, &debug_ospf6_neighbor_cmd); install_element (ENABLE_NODE, &debug_ospf6_neighbor_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_neighbor_detail_cmd); install_element (CONFIG_NODE, &debug_ospf6_neighbor_cmd); install_element (CONFIG_NODE, &debug_ospf6_neighbor_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_neighbor_detail_cmd); } quagga-0.99.24.1/ospf6d/ospf6_interface.c0000644000175000017500000014576012476520570014673 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "if.h" #include "log.h" #include "command.h" #include "thread.h" #include "prefix.h" #include "plist.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_network.h" #include "ospf6_message.h" #include "ospf6_route.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" unsigned char conf_debug_ospf6_interface = 0; const char *ospf6_interface_state_str[] = { "None", "Down", "Loopback", "Waiting", "PointToPoint", "DROther", "BDR", "DR", NULL }; struct ospf6_interface * ospf6_interface_lookup_by_ifindex (int ifindex) { struct ospf6_interface *oi; struct interface *ifp; ifp = if_lookup_by_index (ifindex); if (ifp == NULL) return (struct ospf6_interface *) NULL; oi = (struct ospf6_interface *) ifp->info; return oi; } /* schedule routing table recalculation */ static void ospf6_interface_lsdb_hook (struct ospf6_lsa *lsa, unsigned int reason) { struct ospf6_interface *oi; if (lsa == NULL) return; oi = lsa->lsdb->data; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_LINK: if (oi->state == OSPF6_INTERFACE_DR) OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); ospf6_spf_schedule (oi->area->ospf6, reason); break; default: break; } } static void ospf6_interface_lsdb_hook_add (struct ospf6_lsa *lsa) { ospf6_interface_lsdb_hook(lsa, ospf6_lsadd_to_spf_reason(lsa)); } static void ospf6_interface_lsdb_hook_remove (struct ospf6_lsa *lsa) { ospf6_interface_lsdb_hook(lsa, ospf6_lsremove_to_spf_reason(lsa)); } static u_char ospf6_default_iftype(struct interface *ifp) { if (if_is_pointopoint (ifp)) return OSPF_IFTYPE_POINTOPOINT; else if (if_is_loopback (ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; } static u_int32_t ospf6_interface_get_cost (struct ospf6_interface *oi) { /* If all else fails, use default OSPF cost */ u_int32_t cost; u_int32_t bw, refbw; bw = oi->interface->bandwidth ? oi->interface->bandwidth : OSPF6_INTERFACE_BANDWIDTH; refbw = ospf6 ? ospf6->ref_bandwidth : OSPF6_REFERENCE_BANDWIDTH; /* A specifed ip ospf cost overrides a calculated one. */ if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) cost = oi->cost; else { cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); if (cost < 1) cost = 1; else if (cost > UINT32_MAX) cost = UINT32_MAX; } return cost; } static void ospf6_interface_recalculate_cost (struct ospf6_interface *oi) { u_int32_t newcost; newcost = ospf6_interface_get_cost (oi); if (newcost == oi->cost) return; oi->cost = newcost; /* update cost held in route_connected list in ospf6_interface */ ospf6_interface_connected_route_update (oi->interface); /* execute LSA hooks */ if (oi->area) { OSPF6_LINK_LSA_SCHEDULE (oi); OSPF6_ROUTER_LSA_SCHEDULE (oi->area); OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } } /* Create new ospf6 interface structure */ struct ospf6_interface * ospf6_interface_create (struct interface *ifp) { struct ospf6_interface *oi; unsigned int iobuflen; oi = (struct ospf6_interface *) XCALLOC (MTYPE_OSPF6_IF, sizeof (struct ospf6_interface)); if (!oi) { zlog_err ("Can't malloc ospf6_interface for ifindex %d", ifp->ifindex); return (struct ospf6_interface *) NULL; } oi->area = (struct ospf6_area *) NULL; oi->neighbor_list = list_new (); oi->neighbor_list->cmp = ospf6_neighbor_cmp; oi->linklocal_addr = (struct in6_addr *) NULL; oi->instance_id = OSPF6_INTERFACE_INSTANCE_ID; oi->transdelay = OSPF6_INTERFACE_TRANSDELAY; oi->priority = OSPF6_INTERFACE_PRIORITY; oi->hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; oi->dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; oi->rxmt_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; oi->type = ospf6_default_iftype (ifp); oi->state = OSPF6_INTERFACE_DOWN; oi->flag = 0; oi->mtu_ignore = 0; /* Try to adjust I/O buffer size with IfMtu */ oi->ifmtu = ifp->mtu6; iobuflen = ospf6_iobuf_size (ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", ifp->name, iobuflen); oi->ifmtu = iobuflen; } oi->lsupdate_list = ospf6_lsdb_create (oi); oi->lsack_list = ospf6_lsdb_create (oi); oi->lsdb = ospf6_lsdb_create (oi); oi->lsdb->hook_add = ospf6_interface_lsdb_hook_add; oi->lsdb->hook_remove = ospf6_interface_lsdb_hook_remove; oi->lsdb_self = ospf6_lsdb_create (oi); oi->route_connected = OSPF6_ROUTE_TABLE_CREATE (INTERFACE, CONNECTED_ROUTES); oi->route_connected->scope = oi; /* link both */ oi->interface = ifp; ifp->info = oi; /* Compute cost. */ oi->cost = ospf6_interface_get_cost(oi); return oi; } void ospf6_interface_delete (struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on; for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete (on); list_delete (oi->neighbor_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); ospf6_lsdb_delete (oi->lsdb); ospf6_lsdb_delete (oi->lsdb_self); ospf6_lsdb_delete (oi->lsupdate_list); ospf6_lsdb_delete (oi->lsack_list); ospf6_route_table_delete (oi->route_connected); /* cut link */ oi->interface->info = NULL; /* plist_name */ if (oi->plist_name) XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); XFREE (MTYPE_OSPF6_IF, oi); } void ospf6_interface_enable (struct ospf6_interface *oi) { UNSET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); ospf6_interface_state_update (oi->interface); } void ospf6_interface_disable (struct ospf6_interface *oi) { SET_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE); thread_execute (master, interface_down, oi, 0); ospf6_lsdb_remove_all (oi->lsdb); ospf6_lsdb_remove_all (oi->lsdb_self); ospf6_lsdb_remove_all (oi->lsupdate_list); ospf6_lsdb_remove_all (oi->lsack_list); THREAD_OFF (oi->thread_send_hello); THREAD_OFF (oi->thread_send_lsupdate); THREAD_OFF (oi->thread_send_lsack); THREAD_OFF (oi->thread_network_lsa); THREAD_OFF (oi->thread_link_lsa); THREAD_OFF (oi->thread_intra_prefix_lsa); } static struct in6_addr * ospf6_interface_get_linklocal_address (struct interface *ifp) { struct listnode *n; struct connected *c; struct in6_addr *l = (struct in6_addr *) NULL; /* for each connected address */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, n, c)) { /* if family not AF_INET6, ignore */ if (c->address->family != AF_INET6) continue; /* linklocal scope check */ if (IN6_IS_ADDR_LINKLOCAL (&c->address->u.prefix6)) l = &c->address->u.prefix6; } return l; } void ospf6_interface_if_add (struct interface *ifp) { struct ospf6_interface *oi; unsigned int iobuflen; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* Try to adjust I/O buffer size with IfMtu */ if (oi->ifmtu == 0) oi->ifmtu = ifp->mtu6; iobuflen = ospf6_iobuf_size (ifp->mtu6); if (oi->ifmtu > iobuflen) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s: IfMtu is adjusted to I/O buffer size: %d.", ifp->name, iobuflen); oi->ifmtu = iobuflen; } /* interface start */ ospf6_interface_state_update(oi->interface); } void ospf6_interface_if_del (struct interface *ifp) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* interface stop */ if (oi->area) thread_execute (master, interface_down, oi, 0); listnode_delete (oi->area->if_list, oi); oi->area = (struct ospf6_area *) NULL; /* cut link */ oi->interface = NULL; ifp->info = NULL; ospf6_interface_delete (oi); } void ospf6_interface_state_update (struct interface *ifp) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; if (oi->area == NULL) return; if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) return; if (if_is_operative (ifp) && (ospf6_interface_get_linklocal_address(oi->interface) || if_is_loopback(oi->interface))) thread_add_event (master, interface_up, oi, 0); else thread_add_event (master, interface_down, oi, 0); return; } void ospf6_interface_connected_route_update (struct interface *ifp) { struct ospf6_interface *oi; struct ospf6_route *route; struct connected *c; struct listnode *node, *nnode; oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) return; /* reset linklocal pointer */ oi->linklocal_addr = ospf6_interface_get_linklocal_address (ifp); /* if area is null, do not make connected-route list */ if (oi->area == NULL) return; if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_DISABLE)) return; /* update "route to advertise" interface route table */ ospf6_route_remove_all (oi->route_connected); for (ALL_LIST_ELEMENTS (oi->interface->connected, node, nnode, c)) { if (c->address->family != AF_INET6) continue; CONTINUE_IF_ADDRESS_LINKLOCAL (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_UNSPECIFIED (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_LOOPBACK (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_V4COMPAT (IS_OSPF6_DEBUG_INTERFACE, c->address); CONTINUE_IF_ADDRESS_V4MAPPED (IS_OSPF6_DEBUG_INTERFACE, c->address); /* apply filter */ if (oi->plist_name) { struct prefix_list *plist; enum prefix_list_type ret; char buf[128]; prefix2str (c->address, buf, sizeof (buf)); plist = prefix_list_lookup (AFI_IP6, oi->plist_name); ret = prefix_list_apply (plist, (void *) c->address); if (ret == PREFIX_DENY) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("%s on %s filtered by prefix-list %s ", buf, oi->interface->name, oi->plist_name); continue; } } route = ospf6_route_create (); memcpy (&route->prefix, c->address, sizeof (struct prefix)); apply_mask (&route->prefix); route->type = OSPF6_DEST_TYPE_NETWORK; route->path.area_id = oi->area->area_id; route->path.type = OSPF6_PATH_TYPE_INTRA; route->path.cost = oi->cost; route->nexthop[0].ifindex = oi->interface->ifindex; inet_pton (AF_INET6, "::1", &route->nexthop[0].address); ospf6_route_add (route, oi->route_connected); } /* create new Link-LSA */ OSPF6_LINK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } static void ospf6_interface_state_change (u_char next_state, struct ospf6_interface *oi) { u_char prev_state; prev_state = oi->state; oi->state = next_state; if (prev_state == next_state) return; /* log */ if (IS_OSPF6_DEBUG_INTERFACE) { zlog_debug ("Interface state change %s: %s -> %s", oi->interface->name, ospf6_interface_state_str[prev_state], ospf6_interface_state_str[next_state]); } oi->state_change++; if ((prev_state == OSPF6_INTERFACE_DR || prev_state == OSPF6_INTERFACE_BDR) && (next_state != OSPF6_INTERFACE_DR && next_state != OSPF6_INTERFACE_BDR)) ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_LEAVE_GROUP); if ((prev_state != OSPF6_INTERFACE_DR && prev_state != OSPF6_INTERFACE_BDR) && (next_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_BDR)) ospf6_sso (oi->interface->ifindex, &alldrouters6, IPV6_JOIN_GROUP); OSPF6_ROUTER_LSA_SCHEDULE (oi->area); if (next_state == OSPF6_INTERFACE_DOWN) { OSPF6_NETWORK_LSA_EXECUTE (oi); OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } else if (prev_state == OSPF6_INTERFACE_DR || next_state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } #ifdef HAVE_SNMP /* Terminal state or regression */ if ((next_state == OSPF6_INTERFACE_POINTTOPOINT) || (next_state == OSPF6_INTERFACE_DROTHER) || (next_state == OSPF6_INTERFACE_BDR) || (next_state == OSPF6_INTERFACE_DR) || (next_state < prev_state)) ospf6TrapIfStateChange (oi); #endif } /* DR Election, RFC2328 section 9.4 */ #define IS_ELIGIBLE(n) \ ((n)->state >= OSPF6_NEIGHBOR_TWOWAY && (n)->priority != 0) static struct ospf6_neighbor * better_bdrouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b) { if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) && (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id)) return NULL; else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter == a->router_id) return b; else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter == b->router_id) return a; if (a->bdrouter == a->router_id && b->bdrouter != b->router_id) return a; if (a->bdrouter != a->router_id && b->bdrouter == b->router_id) return b; if (a->priority > b->priority) return a; if (a->priority < b->priority) return b; if (ntohl (a->router_id) > ntohl (b->router_id)) return a; if (ntohl (a->router_id) < ntohl (b->router_id)) return b; zlog_warn ("Router-ID duplicate ?"); return a; } static struct ospf6_neighbor * better_drouter (struct ospf6_neighbor *a, struct ospf6_neighbor *b) { if ((a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) && (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id)) return NULL; else if (a == NULL || ! IS_ELIGIBLE (a) || a->drouter != a->router_id) return b; else if (b == NULL || ! IS_ELIGIBLE (b) || b->drouter != b->router_id) return a; if (a->drouter == a->router_id && b->drouter != b->router_id) return a; if (a->drouter != a->router_id && b->drouter == b->router_id) return b; if (a->priority > b->priority) return a; if (a->priority < b->priority) return b; if (ntohl (a->router_id) > ntohl (b->router_id)) return a; if (ntohl (a->router_id) < ntohl (b->router_id)) return b; zlog_warn ("Router-ID duplicate ?"); return a; } static u_char dr_election (struct ospf6_interface *oi) { struct listnode *node, *nnode; struct ospf6_neighbor *on, *drouter, *bdrouter, myself; struct ospf6_neighbor *best_drouter, *best_bdrouter; u_char next_state = 0; drouter = bdrouter = NULL; best_drouter = best_bdrouter = NULL; /* pseudo neighbor myself, including noting current DR/BDR (1) */ memset (&myself, 0, sizeof (myself)); inet_ntop (AF_INET, &oi->area->ospf6->router_id, myself.name, sizeof (myself.name)); myself.state = OSPF6_NEIGHBOR_TWOWAY; myself.drouter = oi->drouter; myself.bdrouter = oi->bdrouter; myself.priority = oi->priority; myself.router_id = oi->area->ospf6->router_id; /* Electing BDR (2) */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) bdrouter = better_bdrouter (bdrouter, on); best_bdrouter = bdrouter; bdrouter = better_bdrouter (best_bdrouter, &myself); /* Electing DR (3) */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) drouter = better_drouter (drouter, on); best_drouter = drouter; drouter = better_drouter (best_drouter, &myself); if (drouter == NULL) drouter = bdrouter; /* the router itself is newly/no longer DR/BDR (4) */ if ((drouter == &myself && myself.drouter != myself.router_id) || (drouter != &myself && myself.drouter == myself.router_id) || (bdrouter == &myself && myself.bdrouter != myself.router_id) || (bdrouter != &myself && myself.bdrouter == myself.router_id)) { myself.drouter = (drouter ? drouter->router_id : htonl (0)); myself.bdrouter = (bdrouter ? bdrouter->router_id : htonl (0)); /* compatible to Electing BDR (2) */ bdrouter = better_bdrouter (best_bdrouter, &myself); /* compatible to Electing DR (3) */ drouter = better_drouter (best_drouter, &myself); if (drouter == NULL) drouter = bdrouter; } /* Set interface state accordingly (5) */ if (drouter && drouter == &myself) next_state = OSPF6_INTERFACE_DR; else if (bdrouter && bdrouter == &myself) next_state = OSPF6_INTERFACE_BDR; else next_state = OSPF6_INTERFACE_DROTHER; /* If NBMA, schedule Start for each neighbor having priority of 0 (6) */ /* XXX */ /* If DR or BDR change, invoke AdjOK? for each neighbor (7) */ /* RFC 2328 section 12.4. Originating LSAs (3) will be handled accordingly after AdjOK */ if (oi->drouter != (drouter ? drouter->router_id : htonl (0)) || oi->bdrouter != (bdrouter ? bdrouter->router_id : htonl (0))) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("DR Election on %s: DR: %s BDR: %s", oi->interface->name, (drouter ? drouter->name : "0.0.0.0"), (bdrouter ? bdrouter->name : "0.0.0.0")); for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, node, on)) { if (on->state < OSPF6_NEIGHBOR_TWOWAY) continue; /* Schedule AdjOK. */ thread_add_event (master, adj_ok, on, 0); } } oi->drouter = (drouter ? drouter->router_id : htonl (0)); oi->bdrouter = (bdrouter ? bdrouter->router_id : htonl (0)); return next_state; } /* Interface State Machine */ int interface_up (struct thread *thread) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [InterfaceUp]", oi->interface->name); /* check physical interface is up */ if (! if_is_operative (oi->interface)) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s is down, can't execute [InterfaceUp]", oi->interface->name); return 0; } /* check interface has a link-local address */ if (! (ospf6_interface_get_linklocal_address(oi->interface) || if_is_loopback(oi->interface))) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s has no link local address, can't execute [InterfaceUp]", oi->interface->name); return 0; } /* Recompute cost */ ospf6_interface_recalculate_cost (oi); /* if already enabled, do nothing */ if (oi->state > OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface %s already enabled", oi->interface->name); return 0; } /* If no area assigned, return */ if (oi->area == NULL) { zlog_debug ("%s: Not scheduleing Hello for %s as there is no area assigned yet", __func__, oi->interface->name); return 0; } /* Join AllSPFRouters */ ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP); /* Update interface route */ ospf6_interface_connected_route_update (oi->interface); /* Schedule Hello */ if (! CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0); /* decide next interface state */ if ((if_is_pointopoint (oi->interface)) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) { ospf6_interface_state_change (OSPF6_INTERFACE_POINTTOPOINT, oi); } else if (oi->priority == 0) ospf6_interface_state_change (OSPF6_INTERFACE_DROTHER, oi); else { ospf6_interface_state_change (OSPF6_INTERFACE_WAITING, oi); thread_add_timer (master, wait_timer, oi, oi->dead_interval); } return 0; } int wait_timer (struct thread *thread) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [WaitTimer]", oi->interface->name); if (oi->state == OSPF6_INTERFACE_WAITING) ospf6_interface_state_change (dr_election (oi), oi); return 0; } int backup_seen (struct thread *thread) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [BackupSeen]", oi->interface->name); if (oi->state == OSPF6_INTERFACE_WAITING) ospf6_interface_state_change (dr_election (oi), oi); return 0; } int neighbor_change (struct thread *thread) { struct ospf6_interface *oi; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [NeighborChange]", oi->interface->name); if (oi->state == OSPF6_INTERFACE_DROTHER || oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR) ospf6_interface_state_change (dr_election (oi), oi); return 0; } int interface_down (struct thread *thread) { struct ospf6_interface *oi; struct listnode *node, *nnode; struct ospf6_neighbor *on; oi = (struct ospf6_interface *) THREAD_ARG (thread); assert (oi && oi->interface); if (IS_OSPF6_DEBUG_INTERFACE) zlog_debug ("Interface Event %s: [InterfaceDown]", oi->interface->name); /* Stop Hellos */ THREAD_OFF (oi->thread_send_hello); /* Leave AllSPFRouters */ if (oi->state > OSPF6_INTERFACE_DOWN) ospf6_sso (oi->interface->ifindex, &allspfrouters6, IPV6_LEAVE_GROUP); ospf6_interface_state_change (OSPF6_INTERFACE_DOWN, oi); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) ospf6_neighbor_delete (on); list_delete_all_node (oi->neighbor_list); /* When interface state is reset, also reset information about * DR election, as it is no longer valid. */ oi->drouter = oi->prev_drouter = htonl(0); oi->bdrouter = oi->prev_bdrouter = htonl(0); return 0; } /* show specified interface structure */ static int ospf6_interface_show (struct vty *vty, struct interface *ifp) { struct ospf6_interface *oi; struct connected *c; struct prefix *p; struct listnode *i; char strbuf[64], drouter[32], bdrouter[32]; const char *updown[3] = {"down", "up", NULL}; const char *type; struct timeval res, now; char duration[32]; struct ospf6_lsa *lsa; /* check physical interface type */ if (if_is_loopback (ifp)) type = "LOOPBACK"; else if (if_is_broadcast (ifp)) type = "BROADCAST"; else if (if_is_pointopoint (ifp)) type = "POINTOPOINT"; else type = "UNKNOWN"; vty_out (vty, "%s is %s, type %s%s", ifp->name, updown[if_is_operative (ifp)], type, VNL); vty_out (vty, " Interface ID: %d%s", ifp->ifindex, VNL); if (ifp->info == NULL) { vty_out (vty, " OSPF not enabled on this interface%s", VNL); return 0; } else oi = (struct ospf6_interface *) ifp->info; vty_out (vty, " Internet Address:%s", VNL); for (ALL_LIST_ELEMENTS_RO (ifp->connected, i, c)) { p = c->address; prefix2str (p, strbuf, sizeof (strbuf)); switch (p->family) { case AF_INET: vty_out (vty, " inet : %s%s", strbuf, VNL); break; case AF_INET6: vty_out (vty, " inet6: %s%s", strbuf, VNL); break; default: vty_out (vty, " ??? : %s%s", strbuf, VNL); break; } } if (oi->area) { vty_out (vty, " Instance ID %d, Interface MTU %d (autodetect: %d)%s", oi->instance_id, oi->ifmtu, ifp->mtu6, VNL); vty_out (vty, " MTU mismatch detection: %s%s", oi->mtu_ignore ? "disabled" : "enabled", VNL); inet_ntop (AF_INET, &oi->area->area_id, strbuf, sizeof (strbuf)); vty_out (vty, " Area ID %s, Cost %hu%s", strbuf, oi->cost, VNL); } else vty_out (vty, " Not Attached to Area%s", VNL); vty_out (vty, " State %s, Transmit Delay %d sec, Priority %d%s", ospf6_interface_state_str[oi->state], oi->transdelay, oi->priority, VNL); vty_out (vty, " Timer intervals configured:%s", VNL); vty_out (vty, " Hello %d, Dead %d, Retransmit %d%s", oi->hello_interval, oi->dead_interval, oi->rxmt_interval, VNL); inet_ntop (AF_INET, &oi->drouter, drouter, sizeof (drouter)); inet_ntop (AF_INET, &oi->bdrouter, bdrouter, sizeof (bdrouter)); vty_out (vty, " DR: %s BDR: %s%s", drouter, bdrouter, VNL); vty_out (vty, " Number of I/F scoped LSAs is %u%s", oi->lsdb->count, VNL); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timerclear (&res); if (oi->thread_send_lsupdate) timersub (&oi->thread_send_lsupdate->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSUpdate in Time %s [thread %s]%s", oi->lsupdate_list->count, duration, (oi->thread_send_lsupdate ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); timerclear (&res); if (oi->thread_send_lsack) timersub (&oi->thread_send_lsack->u.sands, &now, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, " %d Pending LSAs for LSAck in Time %s [thread %s]%s", oi->lsack_list->count, duration, (oi->thread_send_lsack ? "on" : "off"), VNL); for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa; lsa = ospf6_lsdb_next (lsa)) vty_out (vty, " %s%s", lsa->name, VNL); return 0; } /* show interface */ DEFUN (show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd, "show ipv6 ospf6 interface IFNAME", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR IFNAME_STR ) { struct interface *ifp; struct listnode *i; if (argc) { ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { vty_out (vty, "No such Interface: %s%s", argv[0], VNL); return CMD_WARNING; } ospf6_interface_show (vty, ifp); } else { for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) ospf6_interface_show (vty, ifp); } return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_cmd, "show ipv6 ospf6 interface", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR ) DEFUN (show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_cmd, "show ipv6 ospf6 interface IFNAME prefix", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR IFNAME_STR "Display connected prefixes to advertise\n" ) { struct interface *ifp; struct ospf6_interface *oi; ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { vty_out (vty, "No such Interface: %s%s", argv[0], VNL); return CMD_WARNING; } oi = ifp->info; if (oi == NULL) { vty_out (vty, "OSPFv3 is not enabled on %s%s", argv[0], VNL); return CMD_WARNING; } argc--; argv++; ospf6_route_table_show (vty, argc, argv, oi->route_connected); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_detail_cmd, "show ipv6 ospf6 interface IFNAME prefix (X:X::X:X|X:X::X:X/M|detail)", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR IFNAME_STR "Display connected prefixes to advertise\n" OSPF6_ROUTE_ADDRESS_STR OSPF6_ROUTE_PREFIX_STR "Display details of the prefixes\n" ) ALIAS (show_ipv6_ospf6_interface_ifname_prefix, show_ipv6_ospf6_interface_ifname_prefix_match_cmd, "show ipv6 ospf6 interface IFNAME prefix X:X::X:X/M (match|detail)", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR IFNAME_STR "Display connected prefixes to advertise\n" OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR "Display details of the prefixes\n" ) DEFUN (show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, "show ipv6 ospf6 interface prefix", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR "Display connected prefixes to advertise\n" ) { struct listnode *i; struct ospf6_interface *oi; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) { oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) continue; ospf6_route_table_show (vty, argc, argv, oi->route_connected); } return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_detail_cmd, "show ipv6 ospf6 interface prefix (X:X::X:X|X:X::X:X/M|detail)", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR "Display connected prefixes to advertise\n" OSPF6_ROUTE_ADDRESS_STR OSPF6_ROUTE_PREFIX_STR "Display details of the prefixes\n" ) ALIAS (show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_match_cmd, "show ipv6 ospf6 interface prefix X:X::X:X/M (match|detail)", SHOW_STR IP6_STR OSPF6_STR INTERFACE_STR "Display connected prefixes to advertise\n" OSPF6_ROUTE_PREFIX_STR OSPF6_ROUTE_MATCH_STR "Display details of the prefixes\n" ) /* interface variable set command */ DEFUN (ipv6_ospf6_ifmtu, ipv6_ospf6_ifmtu_cmd, "ipv6 ospf6 ifmtu <1-65535>", IP6_STR OSPF6_STR "Interface MTU\n" "OSPFv3 Interface MTU\n" ) { struct ospf6_interface *oi; struct interface *ifp; unsigned int ifmtu, iobuflen; struct listnode *node, *nnode; struct ospf6_neighbor *on; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); ifmtu = strtol (argv[0], NULL, 10); if (oi->ifmtu == ifmtu) return CMD_SUCCESS; if (ifp->mtu6 != 0 && ifp->mtu6 < ifmtu) { vty_out (vty, "%s's ospf6 ifmtu cannot go beyond physical mtu (%d)%s", ifp->name, ifp->mtu6, VNL); return CMD_WARNING; } if (oi->ifmtu < ifmtu) { iobuflen = ospf6_iobuf_size (ifmtu); if (iobuflen < ifmtu) { vty_out (vty, "%s's ifmtu is adjusted to I/O buffer size (%d).%s", ifp->name, iobuflen, VNL); oi->ifmtu = iobuflen; } else oi->ifmtu = ifmtu; } else oi->ifmtu = ifmtu; /* re-establish adjacencies */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { THREAD_OFF (on->inactivity_timer); thread_add_event (master, inactivity_timer, on, 0); } return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_ifmtu, no_ipv6_ospf6_ifmtu_cmd, "no ipv6 ospf6 ifmtu", NO_STR IP6_STR OSPF6_STR "Interface MTU\n" ) { struct ospf6_interface *oi; struct interface *ifp; unsigned int iobuflen; struct listnode *node, *nnode; struct ospf6_neighbor *on; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); if (oi->ifmtu < ifp->mtu) { iobuflen = ospf6_iobuf_size (ifp->mtu); if (iobuflen < ifp->mtu) { vty_out (vty, "%s's ifmtu is adjusted to I/O buffer size (%d).%s", ifp->name, iobuflen, VNL); oi->ifmtu = iobuflen; } else oi->ifmtu = ifp->mtu; } else oi->ifmtu = ifp->mtu; /* re-establish adjacencies */ for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { THREAD_OFF (on->inactivity_timer); thread_add_event (master, inactivity_timer, on, 0); } return CMD_SUCCESS; } DEFUN (ipv6_ospf6_cost, ipv6_ospf6_cost_cmd, "ipv6 ospf6 cost <1-65535>", IP6_STR OSPF6_STR "Interface cost\n" "Outgoing metric of this interface\n" ) { struct ospf6_interface *oi; struct interface *ifp; unsigned long int lcost; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); lcost = strtol (argv[0], NULL, 10); if (lcost > UINT32_MAX) { vty_out (vty, "Cost %ld is out of range%s", lcost, VNL); return CMD_WARNING; } if (oi->cost == lcost) return CMD_SUCCESS; oi->cost = lcost; SET_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST); ospf6_interface_recalculate_cost(oi); return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_cost, no_ipv6_ospf6_cost_cmd, "no ipv6 ospf6 cost", NO_STR IP6_STR OSPF6_STR "Calculate interface cost from bandwidth\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); UNSET_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST); ospf6_interface_recalculate_cost(oi); return CMD_SUCCESS; } DEFUN (auto_cost_reference_bandwidth, auto_cost_reference_bandwidth_cmd, "auto-cost reference-bandwidth <1-4294967>", "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") { struct ospf6 *o = vty->index; struct ospf6_area *oa; struct ospf6_interface *oi; struct listnode *i, *j; u_int32_t refbw; refbw = strtol (argv[0], NULL, 10); if (refbw < 1 || refbw > 4294967) { vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE); return CMD_WARNING; } /* If reference bandwidth is changed. */ if ((refbw * 1000) == o->ref_bandwidth) return CMD_SUCCESS; o->ref_bandwidth = refbw * 1000; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) ospf6_interface_recalculate_cost (oi); return CMD_SUCCESS; } DEFUN (no_auto_cost_reference_bandwidth, no_auto_cost_reference_bandwidth_cmd, "no auto-cost reference-bandwidth", NO_STR "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n") { struct ospf6 *o = vty->index; struct ospf6_area *oa; struct ospf6_interface *oi; struct listnode *i, *j; if (o->ref_bandwidth == OSPF6_REFERENCE_BANDWIDTH) return CMD_SUCCESS; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) ospf6_interface_recalculate_cost (oi); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_hellointerval, ipv6_ospf6_hellointerval_cmd, "ipv6 ospf6 hello-interval <1-65535>", IP6_STR OSPF6_STR "Interval time of Hello packets\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->hello_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_deadinterval, ipv6_ospf6_deadinterval_cmd, "ipv6 ospf6 dead-interval <1-65535>", IP6_STR OSPF6_STR "Interval time after which a neighbor is declared down\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->dead_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_transmitdelay, ipv6_ospf6_transmitdelay_cmd, "ipv6 ospf6 transmit-delay <1-3600>", IP6_STR OSPF6_STR "Transmit delay of this interface\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->transdelay = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_retransmitinterval, ipv6_ospf6_retransmitinterval_cmd, "ipv6 ospf6 retransmit-interval <1-65535>", IP6_STR OSPF6_STR "Time between retransmitting lost link state advertisements\n" SECONDS_STR ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->rxmt_interval = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } /* interface variable set command */ DEFUN (ipv6_ospf6_priority, ipv6_ospf6_priority_cmd, "ipv6 ospf6 priority <0-255>", IP6_STR OSPF6_STR "Router priority\n" "Priority value\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->priority = strtol (argv[0], NULL, 10); if (oi->area && (oi->state == OSPF6_INTERFACE_DROTHER || oi->state == OSPF6_INTERFACE_BDR || oi->state == OSPF6_INTERFACE_DR)) ospf6_interface_state_change (dr_election (oi), oi); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_instance, ipv6_ospf6_instance_cmd, "ipv6 ospf6 instance-id <0-255>", IP6_STR OSPF6_STR "Instance ID for this interface\n" "Instance ID value\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *)vty->index; assert (ifp); oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->instance_id = strtol (argv[0], NULL, 10); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_passive, ipv6_ospf6_passive_cmd, "ipv6 ospf6 passive", IP6_STR OSPF6_STR "passive interface, No adjacency will be formed on this interface\n" ) { struct ospf6_interface *oi; struct interface *ifp; struct listnode *node, *nnode; struct ospf6_neighbor *on; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); SET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE); THREAD_OFF (oi->thread_send_hello); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { THREAD_OFF (on->inactivity_timer); thread_add_event (master, inactivity_timer, on, 0); } return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_passive, no_ipv6_ospf6_passive_cmd, "no ipv6 ospf6 passive", NO_STR IP6_STR OSPF6_STR "passive interface: No Adjacency will be formed on this I/F\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); UNSET_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE); THREAD_OFF (oi->thread_send_hello); oi->thread_send_hello = thread_add_event (master, ospf6_hello_send, oi, 0); return CMD_SUCCESS; } DEFUN (ipv6_ospf6_mtu_ignore, ipv6_ospf6_mtu_ignore_cmd, "ipv6 ospf6 mtu-ignore", IP6_STR OSPF6_STR "Ignore MTU mismatch on this interface\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->mtu_ignore = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_mtu_ignore, no_ipv6_ospf6_mtu_ignore_cmd, "no ipv6 ospf6 mtu-ignore", NO_STR IP6_STR OSPF6_STR "Ignore MTU mismatch on this interface\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); oi->mtu_ignore = 0; return CMD_SUCCESS; } DEFUN (ipv6_ospf6_advertise_prefix_list, ipv6_ospf6_advertise_prefix_list_cmd, "ipv6 ospf6 advertise prefix-list WORD", IP6_STR OSPF6_STR "Advertising options\n" "Filter prefix using prefix-list\n" "Prefix list name\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); if (oi->plist_name) XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); oi->plist_name = XSTRDUP (MTYPE_PREFIX_LIST_STR, argv[0]); ospf6_interface_connected_route_update (oi->interface); if (oi->area) { OSPF6_LINK_LSA_SCHEDULE (oi); if (oi->state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); } OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_advertise_prefix_list, no_ipv6_ospf6_advertise_prefix_list_cmd, "no ipv6 ospf6 advertise prefix-list", NO_STR IP6_STR OSPF6_STR "Advertising options\n" "Filter prefix using prefix-list\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); assert (oi); if (oi->plist_name) { XFREE (MTYPE_PREFIX_LIST_STR, oi->plist_name); oi->plist_name = NULL; } ospf6_interface_connected_route_update (oi->interface); if (oi->area) { OSPF6_LINK_LSA_SCHEDULE (oi); if (oi->state == OSPF6_INTERFACE_DR) { OSPF6_NETWORK_LSA_SCHEDULE (oi); OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT (oi); } OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB (oi->area); } return CMD_SUCCESS; } DEFUN (ipv6_ospf6_network, ipv6_ospf6_network_cmd, "ipv6 ospf6 network (broadcast|point-to-point)", IP6_STR OSPF6_STR "Network Type\n" "Specify OSPFv6 broadcast network\n" "Specify OSPF6 point-to-point network\n" ) { struct ospf6_interface *oi; struct interface *ifp; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) { oi = ospf6_interface_create (ifp); } assert (oi); if (strncmp (argv[0], "b", 1) == 0) { if (oi->type == OSPF_IFTYPE_BROADCAST) return CMD_SUCCESS; oi->type = OSPF_IFTYPE_BROADCAST; } else if (strncmp (argv[0], "point-to-p", 10) == 0) { if (oi->type == OSPF_IFTYPE_POINTOPOINT) { return CMD_SUCCESS; } oi->type = OSPF_IFTYPE_POINTOPOINT; } /* Reset the interface */ thread_add_event (master, interface_down, oi, 0); thread_add_event (master, interface_up, oi, 0); return CMD_SUCCESS; } DEFUN (no_ipv6_ospf6_network, no_ipv6_ospf6_network_cmd, "no ipv6 ospf6 network", NO_STR IP6_STR OSPF6_STR "Network Type\n" "Default to whatever interface type system specifies" ) { struct ospf6_interface *oi; struct interface *ifp; int type; ifp = (struct interface *) vty->index; assert (ifp); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) { return CMD_SUCCESS; } type = ospf6_default_iftype (ifp); if (oi->type == type) { return CMD_SUCCESS; } oi->type = type; /* Reset the interface */ thread_add_event (master, interface_down, oi, 0); thread_add_event (master, interface_up, oi, 0); return CMD_SUCCESS; } static int config_write_ospf6_interface (struct vty *vty) { struct listnode *i; struct ospf6_interface *oi; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, i, ifp)) { oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) continue; vty_out (vty, "interface %s%s", oi->interface->name, VNL); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VNL); if (ifp->mtu6 != oi->ifmtu) vty_out (vty, " ipv6 ospf6 ifmtu %d%s", oi->ifmtu, VNL); if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_NOAUTOCOST)) vty_out (vty, " ipv6 ospf6 cost %d%s", oi->cost, VNL); if (oi->hello_interval != OSPF6_INTERFACE_HELLO_INTERVAL) vty_out (vty, " ipv6 ospf6 hello-interval %d%s", oi->hello_interval, VNL); if (oi->dead_interval != OSPF6_INTERFACE_DEAD_INTERVAL) vty_out (vty, " ipv6 ospf6 dead-interval %d%s", oi->dead_interval, VNL); if (oi->rxmt_interval != OSPF6_INTERFACE_RXMT_INTERVAL) vty_out (vty, " ipv6 ospf6 retransmit-interval %d%s", oi->rxmt_interval, VNL); if (oi->priority != OSPF6_INTERFACE_PRIORITY) vty_out (vty, " ipv6 ospf6 priority %d%s", oi->priority, VNL); if (oi->transdelay != OSPF6_INTERFACE_TRANSDELAY) vty_out (vty, " ipv6 ospf6 transmit-delay %d%s", oi->transdelay, VNL); if (oi->instance_id != OSPF6_INTERFACE_INSTANCE_ID) vty_out (vty, " ipv6 ospf6 instance-id %d%s", oi->instance_id, VNL); if (oi->plist_name) vty_out (vty, " ipv6 ospf6 advertise prefix-list %s%s", oi->plist_name, VNL); if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) vty_out (vty, " ipv6 ospf6 passive%s", VNL); if (oi->mtu_ignore) vty_out (vty, " ipv6 ospf6 mtu-ignore%s", VNL); if (oi->type == OSPF_IFTYPE_POINTOPOINT) vty_out (vty, " ipv6 ospf6 network point-to-point%s", VNL); else if (oi->type == OSPF_IFTYPE_BROADCAST) vty_out (vty, " ipv6 ospf6 network broadcast%s", VNL); vty_out (vty, "!%s", VNL); } return 0; } static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; void ospf6_interface_init (void) { /* Install interface node. */ install_node (&interface_node, config_write_ospf6_interface); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_prefix_match_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_interface_ifname_prefix_match_cmd); install_element (CONFIG_NODE, &interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_ifmtu_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_deadinterval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_hellointerval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_priority_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_retransmitinterval_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_transmitdelay_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_instance_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_passive_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_passive_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_mtu_ignore_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_mtu_ignore_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_advertise_prefix_list_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_advertise_prefix_list_cmd); install_element (INTERFACE_NODE, &ipv6_ospf6_network_cmd); install_element (INTERFACE_NODE, &no_ipv6_ospf6_network_cmd); /* reference bandwidth commands */ install_element (OSPF6_NODE, &auto_cost_reference_bandwidth_cmd); install_element (OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd); } DEFUN (debug_ospf6_interface, debug_ospf6_interface_cmd, "debug ospf6 interface", DEBUG_STR OSPF6_STR "Debug OSPFv3 Interface\n" ) { OSPF6_DEBUG_INTERFACE_ON (); return CMD_SUCCESS; } DEFUN (no_debug_ospf6_interface, no_debug_ospf6_interface_cmd, "no debug ospf6 interface", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 Interface\n" ) { OSPF6_DEBUG_INTERFACE_OFF (); return CMD_SUCCESS; } int config_write_ospf6_debug_interface (struct vty *vty) { if (IS_OSPF6_DEBUG_INTERFACE) vty_out (vty, "debug ospf6 interface%s", VNL); return 0; } void install_element_ospf6_debug_interface (void) { install_element (ENABLE_NODE, &debug_ospf6_interface_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_interface_cmd); install_element (CONFIG_NODE, &debug_ospf6_interface_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_interface_cmd); } quagga-0.99.24.1/ospf6d/ospf6_area.c0000644000175000017500000005302412476520570013632 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "linklist.h" #include "thread.h" #include "vty.h" #include "command.h" #include "if.h" #include "prefix.h" #include "table.h" #include "plist.h" #include "filter.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_spf.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_intra.h" #include "ospf6_abr.h" #include "ospf6d.h" int ospf6_area_cmp (void *va, void *vb) { struct ospf6_area *oa = (struct ospf6_area *) va; struct ospf6_area *ob = (struct ospf6_area *) vb; return (ntohl (oa->area_id) < ntohl (ob->area_id) ? -1 : 1); } /* schedule routing table recalculation */ static void ospf6_area_lsdb_hook_add (struct ospf6_lsa *lsa) { switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: case OSPF6_LSTYPE_NETWORK: if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) { zlog_debug ("Examin %s", lsa->name); zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), ospf6_lsadd_to_spf_reason(lsa)); break; case OSPF6_LSTYPE_INTRA_PREFIX: ospf6_intra_prefix_lsa_add (lsa); break; case OSPF6_LSTYPE_INTER_PREFIX: case OSPF6_LSTYPE_INTER_ROUTER: ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); break; default: break; } } static void ospf6_area_lsdb_hook_remove (struct ospf6_lsa *lsa) { switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: case OSPF6_LSTYPE_NETWORK: if (IS_OSPF6_DEBUG_EXAMIN_TYPE (lsa->header->type)) { zlog_debug ("LSA disappearing: %s", lsa->name); zlog_debug ("Schedule SPF Calculation for %s", OSPF6_AREA (lsa->lsdb->data)->name); } ospf6_spf_schedule (OSPF6_PROCESS(OSPF6_AREA (lsa->lsdb->data)->ospf6), ospf6_lsremove_to_spf_reason(lsa)); break; case OSPF6_LSTYPE_INTRA_PREFIX: ospf6_intra_prefix_lsa_remove (lsa); break; case OSPF6_LSTYPE_INTER_PREFIX: case OSPF6_LSTYPE_INTER_ROUTER: ospf6_abr_examin_summary (lsa, (struct ospf6_area *) lsa->lsdb->data); break; default: break; } } static void ospf6_area_route_hook_add (struct ospf6_route *route) { struct ospf6_route *copy = ospf6_route_copy (route); ospf6_route_add (copy, ospf6->route_table); } static void ospf6_area_route_hook_remove (struct ospf6_route *route) { struct ospf6_route *copy; copy = ospf6_route_lookup_identical (route, ospf6->route_table); if (copy) ospf6_route_remove (copy, ospf6->route_table); } /* Make new area structure */ struct ospf6_area * ospf6_area_create (u_int32_t area_id, struct ospf6 *o) { struct ospf6_area *oa; struct ospf6_route *route; oa = XCALLOC (MTYPE_OSPF6_AREA, sizeof (struct ospf6_area)); inet_ntop (AF_INET, &area_id, oa->name, sizeof (oa->name)); oa->area_id = area_id; oa->if_list = list_new (); oa->lsdb = ospf6_lsdb_create (oa); oa->lsdb->hook_add = ospf6_area_lsdb_hook_add; oa->lsdb->hook_remove = ospf6_area_lsdb_hook_remove; oa->lsdb_self = ospf6_lsdb_create (oa); oa->spf_table = OSPF6_ROUTE_TABLE_CREATE (AREA, SPF_RESULTS); oa->spf_table->scope = oa; oa->route_table = OSPF6_ROUTE_TABLE_CREATE (AREA, ROUTES); oa->route_table->scope = oa; oa->route_table->hook_add = ospf6_area_route_hook_add; oa->route_table->hook_remove = ospf6_area_route_hook_remove; oa->range_table = OSPF6_ROUTE_TABLE_CREATE (AREA, PREFIX_RANGES); oa->range_table->scope = oa; oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_PREFIXES); oa->summary_prefix->scope = oa; oa->summary_router = OSPF6_ROUTE_TABLE_CREATE (AREA, SUMMARY_ROUTERS); oa->summary_router->scope = oa; /* set default options */ if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) { OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); } else { OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); } OSPF6_OPT_SET (oa->options, OSPF6_OPT_E); oa->ospf6 = o; listnode_add_sort (o->area_list, oa); /* import athoer area's routes as inter-area routes */ for (route = ospf6_route_head (o->route_table); route; route = ospf6_route_next (route)) ospf6_abr_originate_summary_to_area (route, oa); return oa; } void ospf6_area_delete (struct ospf6_area *oa) { struct listnode *n; struct ospf6_interface *oi; ospf6_route_table_delete (oa->range_table); ospf6_route_table_delete (oa->summary_prefix); ospf6_route_table_delete (oa->summary_router); /* The ospf6_interface structs store configuration * information which should not be lost/reset when * deleting an area. * So just detach the interface from the area and * keep it around. */ for (ALL_LIST_ELEMENTS_RO (oa->if_list, n, oi)) oi->area = NULL; list_delete (oa->if_list); ospf6_lsdb_delete (oa->lsdb); ospf6_lsdb_delete (oa->lsdb_self); ospf6_spf_table_finish (oa->spf_table); ospf6_route_table_delete (oa->spf_table); ospf6_route_table_delete (oa->route_table); THREAD_OFF (oa->thread_spf_calculation); THREAD_OFF (oa->thread_route_calculation); listnode_delete (oa->ospf6->area_list, oa); oa->ospf6 = NULL; /* free area */ XFREE (MTYPE_OSPF6_AREA, oa); } struct ospf6_area * ospf6_area_lookup (u_int32_t area_id, struct ospf6 *ospf6) { struct ospf6_area *oa; struct listnode *n; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, n, oa)) if (oa->area_id == area_id) return oa; return (struct ospf6_area *) NULL; } static struct ospf6_area * ospf6_area_get (u_int32_t area_id, struct ospf6 *o) { struct ospf6_area *oa; oa = ospf6_area_lookup (area_id, o); if (oa == NULL) oa = ospf6_area_create (area_id, o); return oa; } void ospf6_area_enable (struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_enable (oi); ospf6_abr_enable_area (oa); } void ospf6_area_disable (struct ospf6_area *oa) { struct listnode *node, *nnode; struct ospf6_interface *oi; UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE); for (ALL_LIST_ELEMENTS (oa->if_list, node, nnode, oi)) ospf6_interface_disable (oi); ospf6_abr_disable_area (oa); ospf6_lsdb_remove_all (oa->lsdb); ospf6_lsdb_remove_all (oa->lsdb_self); ospf6_spf_table_finish(oa->spf_table); ospf6_route_remove_all(oa->route_table); THREAD_OFF (oa->thread_spf_calculation); THREAD_OFF (oa->thread_route_calculation); THREAD_OFF (oa->thread_router_lsa); THREAD_OFF (oa->thread_intra_prefix_lsa); } void ospf6_area_show (struct vty *vty, struct ospf6_area *oa) { struct listnode *i; struct ospf6_interface *oi; vty_out (vty, " Area %s%s", oa->name, VNL); vty_out (vty, " Number of Area scoped LSAs is %u%s", oa->lsdb->count, VNL); vty_out (vty, " Interface attached to this area:"); for (ALL_LIST_ELEMENTS_RO (oa->if_list, i, oi)) vty_out (vty, " %s", oi->interface->name); vty_out (vty, "%s", VNL); } #define OSPF6_CMD_AREA_LOOKUP(str, oa) \ { \ u_int32_t area_id = 0; \ if (inet_pton (AF_INET, str, &area_id) != 1) \ { \ vty_out (vty, "Malformed Area-ID: %s%s", str, VNL); \ return CMD_SUCCESS; \ } \ oa = ospf6_area_lookup (area_id, ospf6); \ if (oa == NULL) \ { \ vty_out (vty, "No such Area: %s%s", str, VNL); \ return CMD_SUCCESS; \ } \ } #define OSPF6_CMD_AREA_GET(str, oa) \ { \ u_int32_t area_id = 0; \ if (inet_pton (AF_INET, str, &area_id) != 1) \ { \ vty_out (vty, "Malformed Area-ID: %s%s", str, VNL); \ return CMD_SUCCESS; \ } \ oa = ospf6_area_get (area_id, ospf6); \ } DEFUN (area_range, area_range_cmd, "area A.B.C.D range X:X::X:X/M", "OSPF area parameters\n" OSPF6_AREA_ID_STR "Configured address range\n" "Specify IPv6 prefix\n" ) { int ret; struct ospf6_area *oa; struct prefix prefix; struct ospf6_route *range; OSPF6_CMD_AREA_GET (argv[0], oa); argc--; argv++; ret = str2prefix (argv[0], &prefix); if (ret != 1 || prefix.family != AF_INET6) { vty_out (vty, "Malformed argument: %s%s", argv[0], VNL); return CMD_SUCCESS; } argc--; argv++; range = ospf6_route_lookup (&prefix, oa->range_table); if (range == NULL) { range = ospf6_route_create (); range->type = OSPF6_DEST_TYPE_RANGE; range->prefix = prefix; } if (argc) { if (! strcmp (argv[0], "not-advertise")) SET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); else if (! strcmp (argv[0], "advertise")) UNSET_FLAG (range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); } if (range->rnode) { vty_out (vty, "Range already defined: %s%s", argv[-1], VNL); return CMD_WARNING; } ospf6_route_add (range, oa->range_table); return CMD_SUCCESS; } ALIAS (area_range, area_range_advertise_cmd, "area A.B.C.D range X:X::X:X/M (advertise|not-advertise)", "OSPF area parameters\n" OSPF6_AREA_ID_STR "Configured address range\n" "Specify IPv6 prefix\n" ) DEFUN (no_area_range, no_area_range_cmd, "no area A.B.C.D range X:X::X:X/M", "OSPF area parameters\n" OSPF6_AREA_ID_STR "Configured address range\n" "Specify IPv6 prefix\n" ) { int ret; struct ospf6_area *oa; struct prefix prefix; struct ospf6_route *range; OSPF6_CMD_AREA_GET (argv[0], oa); argc--; argv++; ret = str2prefix (argv[0], &prefix); if (ret != 1 || prefix.family != AF_INET6) { vty_out (vty, "Malformed argument: %s%s", argv[0], VNL); return CMD_SUCCESS; } range = ospf6_route_lookup (&prefix, oa->range_table); if (range == NULL) { vty_out (vty, "Range %s does not exists.%s", argv[0], VNL); return CMD_SUCCESS; } ospf6_route_remove (range, oa->range_table); return CMD_SUCCESS; } void ospf6_area_config_write (struct vty *vty) { struct listnode *node; struct ospf6_area *oa; struct ospf6_route *range; char buf[128]; for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { for (range = ospf6_route_head (oa->range_table); range; range = ospf6_route_next (range)) { prefix2str (&range->prefix, buf, sizeof (buf)); vty_out (vty, " area %s range %s%s", oa->name, buf, VNL); } if (PREFIX_NAME_IN (oa)) vty_out (vty, " area %s filter-list prefix %s in%s", oa->name, PREFIX_NAME_IN (oa), VNL); if (PREFIX_NAME_OUT (oa)) vty_out (vty, " area %s filter-list prefix %s out%s", oa->name, PREFIX_NAME_OUT (oa), VNL); if (IMPORT_NAME (oa)) vty_out (vty, " area %s import-list %s%s", oa->name, IMPORT_NAME (oa), VNL); if (EXPORT_NAME (oa)) vty_out (vty, " area %s export-list %s%s", oa->name, EXPORT_NAME (oa), VNL); } } DEFUN (area_filter_list, area_filter_list_cmd, "area A.B.C.D filter-list prefix WORD (in|out)", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Filter networks between OSPFv6 areas\n" "Filter prefixes between OSPFv6 areas\n" "Name of an IPv6 prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") { struct ospf6_area *area; struct prefix_list *plist; OSPF6_CMD_AREA_GET (argv[0], area); argc--; argv++; plist = prefix_list_lookup (AFI_IP6, argv[0]); if (strncmp (argv[1], "in", 2) == 0) { PREFIX_LIST_IN (area) = plist; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); PREFIX_NAME_IN (area) = strdup (argv[0]); ospf6_abr_reimport (area); } else { PREFIX_LIST_OUT (area) = plist; if (PREFIX_NAME_OUT (area)) free (PREFIX_NAME_OUT (area)); PREFIX_NAME_OUT (area) = strdup (argv[0]); ospf6_abr_enable_area (area); } return CMD_SUCCESS; } DEFUN (no_area_filter_list, no_area_filter_list_cmd, "no area A.B.C.D filter-list prefix WORD (in|out)", NO_STR "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Filter networks between OSPFv6 areas\n" "Filter prefixes between OSPFv6 areas\n" "Name of an IPv6 prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") { struct ospf6_area *area; OSPF6_CMD_AREA_GET (argv[0], area); argc--; argv++; if (strncmp (argv[1], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) if (strcmp (PREFIX_NAME_IN (area), argv[0]) != 0) return CMD_SUCCESS; PREFIX_LIST_IN (area) = NULL; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); PREFIX_NAME_IN (area) = NULL; ospf6_abr_reimport (area); } else { if (PREFIX_NAME_OUT (area)) if (strcmp (PREFIX_NAME_OUT (area), argv[0]) != 0) return CMD_SUCCESS; PREFIX_LIST_OUT (area) = NULL; if (PREFIX_NAME_OUT (area)) free (PREFIX_NAME_OUT (area)); PREFIX_NAME_OUT (area) = NULL; ospf6_abr_enable_area (area); } return CMD_SUCCESS; } DEFUN (area_import_list, area_import_list_cmd, "area A.B.C.D import-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Set the filter for networks from other areas announced to the specified one\n" "Name of the acess-list\n") { struct ospf6_area *area; struct access_list *list; OSPF6_CMD_AREA_GET(argv[0], area); list = access_list_lookup (AFI_IP6, argv[1]); IMPORT_LIST (area) = list; if (IMPORT_NAME (area)) free (IMPORT_NAME (area)); IMPORT_NAME (area) = strdup (argv[1]); ospf6_abr_reimport (area); return CMD_SUCCESS; } DEFUN (no_area_import_list, no_area_import_list_cmd, "no area A.B.C.D import-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Unset the filter for networks announced to other areas\n" "NAme of the access-list\n") { struct ospf6_area *area; OSPF6_CMD_AREA_GET(argv[0], area); IMPORT_LIST (area) = 0; if (IMPORT_NAME (area)) free (IMPORT_NAME (area)); IMPORT_NAME (area) = NULL; ospf6_abr_reimport (area); return CMD_SUCCESS; } DEFUN (area_export_list, area_export_list_cmd, "area A.B.C.D export-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Set the filter for networks announced to other areas\n" "Name of the acess-list\n") { struct ospf6_area *area; struct access_list *list; OSPF6_CMD_AREA_GET(argv[0], area); list = access_list_lookup (AFI_IP6, argv[1]); EXPORT_LIST (area) = list; if (EXPORT_NAME (area)) free (EXPORT_NAME (area)); EXPORT_NAME (area) = strdup (argv[1]); ospf6_abr_enable_area (area); return CMD_SUCCESS; } DEFUN (no_area_export_list, no_area_export_list_cmd, "no area A.B.C.D export-list NAME", "OSPFv6 area parameters\n" "OSPFv6 area ID in IP address format\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") { struct ospf6_area *area; OSPF6_CMD_AREA_GET(argv[0], area); EXPORT_LIST (area) = 0; if (EXPORT_NAME (area)) free (EXPORT_NAME (area)); EXPORT_NAME (area) = NULL; ospf6_abr_enable_area (area); return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_spf_tree, show_ipv6_ospf6_spf_tree_cmd, "show ipv6 ospf6 spf tree", SHOW_STR IP6_STR OSPF6_STR "Shortest Path First caculation\n" "Show SPF tree\n") { struct listnode *node; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { route = ospf6_route_lookup (&prefix, oa->spf_table); if (route == NULL) { vty_out (vty, "LS entry for root not found in area %s%s", oa->name, VNL); continue; } root = (struct ospf6_vertex *) route->route_option; ospf6_spf_display_subtree (vty, "", 0, root); } return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_area_spf_tree, show_ipv6_ospf6_area_spf_tree_cmd, "show ipv6 ospf6 area A.B.C.D spf tree", SHOW_STR IP6_STR OSPF6_STR OSPF6_AREA_STR OSPF6_AREA_ID_STR "Shortest Path First caculation\n" "Show SPF tree\n") { u_int32_t area_id; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; ospf6_linkstate_prefix (ospf6->router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[0], &area_id) != 1) { vty_out (vty, "Malformed Area-ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } oa = ospf6_area_lookup (area_id, ospf6); if (oa == NULL) { vty_out (vty, "No such Area: %s%s", argv[0], VNL); return CMD_SUCCESS; } route = ospf6_route_lookup (&prefix, oa->spf_table); if (route == NULL) { vty_out (vty, "LS entry for root not found in area %s%s", oa->name, VNL); return CMD_SUCCESS; } root = (struct ospf6_vertex *) route->route_option; ospf6_spf_display_subtree (vty, "", 0, root); return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_simulate_spf_tree_root, show_ipv6_ospf6_simulate_spf_tree_root_cmd, "show ipv6 ospf6 simulate spf-tree A.B.C.D area A.B.C.D", SHOW_STR IP6_STR OSPF6_STR "Shortest Path First caculation\n" "Show SPF tree\n" "Specify root's router-id to calculate another router's SPF tree\n") { u_int32_t area_id; struct ospf6_area *oa; struct ospf6_vertex *root; struct ospf6_route *route; struct prefix prefix; u_int32_t router_id; struct ospf6_route_table *spf_table; unsigned char tmp_debug_ospf6_spf = 0; inet_pton (AF_INET, argv[0], &router_id); ospf6_linkstate_prefix (router_id, htonl (0), &prefix); if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Malformed Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } oa = ospf6_area_lookup (area_id, ospf6); if (oa == NULL) { vty_out (vty, "No such Area: %s%s", argv[1], VNL); return CMD_SUCCESS; } tmp_debug_ospf6_spf = conf_debug_ospf6_spf; conf_debug_ospf6_spf = 0; spf_table = OSPF6_ROUTE_TABLE_CREATE (NONE, SPF_RESULTS); ospf6_spf_calculation (router_id, spf_table, oa); conf_debug_ospf6_spf = tmp_debug_ospf6_spf; route = ospf6_route_lookup (&prefix, spf_table); if (route == NULL) { ospf6_spf_table_finish (spf_table); ospf6_route_table_delete (spf_table); return CMD_SUCCESS; } root = (struct ospf6_vertex *) route->route_option; ospf6_spf_display_subtree (vty, "", 0, root); ospf6_spf_table_finish (spf_table); ospf6_route_table_delete (spf_table); return CMD_SUCCESS; } void ospf6_area_init (void) { install_element (VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_spf_tree_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_area_spf_tree_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_simulate_spf_tree_root_cmd); install_element (OSPF6_NODE, &area_range_cmd); install_element (OSPF6_NODE, &area_range_advertise_cmd); install_element (OSPF6_NODE, &no_area_range_cmd); install_element (OSPF6_NODE, &area_import_list_cmd); install_element (OSPF6_NODE, &no_area_import_list_cmd); install_element (OSPF6_NODE, &area_export_list_cmd); install_element (OSPF6_NODE, &no_area_export_list_cmd); install_element (OSPF6_NODE, &area_filter_list_cmd); install_element (OSPF6_NODE, &no_area_filter_list_cmd); } quagga-0.99.24.1/ospf6d/ospf6_top.c0000644000175000017500000006227612476520570013535 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "vty.h" #include "linklist.h" #include "prefix.h" #include "table.h" #include "thread.h" #include "command.h" #include "ospf6_proto.h" #include "ospf6_message.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_route.h" #include "ospf6_zebra.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_flood.h" #include "ospf6_asbr.h" #include "ospf6_abr.h" #include "ospf6_intra.h" #include "ospf6_spf.h" #include "ospf6d.h" /* global ospf6d variable */ struct ospf6 *ospf6; static void ospf6_disable (struct ospf6 *o); static void ospf6_top_lsdb_hook_add (struct ospf6_lsa *lsa) { switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_AS_EXTERNAL: ospf6_asbr_lsa_add (lsa); break; default: break; } } static void ospf6_top_lsdb_hook_remove (struct ospf6_lsa *lsa) { switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_AS_EXTERNAL: ospf6_asbr_lsa_remove (lsa); break; default: break; } } static void ospf6_top_route_hook_add (struct ospf6_route *route) { ospf6_abr_originate_summary (route); ospf6_zebra_route_update_add (route); } static void ospf6_top_route_hook_remove (struct ospf6_route *route) { ospf6_abr_originate_summary (route); ospf6_zebra_route_update_remove (route); } static void ospf6_top_brouter_hook_add (struct ospf6_route *route) { ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix)); ospf6_asbr_lsentry_add (route); ospf6_abr_originate_summary (route); } static void ospf6_top_brouter_hook_remove (struct ospf6_route *route) { ospf6_abr_examin_brouter (ADV_ROUTER_IN_PREFIX (&route->prefix)); ospf6_asbr_lsentry_remove (route); ospf6_abr_originate_summary (route); } static struct ospf6 * ospf6_create (void) { struct ospf6 *o; o = XCALLOC (MTYPE_OSPF6_TOP, sizeof (struct ospf6)); /* initialize */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &o->starttime); o->area_list = list_new (); o->area_list->cmp = ospf6_area_cmp; o->lsdb = ospf6_lsdb_create (o); o->lsdb_self = ospf6_lsdb_create (o); o->lsdb->hook_add = ospf6_top_lsdb_hook_add; o->lsdb->hook_remove = ospf6_top_lsdb_hook_remove; o->spf_delay = OSPF_SPF_DELAY_DEFAULT; o->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; o->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; o->spf_hold_multiplier = 1; o->route_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, ROUTES); o->route_table->scope = o; o->route_table->hook_add = ospf6_top_route_hook_add; o->route_table->hook_remove = ospf6_top_route_hook_remove; o->brouter_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, BORDER_ROUTERS); o->brouter_table->scope = o; o->brouter_table->hook_add = ospf6_top_brouter_hook_add; o->brouter_table->hook_remove = ospf6_top_brouter_hook_remove; o->external_table = OSPF6_ROUTE_TABLE_CREATE (GLOBAL, EXTERNAL_ROUTES); o->external_table->scope = o; o->external_id_table = route_table_init (); o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; return o; } void ospf6_delete (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; ospf6_disable (ospf6); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_delete (oa); list_delete (o->area_list); ospf6_lsdb_delete (o->lsdb); ospf6_lsdb_delete (o->lsdb_self); ospf6_route_table_delete (o->route_table); ospf6_route_table_delete (o->brouter_table); ospf6_route_table_delete (o->external_table); route_table_finish (o->external_id_table); XFREE (MTYPE_OSPF6_TOP, o); } static void __attribute__((unused)) ospf6_enable (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) { UNSET_FLAG (o->flag, OSPF6_DISABLED); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_enable (oa); } } static void ospf6_disable (struct ospf6 *o) { struct listnode *node, *nnode; struct ospf6_area *oa; if (! CHECK_FLAG (o->flag, OSPF6_DISABLED)) { SET_FLAG (o->flag, OSPF6_DISABLED); for (ALL_LIST_ELEMENTS (o->area_list, node, nnode, oa)) ospf6_area_disable (oa); /* XXX: This also changes persistent settings */ ospf6_asbr_redistribute_reset(); ospf6_lsdb_remove_all (o->lsdb); ospf6_route_remove_all (o->route_table); ospf6_route_remove_all (o->brouter_table); THREAD_OFF(o->maxage_remover); THREAD_OFF(o->t_spf_calc); THREAD_OFF(o->t_ase_calc); } } static int ospf6_maxage_remover (struct thread *thread) { struct ospf6 *o = (struct ospf6 *) THREAD_ARG (thread); struct ospf6_area *oa; struct ospf6_interface *oi; struct ospf6_neighbor *on; struct listnode *i, *j, *k; int reschedule = 0; o->maxage_remover = (struct thread *) NULL; for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { for (ALL_LIST_ELEMENTS_RO (oi->neighbor_list, k, on)) { if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING) continue; ospf6_maxage_remove (o); return 0; } } } for (ALL_LIST_ELEMENTS_RO (o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, j, oi)) { if (ospf6_lsdb_maxage_remover (oi->lsdb)) { reschedule = 1; } } if (ospf6_lsdb_maxage_remover (oa->lsdb)) { reschedule = 1; } } if (ospf6_lsdb_maxage_remover (o->lsdb)) { reschedule = 1; } if (reschedule) { ospf6_maxage_remove (o); } return 0; } void ospf6_maxage_remove (struct ospf6 *o) { if (o && ! o->maxage_remover) o->maxage_remover = thread_add_timer (master, ospf6_maxage_remover, o, OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT); } /* start ospf6 */ DEFUN (router_ospf6, router_ospf6_cmd, "router ospf6", ROUTER_STR OSPF6_STR) { if (ospf6 == NULL) ospf6 = ospf6_create (); /* set current ospf point. */ vty->node = OSPF6_NODE; vty->index = ospf6; return CMD_SUCCESS; } /* stop ospf6 */ DEFUN (no_router_ospf6, no_router_ospf6_cmd, "no router ospf6", NO_STR OSPF6_ROUTER_STR) { if (ospf6 == NULL) vty_out (vty, "OSPFv3 is not configured%s", VNL); else { ospf6_delete (ospf6); ospf6 = NULL; } /* return to config node . */ vty->node = CONFIG_NODE; vty->index = NULL; return CMD_SUCCESS; } /* change Router_ID commands. */ DEFUN (ospf6_router_id, ospf6_router_id_cmd, "router-id A.B.C.D", "Configure OSPF Router-ID\n" V4NOTATION_STR) { int ret; u_int32_t router_id; struct ospf6 *o; o = (struct ospf6 *) vty->index; ret = inet_pton (AF_INET, argv[0], &router_id); if (ret == 0) { vty_out (vty, "malformed OSPF Router-ID: %s%s", argv[0], VNL); return CMD_SUCCESS; } o->router_id_static = router_id; if (o->router_id == 0) o->router_id = router_id; return CMD_SUCCESS; } DEFUN (ospf6_log_adjacency_changes, ospf6_log_adjacency_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct ospf6 *ospf6 = vty->index; SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (ospf6_log_adjacency_changes_detail, ospf6_log_adjacency_changes_detail_cmd, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf6 *ospf6 = vty->index; SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (no_ospf6_log_adjacency_changes, no_ospf6_log_adjacency_changes_cmd, "no log-adjacency-changes", NO_STR "Log changes in adjacency state\n") { struct ospf6 *ospf6 = vty->index; UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (no_ospf6_log_adjacency_changes_detail, no_ospf6_log_adjacency_changes_detail_cmd, "no log-adjacency-changes detail", NO_STR "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf6 *ospf6 = vty->index; UNSET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (ospf6_interface_area, ospf6_interface_area_cmd, "interface IFNAME area A.B.C.D", "Enable routing on an IPv6 interface\n" IFNAME_STR "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) { struct ospf6 *o; struct ospf6_area *oa; struct ospf6_interface *oi; struct interface *ifp; u_int32_t area_id; o = (struct ospf6 *) vty->index; /* find/create ospf6 interface */ ifp = if_get_by_name (argv[0]); oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) oi = ospf6_interface_create (ifp); if (oi->area) { vty_out (vty, "%s already attached to Area %s%s", oi->interface->name, oi->area->name, VNL); return CMD_SUCCESS; } /* parse Area-ID */ if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } /* find/create ospf6 area */ oa = ospf6_area_lookup (area_id, o); if (oa == NULL) oa = ospf6_area_create (area_id, o); /* attach interface to area */ listnode_add (oa->if_list, oi); /* sort ?? */ oi->area = oa; SET_FLAG (oa->flag, OSPF6_AREA_ENABLE); /* ospf6 process is currently disabled, not much more to do */ if (CHECK_FLAG (o->flag, OSPF6_DISABLED)) return CMD_SUCCESS; /* start up */ ospf6_interface_enable (oi); /* If the router is ABR, originate summary routes */ if (ospf6_is_router_abr (o)) ospf6_abr_enable_area (oa); return CMD_SUCCESS; } DEFUN (no_ospf6_interface_area, no_ospf6_interface_area_cmd, "no interface IFNAME area A.B.C.D", NO_STR "Disable routing on an IPv6 interface\n" IFNAME_STR "Specify the OSPF6 area ID\n" "OSPF6 area ID in IPv4 address notation\n" ) { struct ospf6_interface *oi; struct ospf6_area *oa; struct interface *ifp; u_int32_t area_id; ifp = if_lookup_by_name (argv[0]); if (ifp == NULL) { vty_out (vty, "No such interface %s%s", argv[0], VNL); return CMD_SUCCESS; } oi = (struct ospf6_interface *) ifp->info; if (oi == NULL) { vty_out (vty, "Interface %s not enabled%s", ifp->name, VNL); return CMD_SUCCESS; } /* parse Area-ID */ if (inet_pton (AF_INET, argv[1], &area_id) != 1) { vty_out (vty, "Invalid Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } /* Verify Area */ if (oi->area == NULL) { vty_out (vty, "No such Area-ID: %s%s", argv[1], VNL); return CMD_SUCCESS; } if (oi->area->area_id != area_id) { vty_out (vty, "Wrong Area-ID: %s is attached to area %s%s", oi->interface->name, oi->area->name, VNL); return CMD_SUCCESS; } thread_execute (master, interface_down, oi, 0); oa = oi->area; listnode_delete (oi->area->if_list, oi); oi->area = (struct ospf6_area *) NULL; /* Withdraw inter-area routes from this area, if necessary */ if (oa->if_list->count == 0) { UNSET_FLAG (oa->flag, OSPF6_AREA_ENABLE); ospf6_abr_disable_area (oa); } return CMD_SUCCESS; } DEFUN (ospf6_stub_router_admin, ospf6_stub_router_admin_cmd, "stub-router administrative", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Administratively applied, for an indefinite period\n") { struct listnode *node; struct ospf6_area *oa; if (!CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_V6); OSPF6_OPT_CLEAR (oa->options, OSPF6_OPT_R); OSPF6_ROUTER_LSA_SCHEDULE (oa); } SET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); } return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_admin, no_ospf6_stub_router_admin_cmd, "no stub-router administrative", NO_STR "Make router a stub router\n" "Advertise ability to be a transit router\n" "Administratively applied, for an indefinite period\n") { struct listnode *node; struct ospf6_area *oa; if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, node, oa)) { OSPF6_OPT_SET (oa->options, OSPF6_OPT_V6); OSPF6_OPT_SET (oa->options, OSPF6_OPT_R); OSPF6_ROUTER_LSA_SCHEDULE (oa); } UNSET_FLAG (ospf6->flag, OSPF6_STUB_ROUTER); } return CMD_SUCCESS; } DEFUN (ospf6_stub_router_startup, ospf6_stub_router_startup_cmd, "stub-router on-startup <5-86400>", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router on startup of OSPF6\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_startup, no_ospf6_stub_router_startup_cmd, "no stub-router on-startup", NO_STR "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router on startup of OSPF6\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (ospf6_stub_router_shutdown, ospf6_stub_router_shutdown_cmd, "stub-router on-shutdown <5-86400>", "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router before shutdown\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } DEFUN (no_ospf6_stub_router_shutdown, no_ospf6_stub_router_shutdown_cmd, "no stub-router on-shutdown", NO_STR "Make router a stub router\n" "Advertise inability to be a transit router\n" "Automatically advertise as stub-router before shutdown\n" "Time (seconds) to advertise self as stub-router\n") { return CMD_SUCCESS; } static void ospf6_show (struct vty *vty, struct ospf6 *o) { struct listnode *n; struct ospf6_area *oa; char router_id[16], duration[32]; struct timeval now, running, result; char buf[32], rbuf[32]; /* process id, router id */ inet_ntop (AF_INET, &o->router_id, router_id, sizeof (router_id)); vty_out (vty, " OSPFv3 Routing Process (0) with Router-ID %s%s", router_id, VNL); /* running time */ quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &o->starttime, &running); timerstring (&running, duration, sizeof (duration)); vty_out (vty, " Running %s%s", duration, VNL); /* Redistribute configuration */ /* XXX */ /* Show SPF parameters */ vty_out(vty, " Initial SPF scheduling delay %d millisec(s)%s" " Minimum hold time between consecutive SPFs %d millsecond(s)%s" " Maximum hold time between consecutive SPFs %d millsecond(s)%s" " Hold time multiplier is currently %d%s", o->spf_delay, VNL, o->spf_holdtime, VNL, o->spf_max_holdtime, VNL, o->spf_hold_multiplier, VNL); vty_out(vty, " SPF algorithm "); if (o->ts_spf.tv_sec || o->ts_spf.tv_usec) { timersub(&now, &o->ts_spf, &result); timerstring(&result, buf, sizeof(buf)); ospf6_spf_reason_string(o->last_spf_reason, rbuf, sizeof(rbuf)); vty_out(vty, "last executed %s ago, reason %s%s", buf, rbuf, VNL); vty_out (vty, " Last SPF duration %ld sec %ld usec%s", o->ts_spf_duration.tv_sec, o->ts_spf_duration.tv_usec, VNL); } else vty_out(vty, "has not been run$%s", VNL); threadtimer_string(now, o->t_spf_calc, buf, sizeof(buf)); vty_out (vty, " SPF timer %s%s%s", (o->t_spf_calc ? "due in " : "is "), buf, VNL); if (CHECK_FLAG (o->flag, OSPF6_STUB_ROUTER)) vty_out (vty, " Router Is Stub Router%s", VNL); /* LSAs */ vty_out (vty, " Number of AS scoped LSAs is %u%s", o->lsdb->count, VNL); /* Areas */ vty_out (vty, " Number of areas in this router is %u%s", listcount (o->area_list), VNL); if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(o->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) vty_out(vty, " All adjacency changes are logged%s",VTY_NEWLINE); else vty_out(vty, " Adjacency changes are logged%s",VTY_NEWLINE); } vty_out (vty, "%s",VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (o->area_list, n, oa)) ospf6_area_show (vty, oa); } /* show top level structures */ DEFUN (show_ipv6_ospf6, show_ipv6_ospf6_cmd, "show ipv6 ospf6", SHOW_STR IP6_STR OSPF6_STR) { OSPF6_CMD_CHECK_RUNNING (); ospf6_show (vty, ospf6); return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_route, show_ipv6_ospf6_route_cmd, "show ipv6 ospf6 route", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR ) { ospf6_route_table_show (vty, argc, argv, ospf6->route_table); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_route, show_ipv6_ospf6_route_detail_cmd, "show ipv6 ospf6 route (X:X::X:X|X:X::X:X/M|detail|summary)", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 address\n" "Specify IPv6 prefix\n" "Detailed information\n" "Summary of route table\n" ) DEFUN (show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_match_cmd, "show ipv6 ospf6 route X:X::X:X/M match", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes which match the specified route\n" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; /* copy argv to sargv and then append "match" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; sargc = argc; sargv[sargc++] = "match"; sargv[sargc] = NULL; ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } DEFUN (show_ipv6_ospf6_route_match_detail, show_ipv6_ospf6_route_match_detail_cmd, "show ipv6 ospf6 route X:X::X:X/M match detail", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes which match the specified route\n" "Detailed information\n" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; /* copy argv to sargv and then append "match" and "detail" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; sargc = argc; sargv[sargc++] = "match"; sargv[sargc++] = "detail"; sargv[sargc] = NULL; ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } ALIAS (show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_longer_cmd, "show ipv6 ospf6 route X:X::X:X/M longer", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" ) DEFUN (show_ipv6_ospf6_route_match_detail, show_ipv6_ospf6_route_longer_detail_cmd, "show ipv6 ospf6 route X:X::X:X/M longer detail", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Specify IPv6 prefix\n" "Display routes longer than the specified route\n" "Detailed information\n" ); ALIAS (show_ipv6_ospf6_route, show_ipv6_ospf6_route_type_cmd, "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2)", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" ) DEFUN (show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd, "show ipv6 ospf6 route (intra-area|inter-area|external-1|external-2) detail", SHOW_STR IP6_STR OSPF6_STR ROUTE_STR "Display Intra-Area routes\n" "Display Inter-Area routes\n" "Display Type-1 External routes\n" "Display Type-2 External routes\n" "Detailed information\n" ) { const char *sargv[CMD_ARGC_MAX]; int i, sargc; /* copy argv to sargv and then append "detail" */ for (i = 0; i < argc; i++) sargv[i] = argv[i]; sargc = argc; sargv[sargc++] = "detail"; sargv[sargc] = NULL; ospf6_route_table_show (vty, sargc, sargv, ospf6->route_table); return CMD_SUCCESS; } static void ospf6_stub_router_config_write (struct vty *vty) { if (CHECK_FLAG (ospf6->flag, OSPF6_STUB_ROUTER)) { vty_out (vty, " stub-router administrative%s", VNL); } return; } /* OSPF configuration write function. */ static int config_write_ospf6 (struct vty *vty) { char router_id[16]; struct listnode *j, *k; struct ospf6_area *oa; struct ospf6_interface *oi; /* OSPFv6 configuration. */ if (ospf6 == NULL) return CMD_SUCCESS; inet_ntop (AF_INET, &ospf6->router_id_static, router_id, sizeof (router_id)); vty_out (vty, "router ospf6%s", VNL); if (ospf6->router_id_static != 0) vty_out (vty, " router-id %s%s", router_id, VNL); /* log-adjacency-changes flag print. */ if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES)) { vty_out(vty, " log-adjacency-changes"); if (CHECK_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_DETAIL)) vty_out(vty, " detail"); vty_out(vty, "%s", VTY_NEWLINE); } if (ospf6->ref_bandwidth != OSPF6_REFERENCE_BANDWIDTH) vty_out (vty, " auto-cost reference-bandwidth %d%s", ospf6->ref_bandwidth / 1000, VNL); ospf6_stub_router_config_write (vty); ospf6_redistribute_config_write (vty); ospf6_area_config_write (vty); ospf6_spf_config_write (vty); for (ALL_LIST_ELEMENTS_RO (ospf6->area_list, j, oa)) { for (ALL_LIST_ELEMENTS_RO (oa->if_list, k, oi)) vty_out (vty, " interface %s area %s%s", oi->interface->name, oa->name, VNL); } vty_out (vty, "!%s", VNL); return 0; } /* OSPF6 node structure. */ static struct cmd_node ospf6_node = { OSPF6_NODE, "%s(config-ospf6)# ", 1 /* VTYSH */ }; /* Install ospf related commands. */ void ospf6_top_init (void) { /* Install ospf6 top node. */ install_node (&ospf6_node, config_write_ospf6); install_element (VIEW_NODE, &show_ipv6_ospf6_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_cmd); install_element (CONFIG_NODE, &router_ospf6_cmd); install_element (CONFIG_NODE, &no_router_ospf6_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_match_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_cmd); install_element (VIEW_NODE, &show_ipv6_ospf6_route_type_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_match_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_longer_detail_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_cmd); install_element (ENABLE_NODE, &show_ipv6_ospf6_route_type_detail_cmd); install_default (OSPF6_NODE); install_element (OSPF6_NODE, &ospf6_router_id_cmd); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_cmd); install_element (OSPF6_NODE, &ospf6_log_adjacency_changes_detail_cmd); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_cmd); install_element (OSPF6_NODE, &no_ospf6_log_adjacency_changes_detail_cmd); install_element (OSPF6_NODE, &ospf6_interface_area_cmd); install_element (OSPF6_NODE, &no_ospf6_interface_area_cmd); install_element (OSPF6_NODE, &ospf6_stub_router_admin_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_admin_cmd); /* For a later time install_element (OSPF6_NODE, &ospf6_stub_router_startup_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_startup_cmd); install_element (OSPF6_NODE, &ospf6_stub_router_shutdown_cmd); install_element (OSPF6_NODE, &no_ospf6_stub_router_shutdown_cmd); */ } quagga-0.99.24.1/ospf6d/ospf6_lsdb.c0000644000175000017500000003362312476520570013651 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "log.h" #include "command.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6d.h" struct ospf6_lsdb * ospf6_lsdb_create (void *data) { struct ospf6_lsdb *lsdb; lsdb = XCALLOC (MTYPE_OSPF6_LSDB, sizeof (struct ospf6_lsdb)); if (lsdb == NULL) { zlog_warn ("Can't malloc lsdb"); return NULL; } memset (lsdb, 0, sizeof (struct ospf6_lsdb)); lsdb->data = data; lsdb->table = route_table_init (); return lsdb; } void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb) { if (lsdb != NULL) { ospf6_lsdb_remove_all (lsdb); route_table_finish (lsdb->table); XFREE (MTYPE_OSPF6_LSDB, lsdb); } } static void ospf6_lsdb_set_key (struct prefix_ipv6 *key, void *value, int len) { assert (key->prefixlen % 8 == 0); memcpy ((caddr_t) &key->prefix + key->prefixlen / 8, (caddr_t) value, len); key->family = AF_INET6; key->prefixlen += len * 8; } #ifdef DEBUG static void _lsdb_count_assert (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *debug; unsigned int num = 0; for (debug = ospf6_lsdb_head (lsdb); debug; debug = ospf6_lsdb_next (debug)) num++; if (num == lsdb->count) return; zlog_debug ("PANIC !! lsdb[%p]->count = %d, real = %d", lsdb, lsdb->count, num); for (debug = ospf6_lsdb_head (lsdb); debug; debug = ospf6_lsdb_next (debug)) zlog_debug ("%p %p %s lsdb[%p]", debug->prev, debug->next, debug->name, debug->lsdb); zlog_debug ("DUMP END"); assert (num == lsdb->count); } #define ospf6_lsdb_count_assert(t) (_lsdb_count_assert (t)) #else /*DEBUG*/ #define ospf6_lsdb_count_assert(t) ((void) 0) #endif /*DEBUG*/ void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct prefix_ipv6 key; struct route_node *current; struct ospf6_lsa *old = NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); ospf6_lsdb_set_key (&key, &lsa->header->adv_router, sizeof (lsa->header->adv_router)); ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id)); current = route_node_get (lsdb->table, (struct prefix *) &key); old = current->info; current->info = lsa; lsa->rn = current; ospf6_lsa_lock (lsa); if (!old) { lsdb->count++; if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); } else { if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } } else { if (OSPF6_LSA_IS_CHANGED (old, lsa)) { if (OSPF6_LSA_IS_MAXAGE (lsa)) { if (lsdb->hook_remove) { (*lsdb->hook_remove) (old); (*lsdb->hook_remove) (lsa); } } else if (OSPF6_LSA_IS_MAXAGE (old)) { if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } else { if (lsdb->hook_remove) (*lsdb->hook_remove) (old); if (lsdb->hook_add) (*lsdb->hook_add) (lsa); } } ospf6_lsa_unlock (old); } ospf6_lsdb_count_assert (lsdb); } void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &lsa->header->type, sizeof (lsa->header->type)); ospf6_lsdb_set_key (&key, &lsa->header->adv_router, sizeof (lsa->header->adv_router)); ospf6_lsdb_set_key (&key, &lsa->header->id, sizeof (lsa->header->id)); node = route_node_lookup (lsdb->table, (struct prefix *) &key); assert (node && node->info == lsa); node->info = NULL; lsdb->count--; if (lsdb->hook_remove) (*lsdb->hook_remove) (lsa); route_unlock_node (node); /* to free the lookup lock */ route_unlock_node (node); /* to free the original lock */ ospf6_lsa_unlock (lsa); ospf6_lsdb_count_assert (lsdb); } struct ospf6_lsa * ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; if (lsdb == NULL) return NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); ospf6_lsdb_set_key (&key, &id, sizeof (id)); node = route_node_lookup (lsdb->table, (struct prefix *) &key); if (node == NULL || node->info == NULL) return NULL; route_unlock_node (node); return (struct ospf6_lsa *) node->info; } struct ospf6_lsa * ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct route_node *node; struct route_node *matched = NULL; struct prefix_ipv6 key; struct prefix *p; if (lsdb == NULL) return NULL; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); ospf6_lsdb_set_key (&key, &id, sizeof (id)); p = (struct prefix *) &key; { char buf[64]; prefix2str (p, buf, sizeof (buf)); zlog_debug ("lsdb_lookup_next: key: %s", buf); } node = lsdb->table->top; /* walk down tree. */ while (node && node->p.prefixlen <= p->prefixlen && prefix_match (&node->p, p)) { matched = node; node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)]; } if (matched) node = matched; else node = lsdb->table->top; route_lock_node (node); /* skip to real existing entry */ while (node && node->info == NULL) node = route_next (node); if (! node) return NULL; if (prefix_same (&node->p, p)) { node = route_next (node); while (node && node->info == NULL) node = route_next (node); } if (! node) return NULL; route_unlock_node (node); return (struct ospf6_lsa *) node->info; } /* Iteration function */ struct ospf6_lsa * ospf6_lsdb_head (struct ospf6_lsdb *lsdb) { struct route_node *node; node = route_top (lsdb->table); if (node == NULL) return NULL; /* skip to the existing lsdb entry */ while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; if (node->info) ospf6_lsa_lock ((struct ospf6_lsa *) node->info); return (struct ospf6_lsa *) node->info; } struct ospf6_lsa * ospf6_lsdb_next (struct ospf6_lsa *lsa) { struct route_node *node = lsa->rn; struct ospf6_lsa *next = NULL; do { node = route_next (node); } while (node && node->info == NULL); if ((node != NULL) && (node->info != NULL)) { next = node->info; ospf6_lsa_lock (next); } ospf6_lsa_unlock (lsa); return next; } struct ospf6_lsa * ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; struct ospf6_lsa *lsa; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); ospf6_lsdb_set_key (&key, &adv_router, sizeof (adv_router)); node = lsdb->table->top; /* Walk down tree. */ while (node && node->p.prefixlen <= key.prefixlen && prefix_match (&node->p, (struct prefix *) &key)) node = node->link[prefix6_bit(&key.prefix, node->p.prefixlen)]; if (node) route_lock_node (node); while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; lsa = node->info; ospf6_lsa_lock (lsa); return lsa; } struct ospf6_lsa * ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, struct ospf6_lsa *lsa) { struct ospf6_lsa *next = ospf6_lsdb_next(lsa); if (next) { if (next->header->type != type || next->header->adv_router != adv_router) { route_unlock_node (next->rn); ospf6_lsa_unlock (next); next = NULL; } } return next; } struct ospf6_lsa * ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb) { struct route_node *node; struct prefix_ipv6 key; struct ospf6_lsa *lsa; memset (&key, 0, sizeof (key)); ospf6_lsdb_set_key (&key, &type, sizeof (type)); /* Walk down tree. */ node = lsdb->table->top; while (node && node->p.prefixlen <= key.prefixlen && prefix_match (&node->p, (struct prefix *) &key)) node = node->link[prefix6_bit(&key.prefix, node->p.prefixlen)]; if (node) route_lock_node (node); while (node && node->info == NULL) node = route_next (node); if (node == NULL) return NULL; if (! prefix_match ((struct prefix *) &key, &node->p)) return NULL; lsa = node->info; ospf6_lsa_lock (lsa); return lsa; } struct ospf6_lsa * ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa) { struct ospf6_lsa *next = ospf6_lsdb_next (lsa); if (next) { if (next->header->type != type) { route_unlock_node (next->rn); ospf6_lsa_unlock (next); next = NULL; } } return next; } void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; if (lsdb == NULL) return; for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) ospf6_lsdb_remove (lsa, lsdb); } void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa) { if (lsa != NULL) { if (lsa->rn != NULL) route_unlock_node (lsa->rn); ospf6_lsa_unlock (lsa); } } int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb) { int reschedule = 0; struct ospf6_lsa *lsa; for (lsa = ospf6_lsdb_head (lsdb); lsa; lsa = ospf6_lsdb_next (lsa)) { if (! OSPF6_LSA_IS_MAXAGE (lsa)) continue; if (lsa->retrans_count != 0) { reschedule = 1; continue; } if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) zlog_debug ("Remove MaxAge %s", lsa->name); if (CHECK_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED)) { UNSET_FLAG(lsa->flag, OSPF6_LSA_SEQWRAPPED); /* * lsa->header->age = 0; */ lsa->header->seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER + 1); ospf6_lsa_checksum (lsa->header); THREAD_OFF(lsa->refresh); thread_execute (master, ospf6_lsa_refresh, lsa, 0); } else { ospf6_lsdb_remove (lsa, lsdb); } } return (reschedule); } void ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; void (*showfunc) (struct vty *, struct ospf6_lsa *) = NULL; switch (level) { case OSPF6_LSDB_SHOW_LEVEL_DETAIL: showfunc = ospf6_lsa_show; break; case OSPF6_LSDB_SHOW_LEVEL_INTERNAL: showfunc = ospf6_lsa_show_internal; break; case OSPF6_LSDB_SHOW_LEVEL_DUMP: showfunc = ospf6_lsa_show_dump; break; case OSPF6_LSDB_SHOW_LEVEL_NORMAL: default: showfunc = ospf6_lsa_show_summary; } if (type && id && adv_router) { lsa = ospf6_lsdb_lookup (*type, *id, *adv_router, lsdb); if (lsa) { if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show (vty, lsa); else (*showfunc) (vty, lsa); } return; } if (level == OSPF6_LSDB_SHOW_LEVEL_NORMAL) ospf6_lsa_show_summary_header (vty); if (type && adv_router) lsa = ospf6_lsdb_type_router_head (*type, *adv_router, lsdb); else if (type) lsa = ospf6_lsdb_type_head (*type, lsdb); else lsa = ospf6_lsdb_head (lsdb); while (lsa) { if ((! adv_router || lsa->header->adv_router == *adv_router) && (! id || lsa->header->id == *id)) (*showfunc) (vty, lsa); if (type && adv_router) lsa = ospf6_lsdb_type_router_next (*type, *adv_router, lsa); else if (type) lsa = ospf6_lsdb_type_next (*type, lsa); else lsa = ospf6_lsdb_next (lsa); } } /* Decide new Link State ID to originate. note return value is network byte order */ u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; u_int32_t id = 1; for (lsa = ospf6_lsdb_type_router_head (type, adv_router, lsdb); lsa; lsa = ospf6_lsdb_type_router_next (type, adv_router, lsa)) { if (ntohl (lsa->header->id) < id) continue; if (ntohl (lsa->header->id) > id) { ospf6_lsdb_lsa_unlock (lsa); break; } id++; } return ((u_int32_t) htonl (id)); } /* Decide new LS sequence number to originate. note return value is network byte order */ u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb) { struct ospf6_lsa *lsa; signed long seqnum = 0; /* if current database copy not found, return InitialSequenceNumber */ lsa = ospf6_lsdb_lookup (type, id, adv_router, lsdb); if (lsa == NULL) seqnum = OSPF_INITIAL_SEQUENCE_NUMBER; else seqnum = (signed long) ntohl (lsa->header->seqnum) + 1; return ((u_int32_t) htonl (seqnum)); } quagga-0.99.24.1/ospf6d/ospf6_lsa.c0000644000175000017500000006457512476520570013516 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include /* Include other stuffs */ #include "log.h" #include "linklist.h" #include "vector.h" #include "vty.h" #include "command.h" #include "memory.h" #include "thread.h" #include "checksum.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_interface.h" #include "ospf6_neighbor.h" #include "ospf6_flood.h" #include "ospf6d.h" vector ospf6_lsa_handler_vector; static int ospf6_unknown_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { u_char *start, *end, *current; char byte[4]; start = (u_char *) lsa->header + sizeof (struct ospf6_lsa_header); end = (u_char *) lsa->header + ntohs (lsa->header->length); vty_out (vty, " Unknown contents:%s", VNL); for (current = start; current < end; current ++) { if ((current - start) % 16 == 0) vty_out (vty, "%s ", VNL); else if ((current - start) % 4 == 0) vty_out (vty, " "); snprintf (byte, sizeof (byte), "%02x", *current); vty_out (vty, "%s", byte); } vty_out (vty, "%s%s", VNL, VNL); return 0; } struct ospf6_lsa_handler unknown_handler = { OSPF6_LSTYPE_UNKNOWN, "Unknown", "Unk", ospf6_unknown_lsa_show, NULL, OSPF6_LSA_DEBUG, }; void ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler) { /* type in handler is host byte order */ int index = handler->type & OSPF6_LSTYPE_FCODE_MASK; vector_set_index (ospf6_lsa_handler_vector, index, handler); } struct ospf6_lsa_handler * ospf6_get_lsa_handler (u_int16_t type) { struct ospf6_lsa_handler *handler = NULL; unsigned int index = ntohs (type) & OSPF6_LSTYPE_FCODE_MASK; if (index >= vector_active (ospf6_lsa_handler_vector)) handler = &unknown_handler; else handler = vector_slot (ospf6_lsa_handler_vector, index); if (handler == NULL) handler = &unknown_handler; return handler; } const char * ospf6_lstype_name (u_int16_t type) { static char buf[8]; struct ospf6_lsa_handler *handler; handler = ospf6_get_lsa_handler (type); if (handler && handler != &unknown_handler) return handler->name; snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); return buf; } const char * ospf6_lstype_short_name (u_int16_t type) { static char buf[8]; struct ospf6_lsa_handler *handler; handler = ospf6_get_lsa_handler (type); if (handler && handler != &unknown_handler) return handler->short_name; snprintf (buf, sizeof (buf), "0x%04hx", ntohs (type)); return buf; } u_char ospf6_lstype_debug (u_int16_t type) { struct ospf6_lsa_handler *handler; handler = ospf6_get_lsa_handler (type); return handler->debug; } /* RFC2328: Section 13.2 */ int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) { int len; assert (OSPF6_LSA_IS_SAME (lsa1, lsa2)); /* XXX, Options ??? */ ospf6_lsa_age_current (lsa1); ospf6_lsa_age_current (lsa2); if (ntohs (lsa1->header->age) == OSPF_LSA_MAXAGE && ntohs (lsa2->header->age) != OSPF_LSA_MAXAGE) return 1; if (ntohs (lsa1->header->age) != OSPF_LSA_MAXAGE && ntohs (lsa2->header->age) == OSPF_LSA_MAXAGE) return 1; /* compare body */ if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) return 1; len = ntohs (lsa1->header->length) - sizeof (struct ospf6_lsa_header); return memcmp (lsa1->header + 1, lsa2->header + 1, len); } int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2) { int length; if (OSPF6_LSA_IS_MAXAGE (lsa1) ^ OSPF6_LSA_IS_MAXAGE (lsa2)) return 1; if (ntohs (lsa1->header->length) != ntohs (lsa2->header->length)) return 1; /* Going beyond LSA headers to compare the payload only makes sense, when both LSAs aren't header-only. */ if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY) != CHECK_FLAG (lsa2->flag, OSPF6_LSA_HEADERONLY)) { zlog_warn ("%s: only one of two (%s, %s) LSAs compared is header-only", __func__, lsa1->name, lsa2->name); return 1; } if (CHECK_FLAG (lsa1->flag, OSPF6_LSA_HEADERONLY)) return 0; length = OSPF6_LSA_SIZE (lsa1->header) - sizeof (struct ospf6_lsa_header); /* Once upper layer verifies LSAs received, length underrun should become a warning. */ if (length <= 0) return 0; return memcmp (OSPF6_LSA_HEADER_END (lsa1->header), OSPF6_LSA_HEADER_END (lsa2->header), length); } /* ospf6 age functions */ /* calculate birth */ static void ospf6_lsa_age_set (struct ospf6_lsa *lsa) { struct timeval now; assert (lsa && lsa->header); if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", safe_strerror (errno)); lsa->birth.tv_sec = now.tv_sec - ntohs (lsa->header->age); lsa->birth.tv_usec = now.tv_usec; return; } /* this function calculates current age from its birth, then update age field of LSA header. return value is current age */ u_int16_t ospf6_lsa_age_current (struct ospf6_lsa *lsa) { struct timeval now; u_int32_t ulage; u_int16_t age; assert (lsa); assert (lsa->header); /* current time */ if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &now) < 0) zlog_warn ("LSA: quagga_gettime failed, may fail LSA AGEs: %s", safe_strerror (errno)); if (ntohs (lsa->header->age) >= OSPF_LSA_MAXAGE) { /* ospf6_lsa_premature_aging () sets age to MAXAGE; when using relative time, we cannot compare against lsa birth time, so we catch this special case here. */ lsa->header->age = htons (OSPF_LSA_MAXAGE); return OSPF_LSA_MAXAGE; } /* calculate age */ ulage = now.tv_sec - lsa->birth.tv_sec; /* if over MAXAGE, set to it */ age = (ulage > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : ulage); lsa->header->age = htons (age); return age; } /* update age field of LSA header with adding InfTransDelay */ void ospf6_lsa_age_update_to_send (struct ospf6_lsa *lsa, u_int32_t transdelay) { unsigned short age; age = ospf6_lsa_age_current (lsa) + transdelay; if (age > OSPF_LSA_MAXAGE) age = OSPF_LSA_MAXAGE; lsa->header->age = htons (age); } void ospf6_lsa_premature_aging (struct ospf6_lsa *lsa) { /* log */ if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) zlog_debug ("LSA: Premature aging: %s", lsa->name); THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); /* * We clear the LSA from the neighbor retx lists now because it * will not get deleted later. Essentially, changing the age to * MaxAge will prevent this LSA from being matched with its * existing entries in the retx list thereby causing those entries * to be silently replaced with its MaxAged version, but with ever * increasing retx count causing this LSA to remain forever and * for the MaxAge remover thread to be called forever too. * * The reason the previous entry silently disappears is that when * entry is added to a neighbor's retx list, it replaces the existing * entry. But since the ospf6_lsdb_add() routine is generic and not aware * of the special semantics of retx count, the retx count is not * decremented when its replaced. Attempting to add the incr and decr * retx count routines as the hook_add and hook_remove for the retx lists * have a problem because the hook_remove routine is called for MaxAge * entries (as will be the case in a traditional LSDB, unlike in this case * where an LSDB is used as an efficient tree structure to store all kinds * of data) that are added instead of calling the hook_add routine. */ ospf6_flood_clear (lsa); lsa->header->age = htons (OSPF_LSA_MAXAGE); thread_execute (master, ospf6_lsa_expire, lsa, 0); } /* check which is more recent. if a is more recent, return -1; if the same, return 0; otherwise(b is more recent), return 1 */ int ospf6_lsa_compare (struct ospf6_lsa *a, struct ospf6_lsa *b) { int32_t seqnuma, seqnumb; u_int16_t cksuma, cksumb; u_int16_t agea, ageb; assert (a && a->header); assert (b && b->header); assert (OSPF6_LSA_IS_SAME (a, b)); seqnuma = (int32_t) ntohl (a->header->seqnum); seqnumb = (int32_t) ntohl (b->header->seqnum); /* compare by sequence number */ if (seqnuma > seqnumb) return -1; if (seqnuma < seqnumb) return 1; /* Checksum */ cksuma = ntohs (a->header->checksum); cksumb = ntohs (b->header->checksum); if (cksuma > cksumb) return -1; if (cksuma < cksumb) return 0; /* Update Age */ agea = ospf6_lsa_age_current (a); ageb = ospf6_lsa_age_current (b); /* MaxAge check */ if (agea == OSPF_LSA_MAXAGE && ageb != OSPF_LSA_MAXAGE) return -1; else if (agea != OSPF_LSA_MAXAGE && ageb == OSPF_LSA_MAXAGE) return 1; /* Age check */ if (agea > ageb && agea - ageb >= OSPF_LSA_MAXAGE_DIFF) return 1; else if (agea < ageb && ageb - agea >= OSPF_LSA_MAXAGE_DIFF) return -1; /* neither recent */ return 0; } char * ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size) { char id[16], adv_router[16]; inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); snprintf (buf, size, "[%s Id:%s Adv:%s]", ospf6_lstype_name (lsa->header->type), id, adv_router); return buf; } void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header) { char id[16], adv_router[16]; inet_ntop (AF_INET, &header->id, id, sizeof (id)); inet_ntop (AF_INET, &header->adv_router, adv_router, sizeof (adv_router)); zlog_debug (" [%s Id:%s Adv:%s]", ospf6_lstype_name (header->type), id, adv_router); zlog_debug (" Age: %4hu SeqNum: %#08lx Cksum: %04hx Len: %d", ntohs (header->age), (u_long) ntohl (header->seqnum), ntohs (header->checksum), ntohs (header->length)); } void ospf6_lsa_header_print (struct ospf6_lsa *lsa) { ospf6_lsa_age_current (lsa); ospf6_lsa_header_print_raw (lsa->header); } void ospf6_lsa_show_summary_header (struct vty *vty) { vty_out (vty, "%-4s %-15s%-15s%4s %8s %30s%s", "Type", "LSId", "AdvRouter", "Age", "SeqNum", "Payload", VNL); } void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[16], id[16]; int type; struct ospf6_lsa_handler *handler; char buf[64], tmpbuf[80]; int cnt = 0; assert (lsa); assert (lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); type = ntohs(lsa->header->type); handler = ospf6_get_lsa_handler (lsa->header->type); if ((type == OSPF6_LSTYPE_INTER_PREFIX) || (type == OSPF6_LSTYPE_INTER_ROUTER) || (type == OSPF6_LSTYPE_AS_EXTERNAL)) { vty_out (vty, "%-4s %-15s%-15s%4hu %8lx %30s%s", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum), handler->get_prefix_str(lsa, buf, sizeof(buf), 0), VNL); } else if (type != OSPF6_LSTYPE_UNKNOWN) { sprintf (tmpbuf, "%-4s %-15s%-15s%4hu %8lx", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum)); while (handler->get_prefix_str(lsa, buf, sizeof(buf), cnt) != NULL) { vty_out (vty, "%s %30s%s", tmpbuf, buf, VNL); cnt++; } } else { vty_out (vty, "%-4s %-15s%-15s%4hu %8lx%s", ospf6_lstype_short_name (lsa->header->type), id, adv_router, ospf6_lsa_age_current (lsa), (u_long) ntohl (lsa->header->seqnum), VNL); } } void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa) { u_char *start, *end, *current; char byte[4]; start = (u_char *) lsa->header; end = (u_char *) lsa->header + ntohs (lsa->header->length); vty_out (vty, "%s", VNL); vty_out (vty, "%s:%s", lsa->name, VNL); for (current = start; current < end; current ++) { if ((current - start) % 16 == 0) vty_out (vty, "%s ", VNL); else if ((current - start) % 4 == 0) vty_out (vty, " "); snprintf (byte, sizeof (byte), "%02x", *current); vty_out (vty, "%s", byte); } vty_out (vty, "%s%s", VNL, VNL); return; } void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[64], id[64]; assert (lsa && lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); vty_out (vty, "%s", VNL); vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), ospf6_lstype_name (lsa->header->type), VNL); vty_out (vty, "Link State ID: %s%s", id, VNL); vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); vty_out (vty, "LS Sequence Number: %#010lx%s", (u_long) ntohl (lsa->header->seqnum), VNL); vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); vty_out (vty, "Flag: %x %s", lsa->flag, VNL); vty_out (vty, "Lock: %d %s", lsa->lock, VNL); vty_out (vty, "ReTx Count: %d%s", lsa->retrans_count, VNL); vty_out (vty, "Threads: Expire: 0x%p, Refresh: 0x%p %s", lsa->expire, lsa->refresh, VNL); vty_out (vty, "%s", VNL); return; } void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa) { char adv_router[64], id[64]; struct ospf6_lsa_handler *handler; struct timeval now, res; char duration[16]; assert (lsa && lsa->header); inet_ntop (AF_INET, &lsa->header->id, id, sizeof (id)); inet_ntop (AF_INET, &lsa->header->adv_router, adv_router, sizeof (adv_router)); quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); timersub (&now, &lsa->installed, &res); timerstring (&res, duration, sizeof (duration)); vty_out (vty, "Age: %4hu Type: %s%s", ospf6_lsa_age_current (lsa), ospf6_lstype_name (lsa->header->type), VNL); vty_out (vty, "Link State ID: %s%s", id, VNL); vty_out (vty, "Advertising Router: %s%s", adv_router, VNL); vty_out (vty, "LS Sequence Number: %#010lx%s", (u_long) ntohl (lsa->header->seqnum), VNL); vty_out (vty, "CheckSum: %#06hx Length: %hu%s", ntohs (lsa->header->checksum), ntohs (lsa->header->length), VNL); vty_out (vty, "Duration: %s%s", duration, VNL); handler = ospf6_get_lsa_handler (lsa->header->type); if (handler->show == NULL) handler = &unknown_handler; (*handler->show) (vty, lsa); vty_out (vty, "%s", VNL); } /* OSPFv3 LSA creation/deletion function */ struct ospf6_lsa * ospf6_lsa_create (struct ospf6_lsa_header *header) { struct ospf6_lsa *lsa = NULL; struct ospf6_lsa_header *new_header = NULL; u_int16_t lsa_size = 0; /* size of the entire LSA */ lsa_size = ntohs (header->length); /* XXX vulnerable */ /* allocate memory for this LSA */ new_header = (struct ospf6_lsa_header *) XMALLOC (MTYPE_OSPF6_LSA, lsa_size); /* copy LSA from original header */ memcpy (new_header, header, lsa_size); /* LSA information structure */ /* allocate memory */ lsa = (struct ospf6_lsa *) XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); lsa->header = (struct ospf6_lsa_header *) new_header; /* dump string */ ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); /* calculate birth of this lsa */ ospf6_lsa_age_set (lsa); return lsa; } struct ospf6_lsa * ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header) { struct ospf6_lsa *lsa = NULL; struct ospf6_lsa_header *new_header = NULL; /* allocate memory for this LSA */ new_header = (struct ospf6_lsa_header *) XMALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa_header)); /* copy LSA from original header */ memcpy (new_header, header, sizeof (struct ospf6_lsa_header)); /* LSA information structure */ /* allocate memory */ lsa = (struct ospf6_lsa *) XCALLOC (MTYPE_OSPF6_LSA, sizeof (struct ospf6_lsa)); lsa->header = (struct ospf6_lsa_header *) new_header; SET_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY); /* dump string */ ospf6_lsa_printbuf (lsa, lsa->name, sizeof (lsa->name)); /* calculate birth of this lsa */ ospf6_lsa_age_set (lsa); return lsa; } void ospf6_lsa_delete (struct ospf6_lsa *lsa) { assert (lsa->lock == 0); /* cancel threads */ THREAD_OFF (lsa->expire); THREAD_OFF (lsa->refresh); /* do free */ XFREE (MTYPE_OSPF6_LSA, lsa->header); XFREE (MTYPE_OSPF6_LSA, lsa); } struct ospf6_lsa * ospf6_lsa_copy (struct ospf6_lsa *lsa) { struct ospf6_lsa *copy = NULL; ospf6_lsa_age_current (lsa); if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) copy = ospf6_lsa_create_headeronly (lsa->header); else copy = ospf6_lsa_create (lsa->header); assert (copy->lock == 0); copy->birth = lsa->birth; copy->originated = lsa->originated; copy->received = lsa->received; copy->installed = lsa->installed; copy->lsdb = lsa->lsdb; copy->rn = NULL; return copy; } /* increment reference counter of struct ospf6_lsa */ void ospf6_lsa_lock (struct ospf6_lsa *lsa) { lsa->lock++; return; } /* decrement reference counter of struct ospf6_lsa */ void ospf6_lsa_unlock (struct ospf6_lsa *lsa) { /* decrement reference counter */ assert (lsa->lock > 0); lsa->lock--; if (lsa->lock != 0) return; ospf6_lsa_delete (lsa); } /* ospf6 lsa expiry */ int ospf6_lsa_expire (struct thread *thread) { struct ospf6_lsa *lsa; lsa = (struct ospf6_lsa *) THREAD_ARG (thread); assert (lsa && lsa->header); assert (OSPF6_LSA_IS_MAXAGE (lsa)); assert (! lsa->refresh); lsa->expire = (struct thread *) NULL; if (IS_OSPF6_DEBUG_LSA_TYPE (lsa->header->type)) { zlog_debug ("LSA Expire:"); ospf6_lsa_header_print (lsa); } if (CHECK_FLAG (lsa->flag, OSPF6_LSA_HEADERONLY)) return 0; /* dbexchange will do something ... */ /* reinstall lsa */ ospf6_install_lsa (lsa); /* reflood lsa */ ospf6_flood (NULL, lsa); /* schedule maxage remover */ ospf6_maxage_remove (ospf6); return 0; } int ospf6_lsa_refresh (struct thread *thread) { struct ospf6_lsa *old, *self, *new; struct ospf6_lsdb *lsdb_self; assert (thread); old = (struct ospf6_lsa *) THREAD_ARG (thread); assert (old && old->header); old->refresh = (struct thread *) NULL; lsdb_self = ospf6_get_scoped_lsdb_self (old); self = ospf6_lsdb_lookup (old->header->type, old->header->id, old->header->adv_router, lsdb_self); if (self == NULL) { if (IS_OSPF6_DEBUG_LSA_TYPE (old->header->type)) zlog_debug ("Refresh: could not find self LSA, flush %s", old->name); ospf6_lsa_premature_aging (old); return 0; } /* Reset age, increment LS sequence number. */ self->header->age = htons (0); self->header->seqnum = ospf6_new_ls_seqnum (self->header->type, self->header->id, self->header->adv_router, old->lsdb); ospf6_lsa_checksum (self->header); new = ospf6_lsa_create (self->header); new->lsdb = old->lsdb; new->refresh = thread_add_timer (master, ospf6_lsa_refresh, new, OSPF_LS_REFRESH_TIME); /* store it in the LSDB for self-originated LSAs */ ospf6_lsdb_add (ospf6_lsa_copy (new), lsdb_self); if (IS_OSPF6_DEBUG_LSA_TYPE (new->header->type)) { zlog_debug ("LSA Refresh:"); ospf6_lsa_header_print (new); } ospf6_install_lsa (new); ospf6_flood (NULL, new); return 0; } /* Fletcher Checksum -- Refer to RFC1008. */ /* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */ unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *lsa_header) { u_char *buffer = (u_char *) &lsa_header->type; int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa_header->length) - type_offset; /* Checksum offset starts from "type" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ int checksum_offset = (u_char *) &lsa_header->checksum - buffer; return (unsigned short)fletcher_checksum(buffer, len, checksum_offset); } int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *lsa_header) { u_char *buffer = (u_char *) &lsa_header->type; int type_offset = buffer - (u_char *) &lsa_header->age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa_header->length) - type_offset; return (fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } void ospf6_lsa_init (void) { ospf6_lsa_handler_vector = vector_init (0); ospf6_install_lsa_handler (&unknown_handler); } void ospf6_lsa_terminate (void) { vector_free (ospf6_lsa_handler_vector); } static char * ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) { static char buf[64]; unsigned int i; unsigned int size = strlen (h->name); if (!strcmp(h->name, "unknown") && h->type != OSPF6_LSTYPE_UNKNOWN) { snprintf (buf, sizeof (buf), "%#04hx", h->type); return buf; } for (i = 0; i < MIN (size, sizeof (buf)); i++) { if (! islower (h->name[i])) buf[i] = tolower (h->name[i]); else buf[i] = h->name[i]; } buf[size] = '\0'; return buf; } DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { unsigned int i; struct ospf6_lsa_handler *handler = NULL; assert (argc); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) break; if (! strcasecmp (argv[0], handler->name)) break; handler = NULL; } if (handler == NULL) handler = &unknown_handler; if (argc >= 2) { if (! strcmp (argv[1], "originate")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); if (! strcmp (argv[1], "examine")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) SET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); } else SET_FLAG (handler->debug, OSPF6_LSA_DEBUG); return CMD_SUCCESS; } ALIAS (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_detail_cmd, "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", NO_STR DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) { u_int i; struct ospf6_lsa_handler *handler = NULL; assert (argc); for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (strncmp (argv[0], ospf6_lsa_handler_name(handler), strlen(argv[0])) == 0) break; if (! strcasecmp (argv[0], handler->name)) break; } if (handler == NULL) return CMD_SUCCESS; if (argc >= 2) { if (! strcmp (argv[1], "originate")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE); if (! strcmp (argv[1], "examine")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN); if (! strcmp (argv[1], "flooding")) UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD); } else UNSET_FLAG (handler->debug, OSPF6_LSA_DEBUG); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_detail_cmd, "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", NO_STR DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" "Specify LS type as Hexadecimal\n" ) void install_element_ospf6_debug_lsa (void) { install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &debug_ospf6_lsa_hex_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_lsa_hex_detail_cmd); } int config_write_ospf6_debug_lsa (struct vty *vty) { u_int i; struct ospf6_lsa_handler *handler; for (i = 0; i < vector_active (ospf6_lsa_handler_vector); i++) { handler = vector_slot (ospf6_lsa_handler_vector, i); if (handler == NULL) continue; if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG)) vty_out (vty, "debug ospf6 lsa %s%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_ORIGINATE)) vty_out (vty, "debug ospf6 lsa %s originate%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_EXAMIN)) vty_out (vty, "debug ospf6 lsa %s examine%s", ospf6_lsa_handler_name (handler), VNL); if (CHECK_FLAG (handler->debug, OSPF6_LSA_DEBUG_FLOOD)) vty_out (vty, "debug ospf6 lsa %s flooding%s", ospf6_lsa_handler_name (handler), VNL); } return 0; } quagga-0.99.24.1/ospf6d/ospf6_message.c0000644000175000017500000023272412476520570014354 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "memory.h" #include "log.h" #include "vty.h" #include "command.h" #include "thread.h" #include "linklist.h" #include "ospf6_proto.h" #include "ospf6_lsa.h" #include "ospf6_lsdb.h" #include "ospf6_network.h" #include "ospf6_message.h" #include "ospf6_top.h" #include "ospf6_area.h" #include "ospf6_neighbor.h" #include "ospf6_interface.h" /* for structures and macros ospf6_lsa_examin() needs */ #include "ospf6_abr.h" #include "ospf6_asbr.h" #include "ospf6_intra.h" #include "ospf6_flood.h" #include "ospf6d.h" #include unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0}; static const struct message ospf6_message_type_str [] = { { OSPF6_MESSAGE_TYPE_HELLO, "Hello" }, { OSPF6_MESSAGE_TYPE_DBDESC, "DbDesc" }, { OSPF6_MESSAGE_TYPE_LSREQ, "LSReq" }, { OSPF6_MESSAGE_TYPE_LSUPDATE, "LSUpdate" }, { OSPF6_MESSAGE_TYPE_LSACK, "LSAck" }, }; static const size_t ospf6_message_type_str_max = array_size(ospf6_message_type_str); /* Minimum (besides the standard OSPF packet header) lengths for OSPF packets of particular types, offset is the "type" field. */ const u_int16_t ospf6_packet_minlen[OSPF6_MESSAGE_TYPE_ALL] = { 0, OSPF6_HELLO_MIN_SIZE, OSPF6_DB_DESC_MIN_SIZE, OSPF6_LS_REQ_MIN_SIZE, OSPF6_LS_UPD_MIN_SIZE, OSPF6_LS_ACK_MIN_SIZE }; /* Minimum (besides the standard LSA header) lengths for LSAs of particular types, offset is the "LSA function code" portion of "LSA type" field. */ const u_int16_t ospf6_lsa_minlen[OSPF6_LSTYPE_SIZE] = { 0, /* 0x2001 */ OSPF6_ROUTER_LSA_MIN_SIZE, /* 0x2002 */ OSPF6_NETWORK_LSA_MIN_SIZE, /* 0x2003 */ OSPF6_INTER_PREFIX_LSA_MIN_SIZE, /* 0x2004 */ OSPF6_INTER_ROUTER_LSA_FIX_SIZE, /* 0x4005 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, /* 0x2006 */ 0, /* 0x2007 */ OSPF6_AS_EXTERNAL_LSA_MIN_SIZE, /* 0x0008 */ OSPF6_LINK_LSA_MIN_SIZE, /* 0x2009 */ OSPF6_INTRA_PREFIX_LSA_MIN_SIZE }; /* print functions */ static void ospf6_header_print (struct ospf6_header *oh) { char router_id[16], area_id[16]; inet_ntop (AF_INET, &oh->router_id, router_id, sizeof (router_id)); inet_ntop (AF_INET, &oh->area_id, area_id, sizeof (area_id)); zlog_debug (" OSPFv%d Type:%d Len:%hu Router-ID:%s", oh->version, oh->type, ntohs (oh->length), router_id); zlog_debug (" Area-ID:%s Cksum:%hx Instance-ID:%d", area_id, ntohs (oh->checksum), oh->instance_id); } void ospf6_hello_print (struct ospf6_header *oh) { struct ospf6_hello *hello; char options[16]; char drouter[16], bdrouter[16], neighbor[16]; char *p; ospf6_header_print (oh); assert (oh->type == OSPF6_MESSAGE_TYPE_HELLO); hello = (struct ospf6_hello *) ((caddr_t) oh + sizeof (struct ospf6_header)); inet_ntop (AF_INET, &hello->drouter, drouter, sizeof (drouter)); inet_ntop (AF_INET, &hello->bdrouter, bdrouter, sizeof (bdrouter)); ospf6_options_printbuf (hello->options, options, sizeof (options)); zlog_debug (" I/F-Id:%ld Priority:%d Option:%s", (u_long) ntohl (hello->interface_id), hello->priority, options); zlog_debug (" HelloInterval:%hu DeadInterval:%hu", ntohs (hello->hello_interval), ntohs (hello->dead_interval)); zlog_debug (" DR:%s BDR:%s", drouter, bdrouter); for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); p += sizeof (u_int32_t)) { inet_ntop (AF_INET, (void *) p, neighbor, sizeof (neighbor)); zlog_debug (" Neighbor: %s", neighbor); } assert (p == OSPF6_MESSAGE_END (oh)); } void ospf6_dbdesc_print (struct ospf6_header *oh) { struct ospf6_dbdesc *dbdesc; char options[16]; char *p; ospf6_header_print (oh); assert (oh->type == OSPF6_MESSAGE_TYPE_DBDESC); dbdesc = (struct ospf6_dbdesc *) ((caddr_t) oh + sizeof (struct ospf6_header)); ospf6_options_printbuf (dbdesc->options, options, sizeof (options)); zlog_debug (" MBZ: %#x Option: %s IfMTU: %hu", dbdesc->reserved1, options, ntohs (dbdesc->ifmtu)); zlog_debug (" MBZ: %#x Bits: %s%s%s SeqNum: %#lx", dbdesc->reserved2, (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) ? "I" : "-"), (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) ? "M" : "-"), (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) ? "m" : "s"), (u_long) ntohl (dbdesc->seqnum)); for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsa_header)) ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); assert (p == OSPF6_MESSAGE_END (oh)); } void ospf6_lsreq_print (struct ospf6_header *oh) { char id[16], adv_router[16]; char *p; ospf6_header_print (oh); assert (oh->type == OSPF6_MESSAGE_TYPE_LSREQ); for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsreq_entry)) { struct ospf6_lsreq_entry *e = (struct ospf6_lsreq_entry *) p; inet_ntop (AF_INET, &e->adv_router, adv_router, sizeof (adv_router)); inet_ntop (AF_INET, &e->id, id, sizeof (id)); zlog_debug (" [%s Id:%s Adv:%s]", ospf6_lstype_name (e->type), id, adv_router); } assert (p == OSPF6_MESSAGE_END (oh)); } void ospf6_lsupdate_print (struct ospf6_header *oh) { struct ospf6_lsupdate *lsupdate; u_long num; char *p; ospf6_header_print (oh); assert (oh->type == OSPF6_MESSAGE_TYPE_LSUPDATE); lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); num = ntohl (lsupdate->lsa_number); zlog_debug (" Number of LSA: %ld", num); for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); p < OSPF6_MESSAGE_END (oh) && p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); p += OSPF6_LSA_SIZE (p)) { ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); } assert (p == OSPF6_MESSAGE_END (oh)); } void ospf6_lsack_print (struct ospf6_header *oh) { char *p; ospf6_header_print (oh); assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsa_header)) ospf6_lsa_header_print_raw ((struct ospf6_lsa_header *) p); assert (p == OSPF6_MESSAGE_END (oh)); } static void ospf6_hello_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_hello *hello; struct ospf6_neighbor *on; char *p; int twoway = 0; int neighborchange = 0; int backupseen = 0; hello = (struct ospf6_hello *) ((caddr_t) oh + sizeof (struct ospf6_header)); /* HelloInterval check */ if (ntohs (hello->hello_interval) != oi->hello_interval) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("HelloInterval mismatch"); return; } /* RouterDeadInterval check */ if (ntohs (hello->dead_interval) != oi->dead_interval) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("RouterDeadInterval mismatch"); return; } /* E-bit check */ if (OSPF6_OPT_ISSET (hello->options, OSPF6_OPT_E) != OSPF6_OPT_ISSET (oi->area->options, OSPF6_OPT_E)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("E-bit mismatch"); return; } /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { on = ospf6_neighbor_create (oh->router_id, oi); on->prev_drouter = on->drouter = hello->drouter; on->prev_bdrouter = on->bdrouter = hello->bdrouter; on->priority = hello->priority; } /* always override neighbor's source address and ifindex */ on->ifindex = ntohl (hello->interface_id); memcpy (&on->linklocal_addr, src, sizeof (struct in6_addr)); /* TwoWay check */ for (p = (char *) ((caddr_t) hello + sizeof (struct ospf6_hello)); p + sizeof (u_int32_t) <= OSPF6_MESSAGE_END (oh); p += sizeof (u_int32_t)) { u_int32_t *router_id = (u_int32_t *) p; if (*router_id == oi->area->ospf6->router_id) twoway++; } assert (p == OSPF6_MESSAGE_END (oh)); /* RouterPriority check */ if (on->priority != hello->priority) { on->priority = hello->priority; neighborchange++; } /* DR check */ if (on->drouter != hello->drouter) { on->prev_drouter = on->drouter; on->drouter = hello->drouter; if (on->prev_drouter == on->router_id || on->drouter == on->router_id) neighborchange++; } /* BDR check */ if (on->bdrouter != hello->bdrouter) { on->prev_bdrouter = on->bdrouter; on->bdrouter = hello->bdrouter; if (on->prev_bdrouter == on->router_id || on->bdrouter == on->router_id) neighborchange++; } /* BackupSeen check */ if (oi->state == OSPF6_INTERFACE_WAITING) { if (hello->bdrouter == on->router_id) backupseen++; else if (hello->drouter == on->router_id && hello->bdrouter == htonl (0)) backupseen++; } /* Execute neighbor events */ thread_execute (master, hello_received, on, 0); if (twoway) thread_execute (master, twoway_received, on, 0); else thread_execute (master, oneway_received, on, 0); /* Schedule interface events */ if (backupseen) thread_add_event (master, backup_seen, oi, 0); if (neighborchange) thread_add_event (master, neighbor_change, oi, 0); } static void ospf6_dbdesc_recv_master (struct ospf6_header *oh, struct ospf6_neighbor *on) { struct ospf6_dbdesc *dbdesc; char *p; dbdesc = (struct ospf6_dbdesc *) ((caddr_t) oh + sizeof (struct ospf6_header)); if (on->state < OSPF6_NEIGHBOR_INIT) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state less than Init, ignore"); return; } switch (on->state) { case OSPF6_NEIGHBOR_TWOWAY: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state is 2-Way, ignore"); return; case OSPF6_NEIGHBOR_INIT: thread_execute (master, twoway_received, on, 0); if (on->state != OSPF6_NEIGHBOR_EXSTART) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state is not ExStart, ignore"); return; } /* else fall through to ExStart */ case OSPF6_NEIGHBOR_EXSTART: /* if neighbor obeys us as our slave, schedule negotiation_done and process LSA Headers. Otherwise, ignore this message */ if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && ! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && ntohl (dbdesc->seqnum) == on->dbdesc_seqnum) { /* execute NegotiationDone */ thread_execute (master, negotiation_done, on, 0); /* Record neighbor options */ memcpy (on->options, dbdesc->options, sizeof (on->options)); } else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Negotiation failed"); return; } /* fall through to exchange */ case OSPF6_NEIGHBOR_EXCHANGE: if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) { /* Duplicated DatabaseDescription is dropped by master */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Duplicated dbdesc discarded by Master, ignore"); return; } if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Master/Slave bit mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Initialize bit mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (memcmp (on->options, dbdesc->options, sizeof (on->options))) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Option field mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Sequence number mismatch (%#lx expected)", (u_long) on->dbdesc_seqnum); thread_add_event (master, seqnumber_mismatch, on, 0); return; } break; case OSPF6_NEIGHBOR_LOADING: case OSPF6_NEIGHBOR_FULL: if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) { /* Duplicated DatabaseDescription is dropped by master */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Duplicated dbdesc discarded by Master, ignore"); return; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Not duplicate dbdesc in state %s", ospf6_neighbor_state_str[on->state]); thread_add_event (master, seqnumber_mismatch, on, 0); return; default: assert (0); break; } /* Process LSA headers */ for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsa_header)) { struct ospf6_lsa *his, *mine; struct ospf6_lsdb *lsdb = NULL; his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("%s", his->name); switch (OSPF6_LSA_SCOPE (his->header->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb = on->ospf6_if->lsdb; break; case OSPF6_SCOPE_AREA: lsdb = on->ospf6_if->area->lsdb; break; case OSPF6_SCOPE_AS: lsdb = on->ospf6_if->area->ospf6->lsdb; break; case OSPF6_SCOPE_RESERVED: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Ignoring LSA of reserved scope"); ospf6_lsa_delete (his); continue; break; } if (ntohs (his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL && IS_AREA_STUB (on->ospf6_if->area)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("SeqNumMismatch (E-bit mismatch), discard"); ospf6_lsa_delete (his); thread_add_event (master, seqnumber_mismatch, on, 0); return; } mine = ospf6_lsdb_lookup (his->header->type, his->header->id, his->header->adv_router, lsdb); if (mine == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request (No database copy)"); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else if (ospf6_lsa_compare (his, mine) < 0) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request (Received MoreRecent)"); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Discard (Existing MoreRecent)"); } ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); /* Increment sequence number */ on->dbdesc_seqnum ++; /* schedule send lsreq */ if (on->request_list->count && (on->thread_send_lsreq == NULL)) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); THREAD_OFF (on->thread_send_dbdesc); /* More bit check */ if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) thread_add_event (master, exchange_done, on, 0); else on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); /* save last received dbdesc */ memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); } static void ospf6_dbdesc_recv_slave (struct ospf6_header *oh, struct ospf6_neighbor *on) { struct ospf6_dbdesc *dbdesc; char *p; dbdesc = (struct ospf6_dbdesc *) ((caddr_t) oh + sizeof (struct ospf6_header)); if (on->state < OSPF6_NEIGHBOR_INIT) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state less than Init, ignore"); return; } switch (on->state) { case OSPF6_NEIGHBOR_TWOWAY: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state is 2-Way, ignore"); return; case OSPF6_NEIGHBOR_INIT: thread_execute (master, twoway_received, on, 0); if (on->state != OSPF6_NEIGHBOR_EXSTART) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state is not ExStart, ignore"); return; } /* else fall through to ExStart */ case OSPF6_NEIGHBOR_EXSTART: /* If the neighbor is Master, act as Slave. Schedule negotiation_done and process LSA Headers. Otherwise, ignore this message */ if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT) && CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MBIT) && CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT) && ntohs (oh->length) == sizeof (struct ospf6_header) + sizeof (struct ospf6_dbdesc)) { /* set the master/slave bit to slave */ UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT); /* set the DD sequence number to one specified by master */ on->dbdesc_seqnum = ntohl (dbdesc->seqnum); /* schedule NegotiationDone */ thread_execute (master, negotiation_done, on, 0); /* Record neighbor options */ memcpy (on->options, dbdesc->options, sizeof (on->options)); } else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Negotiation failed"); return; } break; case OSPF6_NEIGHBOR_EXCHANGE: if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) { /* Duplicated DatabaseDescription causes slave to retransmit */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Duplicated dbdesc causes retransmit"); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return; } if (! CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_MSBIT)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Master/Slave bit mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (CHECK_FLAG (dbdesc->bits, OSPF6_DBDESC_IBIT)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Initialize bit mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (memcmp (on->options, dbdesc->options, sizeof (on->options))) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Option field mismatch"); thread_add_event (master, seqnumber_mismatch, on, 0); return; } if (ntohl (dbdesc->seqnum) != on->dbdesc_seqnum + 1) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Sequence number mismatch (%#lx expected)", (u_long) on->dbdesc_seqnum + 1); thread_add_event (master, seqnumber_mismatch, on, 0); return; } break; case OSPF6_NEIGHBOR_LOADING: case OSPF6_NEIGHBOR_FULL: if (! memcmp (dbdesc, &on->dbdesc_last, sizeof (struct ospf6_dbdesc))) { /* Duplicated DatabaseDescription causes slave to retransmit */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Duplicated dbdesc causes retransmit"); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send, on, 0); return; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Not duplicate dbdesc in state %s", ospf6_neighbor_state_str[on->state]); thread_add_event (master, seqnumber_mismatch, on, 0); return; default: assert (0); break; } /* Process LSA headers */ for (p = (char *) ((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsa_header)) { struct ospf6_lsa *his, *mine; struct ospf6_lsdb *lsdb = NULL; his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); switch (OSPF6_LSA_SCOPE (his->header->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb = on->ospf6_if->lsdb; break; case OSPF6_SCOPE_AREA: lsdb = on->ospf6_if->area->lsdb; break; case OSPF6_SCOPE_AS: lsdb = on->ospf6_if->area->ospf6->lsdb; break; case OSPF6_SCOPE_RESERVED: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Ignoring LSA of reserved scope"); ospf6_lsa_delete (his); continue; break; } if (OSPF6_LSA_SCOPE (his->header->type) == OSPF6_SCOPE_AS && IS_AREA_STUB (on->ospf6_if->area)) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("E-bit mismatch with LSA Headers"); ospf6_lsa_delete (his); thread_add_event (master, seqnumber_mismatch, on, 0); return; } mine = ospf6_lsdb_lookup (his->header->type, his->header->id, his->header->adv_router, lsdb); if (mine == NULL || ospf6_lsa_compare (his, mine) < 0) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Add request-list: %s", his->name); ospf6_lsdb_add (ospf6_lsa_copy(his), on->request_list); } ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); /* Set sequence number to Master's */ on->dbdesc_seqnum = ntohl (dbdesc->seqnum); /* schedule send lsreq */ if ((on->thread_send_lsreq == NULL) && (on->request_list->count)) on->thread_send_lsreq = thread_add_event (master, ospf6_lsreq_send, on, 0); THREAD_OFF (on->thread_send_dbdesc); on->thread_send_dbdesc = thread_add_event (master, ospf6_dbdesc_send_newone, on, 0); /* save last received dbdesc */ memcpy (&on->dbdesc_last, dbdesc, sizeof (struct ospf6_dbdesc)); } static void ospf6_dbdesc_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_neighbor *on; struct ospf6_dbdesc *dbdesc; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor not found, ignore"); return; } dbdesc = (struct ospf6_dbdesc *) ((caddr_t) oh + sizeof (struct ospf6_header)); /* Interface MTU check */ if (!oi->mtu_ignore && ntohs (dbdesc->ifmtu) != oi->ifmtu) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("I/F MTU mismatch"); return; } if (dbdesc->reserved1 || dbdesc->reserved2) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Non-0 reserved field in %s's DbDesc, correct", on->name); dbdesc->reserved1 = 0; dbdesc->reserved2 = 0; } if (ntohl (oh->router_id) < ntohl (ospf6->router_id)) ospf6_dbdesc_recv_master (oh, on); else if (ntohl (ospf6->router_id) < ntohl (oh->router_id)) ospf6_dbdesc_recv_slave (oh, on); else { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Can't decide which is master, ignore"); } } static void ospf6_lsreq_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_neighbor *on; char *p; struct ospf6_lsreq_entry *e; struct ospf6_lsdb *lsdb = NULL; struct ospf6_lsa *lsa; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor not found, ignore"); return; } if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING && on->state != OSPF6_NEIGHBOR_FULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state less than Exchange, ignore"); return; } /* Process each request */ for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); p + sizeof (struct ospf6_lsreq_entry) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsreq_entry)) { e = (struct ospf6_lsreq_entry *) p; switch (OSPF6_LSA_SCOPE (e->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb = on->ospf6_if->lsdb; break; case OSPF6_SCOPE_AREA: lsdb = on->ospf6_if->area->lsdb; break; case OSPF6_SCOPE_AS: lsdb = on->ospf6_if->area->ospf6->lsdb; break; default: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Ignoring LSA of reserved scope"); continue; break; } /* Find database copy */ lsa = ospf6_lsdb_lookup (e->type, e->id, e->adv_router, lsdb); if (lsa == NULL) { char id[16], adv_router[16]; if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) { inet_ntop (AF_INET, &e->id, id, sizeof (id)); inet_ntop (AF_INET, &e->adv_router, adv_router, sizeof (adv_router)); zlog_debug ("Can't find requested [%s Id:%s Adv:%s]", ospf6_lstype_name (e->type), id, adv_router); } thread_add_event (master, bad_lsreq, on, 0); return; } ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->lsupdate_list); } assert (p == OSPF6_MESSAGE_END (oh)); /* schedule send lsupdate */ THREAD_OFF (on->thread_send_lsupdate); on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); } /* Verify, that the specified memory area contains exactly N valid IPv6 prefixes as specified by RFC5340, A.4.1. */ static unsigned ospf6_prefixes_examin ( struct ospf6_prefix *current, /* start of buffer */ unsigned length, const u_int32_t req_num_pfxs /* always compared with the actual number of prefixes */ ) { u_char requested_pfx_bytes; u_int32_t real_num_pfxs = 0; while (length) { if (length < OSPF6_PREFIX_MIN_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized IPv6 prefix header", __func__); return MSG_NG; } /* safe to look deeper */ if (current->prefix_length > IPV6_MAX_BITLEN) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid PrefixLength (%u bits)", __func__, current->prefix_length); return MSG_NG; } /* covers both fixed- and variable-sized fields */ requested_pfx_bytes = OSPF6_PREFIX_MIN_SIZE + OSPF6_PREFIX_SPACE (current->prefix_length); if (requested_pfx_bytes > length) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized IPv6 prefix", __func__); return MSG_NG; } /* next prefix */ length -= requested_pfx_bytes; current = (struct ospf6_prefix *) ((caddr_t) current + requested_pfx_bytes); real_num_pfxs++; } if (real_num_pfxs != req_num_pfxs) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: IPv6 prefix number mismatch (%u required, %u real)", __func__, req_num_pfxs, real_num_pfxs); return MSG_NG; } return MSG_OK; } /* Verify an LSA to have a valid length and dispatch further (where appropriate) to check if the contents, including nested IPv6 prefixes, is properly sized/aligned within the LSA. Note that this function gets LSA type in network byte order, uses in host byte order and passes to ospf6_lstype_name() in network byte order again. */ static unsigned ospf6_lsa_examin (struct ospf6_lsa_header *lsah, const u_int16_t lsalen, const u_char headeronly) { struct ospf6_intra_prefix_lsa *intra_prefix_lsa; struct ospf6_as_external_lsa *as_external_lsa; struct ospf6_link_lsa *link_lsa; unsigned exp_length; u_int8_t ltindex; u_int16_t lsatype; /* In case an additional minimum length constraint is defined for current LSA type, make sure that this constraint is met. */ lsatype = ntohs (lsah->type); ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK; if ( ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex] && lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE ) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA", __func__, lsalen); return MSG_NG; } switch (lsatype) { case OSPF6_LSTYPE_ROUTER: /* RFC5340 A.4.3, LSA header + OSPF6_ROUTER_LSA_MIN_SIZE bytes followed by N>=0 interface descriptions. */ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE) % OSPF6_ROUTER_LSDESC_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: interface description alignment error", __func__); return MSG_NG; } break; case OSPF6_LSTYPE_NETWORK: /* RFC5340 A.4.4, LSA header + OSPF6_NETWORK_LSA_MIN_SIZE bytes followed by N>=0 attached router descriptions. */ if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_NETWORK_LSA_MIN_SIZE) % OSPF6_NETWORK_LSDESC_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: router description alignment error", __func__); return MSG_NG; } break; case OSPF6_LSTYPE_INTER_PREFIX: /* RFC5340 A.4.5, LSA header + OSPF6_INTER_PREFIX_LSA_MIN_SIZE bytes followed by 3-4 fields of a single IPv6 prefix. */ if (headeronly) break; return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_PREFIX_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTER_PREFIX_LSA_MIN_SIZE, 1 ); case OSPF6_LSTYPE_INTER_ROUTER: /* RFC5340 A.4.6, fixed-size LSA. */ if (lsalen > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: oversized (%u B) LSA", __func__, lsalen); return MSG_NG; } break; case OSPF6_LSTYPE_AS_EXTERNAL: /* RFC5340 A.4.7, same as A.4.8. */ case OSPF6_LSTYPE_TYPE_7: /* RFC5340 A.4.8, LSA header + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE bytes followed by 3-4 fields of IPv6 prefix and 3 conditional LSA fields: 16 bytes of forwarding address, 4 bytes of external route tag, 4 bytes of referenced link state ID. */ if (headeronly) break; as_external_lsa = (struct ospf6_as_external_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); exp_length = OSPF6_LSA_HEADER_SIZE + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE; /* To find out if the last optional field (Referenced Link State ID) is assumed in this LSA, we need to access fixed fields of the IPv6 prefix before ospf6_prefix_examin() confirms its sizing. */ if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); return MSG_NG; } /* forwarding address */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F)) exp_length += 16; /* external route tag */ if (CHECK_FLAG (as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) exp_length += 4; /* referenced link state ID */ if (as_external_lsa->prefix.u._prefix_referenced_lstype) exp_length += 4; /* All the fixed-size fields (mandatory and optional) must fit. I.e., this check does not include any IPv6 prefix fields. */ if (exp_length > lsalen) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) LSA header", __func__, lsalen); return MSG_NG; } /* The last call completely covers the remainder (IPv6 prefix). */ return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) as_external_lsa + OSPF6_AS_EXTERNAL_LSA_MIN_SIZE), lsalen - exp_length, 1 ); case OSPF6_LSTYPE_LINK: /* RFC5340 A.4.9, LSA header + OSPF6_LINK_LSA_MIN_SIZE bytes followed by N>=0 IPv6 prefix blocks (with N declared beforehand). */ if (headeronly) break; link_lsa = (struct ospf6_link_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) link_lsa + OSPF6_LINK_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_LINK_LSA_MIN_SIZE, ntohl (link_lsa->prefix_num) /* 32 bits */ ); case OSPF6_LSTYPE_INTRA_PREFIX: /* RFC5340 A.4.10, LSA header + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE bytes followed by N>=0 IPv6 prefixes (with N declared beforehand). */ if (headeronly) break; intra_prefix_lsa = (struct ospf6_intra_prefix_lsa *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); return ospf6_prefixes_examin ( (struct ospf6_prefix *) ((caddr_t) intra_prefix_lsa + OSPF6_INTRA_PREFIX_LSA_MIN_SIZE), lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_INTRA_PREFIX_LSA_MIN_SIZE, ntohs (intra_prefix_lsa->prefix_num) /* 16 bits */ ); } /* No additional validation is possible for unknown LSA types, which are themselves valid in OPSFv3, hence the default decision is to accept. */ return MSG_OK; } /* Verify if the provided input buffer is a valid sequence of LSAs. This includes verification of LSA blocks length/alignment and dispatching of deeper-level checks. */ static unsigned ospf6_lsaseq_examin ( struct ospf6_lsa_header *lsah, /* start of buffered data */ size_t length, const u_char headeronly, /* When declared_num_lsas is not 0, compare it to the real number of LSAs and treat the difference as an error. */ const u_int32_t declared_num_lsas ) { u_int32_t counted_lsas = 0; while (length) { u_int16_t lsalen; if (length < OSPF6_LSA_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", __func__, length, counted_lsas); return MSG_NG; } /* save on ntohs() calls here and in the LSA validator */ lsalen = OSPF6_LSA_SIZE (lsah); if (lsalen < OSPF6_LSA_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", __func__, counted_lsas, lsalen); return MSG_NG; } if (headeronly) { /* less checks here and in ospf6_lsa_examin() */ if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 1)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in header-only %s LSA #%u", __func__, ospf6_lstype_name (lsah->type), counted_lsas); return MSG_NG; } lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + OSPF6_LSA_HEADER_SIZE); length -= OSPF6_LSA_HEADER_SIZE; } else { /* make sure the input buffer is deep enough before further checks */ if (lsalen > length) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B", __func__, ospf6_lstype_name (lsah->type), counted_lsas, lsalen, length); return MSG_NG; } if (MSG_OK != ospf6_lsa_examin (lsah, lsalen, 0)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s LSA #%u", __func__, ospf6_lstype_name (lsah->type), counted_lsas); return MSG_NG; } lsah = (struct ospf6_lsa_header *) ((caddr_t) lsah + lsalen); length -= lsalen; } counted_lsas++; } if (declared_num_lsas && counted_lsas != declared_num_lsas) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", __func__, declared_num_lsas, counted_lsas); return MSG_NG; } return MSG_OK; } /* Verify a complete OSPF packet for proper sizing/alignment. */ static unsigned ospf6_packet_examin (struct ospf6_header *oh, const unsigned bytesonwire) { struct ospf6_lsupdate *lsupd; unsigned test; /* length, 1st approximation */ if (bytesonwire < OSPF6_HEADER_SIZE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); return MSG_NG; } /* Now it is safe to access header fields. */ if (bytesonwire != ntohs (oh->length)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: packet length error (%u real, %u declared)", __func__, bytesonwire, ntohs (oh->length)); return MSG_NG; } /* version check */ if (oh->version != OSPFV3_VERSION) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); return MSG_NG; } /* length, 2nd approximation */ if ( oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type] && bytesonwire < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type] ) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: undersized (%u B) %s packet", __func__, bytesonwire, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; } /* type-specific deeper validation */ switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: /* RFC5340 A.3.2, packet header + OSPF6_HELLO_MIN_SIZE bytes followed by N>=0 router-IDs. */ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE) % 4) return MSG_OK; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: alignment error in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_DBDESC: /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes followed by N>=0 header-only LSAs. */ test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_DB_DESC_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_DB_DESC_MIN_SIZE, 1, 0 ); break; case OSPF6_MESSAGE_TYPE_LSREQ: /* RFC5340 A.3.4, packet header + N>=0 LS description blocks. */ if (0 == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE) % OSPF6_LSREQ_LSDESC_FIX_SIZE) return MSG_OK; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: alignment error in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return MSG_NG; case OSPF6_MESSAGE_TYPE_LSUPDATE: /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes followed by N>=0 full LSAs (with N declared beforehand). */ lsupd = (struct ospf6_lsupdate *) ((caddr_t) oh + OSPF6_HEADER_SIZE); test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) lsupd + OSPF6_LS_UPD_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_UPD_MIN_SIZE, 0, ntohl (lsupd->lsa_number) /* 32 bits */ ); break; case OSPF6_MESSAGE_TYPE_LSACK: /* RFC5340 A.3.6, packet header + N>=0 header-only LSAs. */ test = ospf6_lsaseq_examin ( (struct ospf6_lsa_header *) ((caddr_t) oh + OSPF6_HEADER_SIZE + OSPF6_LS_ACK_MIN_SIZE), bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_ACK_MIN_SIZE, 1, 0 ); break; default: if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: invalid (%u) message type", __func__, oh->type); return MSG_NG; } if (test != MSG_OK && IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: anomaly in %s packet", __func__, LOOKUP (ospf6_message_type_str, oh->type)); return test; } /* Verify particular fields of otherwise correct received OSPF packet to meet the requirements of RFC. */ static int ospf6_rxpacket_examin (struct ospf6_interface *oi, struct ospf6_header *oh, const unsigned bytesonwire) { char buf[2][INET_ADDRSTRLEN]; if (MSG_OK != ospf6_packet_examin (oh, bytesonwire)) return MSG_NG; /* Area-ID check */ if (oh->area_id != oi->area->area_id) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) { if (oh->area_id == OSPF_AREA_BACKBONE) zlog_debug ("%s: Message may be via Virtual Link: not supported", __func__); else zlog_debug ( "%s: Area-ID mismatch (my %s, rcvd %s)", __func__, inet_ntop (AF_INET, &oi->area->area_id, buf[0], INET_ADDRSTRLEN), inet_ntop (AF_INET, &oh->area_id, buf[1], INET_ADDRSTRLEN) ); } return MSG_NG; } /* Instance-ID check */ if (oh->instance_id != oi->instance_id) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("%s: Instance-ID mismatch (my %u, rcvd %u)", __func__, oi->instance_id, oh->instance_id); return MSG_NG; } /* Router-ID check */ if (oh->router_id == oi->area->ospf6->router_id) { zlog_warn ("%s: Duplicate Router-ID (%s)", __func__, inet_ntop (AF_INET, &oh->router_id, buf[0], INET_ADDRSTRLEN)); return MSG_NG; } return MSG_OK; } static void ospf6_lsupdate_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_neighbor *on; struct ospf6_lsupdate *lsupdate; char *p; on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor not found, ignore"); return; } if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING && on->state != OSPF6_NEIGHBOR_FULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state less than Exchange, ignore"); return; } lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); /* Process LSAs */ for (p = (char *) ((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); p < OSPF6_MESSAGE_END (oh) && p + OSPF6_LSA_SIZE (p) <= OSPF6_MESSAGE_END (oh); p += OSPF6_LSA_SIZE (p)) { ospf6_receive_lsa (on, (struct ospf6_lsa_header *) p); } assert (p == OSPF6_MESSAGE_END (oh)); } static void ospf6_lsack_recv (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { struct ospf6_neighbor *on; char *p; struct ospf6_lsa *his, *mine; struct ospf6_lsdb *lsdb = NULL; assert (oh->type == OSPF6_MESSAGE_TYPE_LSACK); on = ospf6_neighbor_lookup (oh->router_id, oi); if (on == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor not found, ignore"); return; } if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING && on->state != OSPF6_NEIGHBOR_FULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Neighbor state less than Exchange, ignore"); return; } for (p = (char *) ((caddr_t) oh + sizeof (struct ospf6_header)); p + sizeof (struct ospf6_lsa_header) <= OSPF6_MESSAGE_END (oh); p += sizeof (struct ospf6_lsa_header)) { his = ospf6_lsa_create_headeronly ((struct ospf6_lsa_header *) p); switch (OSPF6_LSA_SCOPE (his->header->type)) { case OSPF6_SCOPE_LINKLOCAL: lsdb = on->ospf6_if->lsdb; break; case OSPF6_SCOPE_AREA: lsdb = on->ospf6_if->area->lsdb; break; case OSPF6_SCOPE_AS: lsdb = on->ospf6_if->area->ospf6->lsdb; break; case OSPF6_SCOPE_RESERVED: if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Ignoring LSA of reserved scope"); ospf6_lsa_delete (his); continue; break; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("%s acknowledged by %s", his->name, on->name); /* Find database copy */ mine = ospf6_lsdb_lookup (his->header->type, his->header->id, his->header->adv_router, lsdb); if (mine == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("No database copy"); ospf6_lsa_delete (his); continue; } /* Check if the LSA is on his retrans-list */ mine = ospf6_lsdb_lookup (his->header->type, his->header->id, his->header->adv_router, on->retrans_list); if (mine == NULL) { if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Not on %s's retrans-list", on->name); ospf6_lsa_delete (his); continue; } if (ospf6_lsa_compare (his, mine) != 0) { /* Log this questionable acknowledgement, and examine the next one. */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Questionable acknowledgement"); ospf6_lsa_delete (his); continue; } if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) zlog_debug ("Acknowledged, remove from %s's retrans-list", on->name); ospf6_decrement_retrans_count (mine); if (OSPF6_LSA_IS_MAXAGE (mine)) ospf6_maxage_remove (on->ospf6_if->area->ospf6); ospf6_lsdb_remove (mine, on->retrans_list); ospf6_lsa_delete (his); } assert (p == OSPF6_MESSAGE_END (oh)); } static u_char *recvbuf = NULL; static u_char *sendbuf = NULL; static unsigned int iobuflen = 0; int ospf6_iobuf_size (unsigned int size) { u_char *recvnew, *sendnew; if (size <= iobuflen) return iobuflen; recvnew = XMALLOC (MTYPE_OSPF6_MESSAGE, size); sendnew = XMALLOC (MTYPE_OSPF6_MESSAGE, size); if (recvnew == NULL || sendnew == NULL) { if (recvnew) XFREE (MTYPE_OSPF6_MESSAGE, recvnew); if (sendnew) XFREE (MTYPE_OSPF6_MESSAGE, sendnew); zlog_debug ("Could not allocate I/O buffer of size %d.", size); return iobuflen; } if (recvbuf) XFREE (MTYPE_OSPF6_MESSAGE, recvbuf); if (sendbuf) XFREE (MTYPE_OSPF6_MESSAGE, sendbuf); recvbuf = recvnew; sendbuf = sendnew; iobuflen = size; return iobuflen; } void ospf6_message_terminate (void) { if (recvbuf) { XFREE (MTYPE_OSPF6_MESSAGE, recvbuf); recvbuf = NULL; } if (sendbuf) { XFREE (MTYPE_OSPF6_MESSAGE, sendbuf); sendbuf = NULL; } iobuflen = 0; } int ospf6_receive (struct thread *thread) { int sockfd; unsigned int len; char srcname[64], dstname[64]; struct in6_addr src, dst; unsigned int ifindex; struct iovec iovector[2]; struct ospf6_interface *oi; struct ospf6_header *oh; /* add next read thread */ sockfd = THREAD_FD (thread); thread_add_read (master, ospf6_receive, NULL, sockfd); /* initialize */ memset (&src, 0, sizeof (src)); memset (&dst, 0, sizeof (dst)); ifindex = 0; memset (recvbuf, 0, iobuflen); iovector[0].iov_base = recvbuf; iovector[0].iov_len = iobuflen; iovector[1].iov_base = NULL; iovector[1].iov_len = 0; /* receive message */ len = ospf6_recvmsg (&src, &dst, &ifindex, iovector); if (len > iobuflen) { zlog_err ("Excess message read"); return 0; } oi = ospf6_interface_lookup_by_ifindex (ifindex); if (oi == NULL || oi->area == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) { zlog_debug ("Message received on disabled interface"); return 0; } if (CHECK_FLAG (oi->flag, OSPF6_INTERFACE_PASSIVE)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) zlog_debug ("%s: Ignore message on passive interface %s", __func__, oi->interface->name); return 0; } oh = (struct ospf6_header *) recvbuf; if (ospf6_rxpacket_examin (oi, oh, len) != MSG_OK) return 0; /* Being here means, that no sizing/alignment issues were detected in the input packet. This renders the additional checks performed below and also in the type-specific dispatching functions a dead code, which can be dismissed in a cleanup-focused review round later. */ /* Log */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, RECV)) { inet_ntop (AF_INET6, &src, srcname, sizeof (srcname)); inet_ntop (AF_INET6, &dst, dstname, sizeof (dstname)); zlog_debug ("%s received on %s", LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" dst: %s", dstname); switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: ospf6_hello_print (oh); break; case OSPF6_MESSAGE_TYPE_DBDESC: ospf6_dbdesc_print (oh); break; case OSPF6_MESSAGE_TYPE_LSREQ: ospf6_lsreq_print (oh); break; case OSPF6_MESSAGE_TYPE_LSUPDATE: ospf6_lsupdate_print (oh); break; case OSPF6_MESSAGE_TYPE_LSACK: ospf6_lsack_print (oh); break; default: assert (0); } } switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: ospf6_hello_recv (&src, &dst, oi, oh); break; case OSPF6_MESSAGE_TYPE_DBDESC: ospf6_dbdesc_recv (&src, &dst, oi, oh); break; case OSPF6_MESSAGE_TYPE_LSREQ: ospf6_lsreq_recv (&src, &dst, oi, oh); break; case OSPF6_MESSAGE_TYPE_LSUPDATE: ospf6_lsupdate_recv (&src, &dst, oi, oh); break; case OSPF6_MESSAGE_TYPE_LSACK: ospf6_lsack_recv (&src, &dst, oi, oh); break; default: assert (0); } return 0; } static void ospf6_send (struct in6_addr *src, struct in6_addr *dst, struct ospf6_interface *oi, struct ospf6_header *oh) { int len; char srcname[64], dstname[64]; struct iovec iovector[2]; /* initialize */ iovector[0].iov_base = (caddr_t) oh; iovector[0].iov_len = ntohs (oh->length); iovector[1].iov_base = NULL; iovector[1].iov_len = 0; /* fill OSPF header */ oh->version = OSPFV3_VERSION; /* message type must be set before */ /* message length must be set before */ oh->router_id = oi->area->ospf6->router_id; oh->area_id = oi->area->area_id; /* checksum is calculated by kernel */ oh->instance_id = oi->instance_id; oh->reserved = 0; /* Log */ if (IS_OSPF6_DEBUG_MESSAGE (oh->type, SEND)) { inet_ntop (AF_INET6, dst, dstname, sizeof (dstname)); if (src) inet_ntop (AF_INET6, src, srcname, sizeof (srcname)); else memset (srcname, 0, sizeof (srcname)); zlog_debug ("%s send on %s", LOOKUP (ospf6_message_type_str, oh->type), oi->interface->name); zlog_debug (" src: %s", srcname); zlog_debug (" dst: %s", dstname); switch (oh->type) { case OSPF6_MESSAGE_TYPE_HELLO: ospf6_hello_print (oh); break; case OSPF6_MESSAGE_TYPE_DBDESC: ospf6_dbdesc_print (oh); break; case OSPF6_MESSAGE_TYPE_LSREQ: ospf6_lsreq_print (oh); break; case OSPF6_MESSAGE_TYPE_LSUPDATE: ospf6_lsupdate_print (oh); break; case OSPF6_MESSAGE_TYPE_LSACK: ospf6_lsack_print (oh); break; default: zlog_debug ("Unknown message"); assert (0); break; } } /* send message */ len = ospf6_sendmsg (src, dst, &oi->interface->ifindex, iovector); if (len != ntohs (oh->length)) zlog_err ("Could not send entire message"); } static uint32_t ospf6_packet_max(struct ospf6_interface *oi) { assert (oi->ifmtu > sizeof (struct ip6_hdr)); return oi->ifmtu - (sizeof (struct ip6_hdr)); } int ospf6_hello_send (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; struct ospf6_hello *hello; u_char *p; struct listnode *node, *nnode; struct ospf6_neighbor *on; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_hello = (struct thread *) NULL; if (oi->state <= OSPF6_INTERFACE_DOWN) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) zlog_debug ("Unable to send Hello on down interface %s", oi->interface->name); return 0; } if (iobuflen == 0) { zlog_debug ("Unable to send Hello on interface %s iobuflen is 0", oi->interface->name); return 0; } /* set next thread */ oi->thread_send_hello = thread_add_timer (master, ospf6_hello_send, oi, oi->hello_interval); memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; hello = (struct ospf6_hello *)((caddr_t) oh + sizeof (struct ospf6_header)); hello->interface_id = htonl (oi->interface->ifindex); hello->priority = oi->priority; hello->options[0] = oi->area->options[0]; hello->options[1] = oi->area->options[1]; hello->options[2] = oi->area->options[2]; hello->hello_interval = htons (oi->hello_interval); hello->dead_interval = htons (oi->dead_interval); hello->drouter = oi->drouter; hello->bdrouter = oi->bdrouter; p = (u_char *)((caddr_t) hello + sizeof (struct ospf6_hello)); for (ALL_LIST_ELEMENTS (oi->neighbor_list, node, nnode, on)) { if (on->state < OSPF6_NEIGHBOR_INIT) continue; if (p - sendbuf + sizeof (u_int32_t) > ospf6_packet_max(oi)) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_HELLO, SEND)) zlog_debug ("sending Hello message: exceeds I/F MTU"); break; } memcpy (p, &on->router_id, sizeof (u_int32_t)); p += sizeof (u_int32_t); } oh->type = OSPF6_MESSAGE_TYPE_HELLO; oh->length = htons (p - sendbuf); ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); return 0; } int ospf6_dbdesc_send (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_dbdesc *dbdesc; u_char *p; struct ospf6_lsa *lsa; struct in6_addr *dst; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_dbdesc = (struct thread *) NULL; if (on->state < OSPF6_NEIGHBOR_EXSTART) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_DBDESC, SEND)) zlog_debug ("Quit to send DbDesc to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); return 0; } /* set next thread if master */ if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) on->thread_send_dbdesc = thread_add_timer (master, ospf6_dbdesc_send, on, on->ospf6_if->rxmt_interval); memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; dbdesc = (struct ospf6_dbdesc *)((caddr_t) oh + sizeof (struct ospf6_header)); /* if this is initial one, initialize sequence number for DbDesc */ if (CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT) && (on->dbdesc_seqnum == 0)) { struct timeval tv; if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0) tv.tv_sec = 1; on->dbdesc_seqnum = tv.tv_sec; } dbdesc->options[0] = on->ospf6_if->area->options[0]; dbdesc->options[1] = on->ospf6_if->area->options[1]; dbdesc->options[2] = on->ospf6_if->area->options[2]; dbdesc->ifmtu = htons (on->ospf6_if->ifmtu); dbdesc->bits = on->dbdesc_bits; dbdesc->seqnum = htonl (on->dbdesc_seqnum); /* if this is not initial one, set LSA headers in dbdesc */ p = (u_char *)((caddr_t) dbdesc + sizeof (struct ospf6_dbdesc)); if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_IBIT)) { for (lsa = ospf6_lsdb_head (on->dbdesc_list); lsa; lsa = ospf6_lsdb_next (lsa)) { ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock (lsa); break; } memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); } } oh->type = OSPF6_MESSAGE_TYPE_DBDESC; oh->length = htons (p - sendbuf); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) dst = &allspfrouters6; else dst = &on->linklocal_addr; ospf6_send (on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh); return 0; } int ospf6_dbdesc_send_newone (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_lsa *lsa; unsigned int size = 0; on = (struct ospf6_neighbor *) THREAD_ARG (thread); ospf6_lsdb_remove_all (on->dbdesc_list); /* move LSAs from summary_list to dbdesc_list (within neighbor structure) so that ospf6_send_dbdesc () can send those LSAs */ size = sizeof (struct ospf6_lsa_header) + sizeof (struct ospf6_dbdesc); for (lsa = ospf6_lsdb_head (on->summary_list); lsa; lsa = ospf6_lsdb_next (lsa)) { if (size + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsdb_add (ospf6_lsa_copy (lsa), on->dbdesc_list); ospf6_lsdb_remove (lsa, on->summary_list); size += sizeof (struct ospf6_lsa_header); } if (on->summary_list->count == 0) UNSET_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT); /* If slave, More bit check must be done here */ if (! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ ! CHECK_FLAG (on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) && ! CHECK_FLAG (on->dbdesc_bits, OSPF6_DBDESC_MBIT)) thread_add_event (master, exchange_done, on, 0); thread_execute (master, ospf6_dbdesc_send, on, 0); return 0; } int ospf6_lsreq_send (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_lsreq_entry *e; u_char *p; struct ospf6_lsa *lsa, *last_req; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsreq = (struct thread *) NULL; /* LSReq will be sent only in ExStart or Loading */ if (on->state != OSPF6_NEIGHBOR_EXCHANGE && on->state != OSPF6_NEIGHBOR_LOADING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSREQ, SEND)) zlog_debug ("Quit to send LSReq to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); return 0; } /* schedule loading_done if request list is empty */ if (on->request_list->count == 0) { thread_add_event (master, loading_done, on, 0); return 0; } memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; last_req = NULL; /* set Request entries in lsreq */ p = (u_char *)((caddr_t) oh + sizeof (struct ospf6_header)); for (lsa = ospf6_lsdb_head (on->request_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsreq_entry) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock (lsa); break; } e = (struct ospf6_lsreq_entry *) p; e->type = lsa->header->type; e->id = lsa->header->id; e->adv_router = lsa->header->adv_router; p += sizeof (struct ospf6_lsreq_entry); last_req = lsa; } if (last_req != NULL) { if (on->last_ls_req != NULL) { ospf6_lsa_unlock (on->last_ls_req); } ospf6_lsa_lock (last_req); on->last_ls_req = last_req; } oh->type = OSPF6_MESSAGE_TYPE_LSREQ; oh->length = htons (p - sendbuf); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); /* set next thread */ if (on->request_list->count != 0) { on->thread_send_lsreq = thread_add_timer (master, ospf6_lsreq_send, on, on->ospf6_if->rxmt_interval); } return 0; } int ospf6_lsupdate_send_neighbor (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; int lsa_cnt; struct ospf6_lsa *lsa; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsupdate = (struct thread *) NULL; if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_debug ("LSUpdate to neighbor %s", on->name); if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_debug ("Quit to send (neighbor state %s)", ospf6_neighbor_state_str[on->state]); return 0; } memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 0; /* lsupdate_list lists those LSA which doesn't need to be retransmitted. remove those from the list */ for (lsa = ospf6_lsdb_head (on->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsupdate_list); } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); lsupdate->lsa_number = htonl (lsa_cnt); if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) || (on->ospf6_if->state == OSPF6_INTERFACE_DR) || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } /* The addresses used for retransmissions are different from those sent the first time and so we need to separate them here. */ memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *) ((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 0; for (lsa = ospf6_lsdb_head (on->retrans_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + (unsigned int)OSPF6_LSA_SIZE (lsa->header)) > ospf6_packet_max(on->ospf6_if)) { ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); lsa_cnt++; } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); lsupdate->lsa_number = htonl (lsa_cnt); if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT) ospf6_send (on->ospf6_if->linklocal_addr, &allspfrouters6, on->ospf6_if, oh); else ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } if (on->lsupdate_list->count != 0) on->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_neighbor, on, 0); else if (on->retrans_list->count != 0) on->thread_send_lsupdate = thread_add_timer (master, ospf6_lsupdate_send_neighbor, on, on->ospf6_if->rxmt_interval); return 0; } int ospf6_lsupdate_send_interface (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; struct ospf6_lsupdate *lsupdate; u_char *p; int lsa_cnt; struct ospf6_lsa *lsa; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_lsupdate = (struct thread *) NULL; if (oi->state <= OSPF6_INTERFACE_WAITING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSUPDATE, SEND)) zlog_debug ("Quit to send LSUpdate to interface %s state %s", oi->interface->name, ospf6_interface_state_str[oi->state]); return 0; } /* if we have nothing to send, return */ if (oi->lsupdate_list->count == 0) return 0; memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; lsupdate = (struct ospf6_lsupdate *)((caddr_t) oh + sizeof (struct ospf6_header)); p = (u_char *)((caddr_t) lsupdate + sizeof (struct ospf6_lsupdate)); lsa_cnt = 0; for (lsa = ospf6_lsdb_head (oi->lsupdate_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if ( (p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE (lsa->header))) > ospf6_packet_max(oi)) { ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, OSPF6_LSA_SIZE (lsa->header)); p += OSPF6_LSA_SIZE (lsa->header); lsa_cnt++; assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsupdate_list); } if (lsa_cnt) { lsupdate->lsa_number = htonl (lsa_cnt); oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE; oh->length = htons (p - sendbuf); if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (oi->state == OSPF6_INTERFACE_DR) || (oi->state == OSPF6_INTERFACE_BDR)) ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); else ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); } if (oi->lsupdate_list->count > 0) { oi->thread_send_lsupdate = thread_add_event (master, ospf6_lsupdate_send_interface, oi, 0); } return 0; } int ospf6_lsack_send_neighbor (struct thread *thread) { struct ospf6_neighbor *on; struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; int lsa_cnt = 0; on = (struct ospf6_neighbor *) THREAD_ARG (thread); on->thread_send_lsack = (struct thread *) NULL; if (on->state < OSPF6_NEIGHBOR_EXCHANGE) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) zlog_debug ("Quit to send LSAck to neighbor %s state %s", on->name, ospf6_neighbor_state_str[on->state]); return 0; } /* if we have nothing to send, return */ if (on->lsack_list->count == 0) return 0; memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; p = (u_char *)((caddr_t) oh + sizeof (struct ospf6_header)); for (lsa = ospf6_lsdb_head (on->lsack_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(on->ospf6_if)) { /* if we run out of packet size/space here, better to try again soon. */ THREAD_OFF (on->thread_send_lsack); on->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, on->ospf6_if->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, on->lsack_list); lsa_cnt++; } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons (p - sendbuf); ospf6_send (on->ospf6_if->linklocal_addr, &on->linklocal_addr, on->ospf6_if, oh); } if (on->thread_send_lsack == NULL && on->lsack_list->count > 0) { on->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_neighbor, on, 0); } return 0; } int ospf6_lsack_send_interface (struct thread *thread) { struct ospf6_interface *oi; struct ospf6_header *oh; u_char *p; struct ospf6_lsa *lsa; int lsa_cnt = 0; oi = (struct ospf6_interface *) THREAD_ARG (thread); oi->thread_send_lsack = (struct thread *) NULL; if (oi->state <= OSPF6_INTERFACE_WAITING) { if (IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_LSACK, SEND)) zlog_debug ("Quit to send LSAck to interface %s state %s", oi->interface->name, ospf6_interface_state_str[oi->state]); return 0; } /* if we have nothing to send, return */ if (oi->lsack_list->count == 0) return 0; memset (sendbuf, 0, iobuflen); oh = (struct ospf6_header *) sendbuf; p = (u_char *)((caddr_t) oh + sizeof (struct ospf6_header)); for (lsa = ospf6_lsdb_head (oi->lsack_list); lsa; lsa = ospf6_lsdb_next (lsa)) { /* MTU check */ if (p - sendbuf + sizeof (struct ospf6_lsa_header) > ospf6_packet_max(oi)) { /* if we run out of packet size/space here, better to try again soon. */ THREAD_OFF (oi->thread_send_lsack); oi->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_interface, oi, 0); ospf6_lsdb_lsa_unlock (lsa); break; } ospf6_lsa_age_update_to_send (lsa, oi->transdelay); memcpy (p, lsa->header, sizeof (struct ospf6_lsa_header)); p += sizeof (struct ospf6_lsa_header); assert (lsa->lock == 2); ospf6_lsdb_remove (lsa, oi->lsack_list); lsa_cnt++; } if (lsa_cnt) { oh->type = OSPF6_MESSAGE_TYPE_LSACK; oh->length = htons (p - sendbuf); if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT) || (oi->state == OSPF6_INTERFACE_DR) || (oi->state == OSPF6_INTERFACE_BDR)) ospf6_send (oi->linklocal_addr, &allspfrouters6, oi, oh); else ospf6_send (oi->linklocal_addr, &alldrouters6, oi, oh); } if (oi->thread_send_lsack == NULL && oi->lsack_list->count > 0) { oi->thread_send_lsack = thread_add_event (master, ospf6_lsack_send_interface, oi, 0); } return 0; } /* Commands */ DEFUN (debug_ospf6_message, debug_ospf6_message_cmd, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) { unsigned char level = 0; int type = 0; int i; assert (argc > 0); /* check type */ if (! strncmp (argv[0], "u", 1)) type = OSPF6_MESSAGE_TYPE_UNKNOWN; else if (! strncmp (argv[0], "h", 1)) type = OSPF6_MESSAGE_TYPE_HELLO; else if (! strncmp (argv[0], "d", 1)) type = OSPF6_MESSAGE_TYPE_DBDESC; else if (! strncmp (argv[0], "lsr", 3)) type = OSPF6_MESSAGE_TYPE_LSREQ; else if (! strncmp (argv[0], "lsu", 3)) type = OSPF6_MESSAGE_TYPE_LSUPDATE; else if (! strncmp (argv[0], "lsa", 3)) type = OSPF6_MESSAGE_TYPE_LSACK; else if (! strncmp (argv[0], "a", 1)) type = OSPF6_MESSAGE_TYPE_ALL; if (argc == 1) level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; else if (! strncmp (argv[1], "s", 1)) level = OSPF6_DEBUG_MESSAGE_SEND; else if (! strncmp (argv[1], "r", 1)) level = OSPF6_DEBUG_MESSAGE_RECV; if (type == OSPF6_MESSAGE_TYPE_ALL) { for (i = 0; i < 6; i++) OSPF6_DEBUG_MESSAGE_ON (i, level); } else OSPF6_DEBUG_MESSAGE_ON (type, level); return CMD_SUCCESS; } ALIAS (debug_ospf6_message, debug_ospf6_message_sendrecv_cmd, "debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) DEFUN (no_debug_ospf6_message, no_debug_ospf6_message_cmd, "no debug ospf6 message (unknown|hello|dbdesc|lsreq|lsupdate|lsack|all)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" ) { unsigned char level = 0; int type = 0; int i; assert (argc > 0); /* check type */ if (! strncmp (argv[0], "u", 1)) type = OSPF6_MESSAGE_TYPE_UNKNOWN; else if (! strncmp (argv[0], "h", 1)) type = OSPF6_MESSAGE_TYPE_HELLO; else if (! strncmp (argv[0], "d", 1)) type = OSPF6_MESSAGE_TYPE_DBDESC; else if (! strncmp (argv[0], "lsr", 3)) type = OSPF6_MESSAGE_TYPE_LSREQ; else if (! strncmp (argv[0], "lsu", 3)) type = OSPF6_MESSAGE_TYPE_LSUPDATE; else if (! strncmp (argv[0], "lsa", 3)) type = OSPF6_MESSAGE_TYPE_LSACK; else if (! strncmp (argv[0], "a", 1)) type = OSPF6_MESSAGE_TYPE_ALL; if (argc == 1) level = OSPF6_DEBUG_MESSAGE_SEND | OSPF6_DEBUG_MESSAGE_RECV; else if (! strncmp (argv[1], "s", 1)) level = OSPF6_DEBUG_MESSAGE_SEND; else if (! strncmp (argv[1], "r", 1)) level = OSPF6_DEBUG_MESSAGE_RECV; if (type == OSPF6_MESSAGE_TYPE_ALL) { for (i = 0; i < 6; i++) OSPF6_DEBUG_MESSAGE_OFF (i, level); } else OSPF6_DEBUG_MESSAGE_OFF (type, level); return CMD_SUCCESS; } ALIAS (no_debug_ospf6_message, no_debug_ospf6_message_sendrecv_cmd, "no debug ospf6 message " "(unknown|hello|dbdesc|lsreq|lsupdate|lsack|all) (send|recv)", NO_STR DEBUG_STR OSPF6_STR "Debug OSPFv3 message\n" "Debug Unknown message\n" "Debug Hello message\n" "Debug Database Description message\n" "Debug Link State Request message\n" "Debug Link State Update message\n" "Debug Link State Acknowledgement message\n" "Debug All message\n" "Debug only sending message\n" "Debug only receiving message\n" ) int config_write_ospf6_debug_message (struct vty *vty) { const char *type_str[] = {"unknown", "hello", "dbdesc", "lsreq", "lsupdate", "lsack"}; unsigned char s = 0, r = 0; int i; for (i = 0; i < 6; i++) { if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) s |= 1 << i; if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) r |= 1 << i; } if (s == 0x3f && r == 0x3f) { vty_out (vty, "debug ospf6 message all%s", VNL); return 0; } if (s == 0x3f && r == 0) { vty_out (vty, "debug ospf6 message all send%s", VNL); return 0; } else if (s == 0 && r == 0x3f) { vty_out (vty, "debug ospf6 message all recv%s", VNL); return 0; } /* Unknown message is logged by default */ if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND) && ! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) vty_out (vty, "no debug ospf6 message unknown%s", VNL); else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, SEND)) vty_out (vty, "no debug ospf6 message unknown send%s", VNL); else if (! IS_OSPF6_DEBUG_MESSAGE (OSPF6_MESSAGE_TYPE_UNKNOWN, RECV)) vty_out (vty, "no debug ospf6 message unknown recv%s", VNL); for (i = 1; i < 6; i++) { if (IS_OSPF6_DEBUG_MESSAGE (i, SEND) && IS_OSPF6_DEBUG_MESSAGE (i, RECV)) vty_out (vty, "debug ospf6 message %s%s", type_str[i], VNL); else if (IS_OSPF6_DEBUG_MESSAGE (i, SEND)) vty_out (vty, "debug ospf6 message %s send%s", type_str[i], VNL); else if (IS_OSPF6_DEBUG_MESSAGE (i, RECV)) vty_out (vty, "debug ospf6 message %s recv%s", type_str[i], VNL); } return 0; } void install_element_ospf6_debug_message (void) { install_element (ENABLE_NODE, &debug_ospf6_message_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_message_cmd); install_element (ENABLE_NODE, &debug_ospf6_message_sendrecv_cmd); install_element (ENABLE_NODE, &no_debug_ospf6_message_sendrecv_cmd); install_element (CONFIG_NODE, &debug_ospf6_message_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_message_cmd); install_element (CONFIG_NODE, &debug_ospf6_message_sendrecv_cmd); install_element (CONFIG_NODE, &no_debug_ospf6_message_sendrecv_cmd); } quagga-0.99.24.1/ospf6d/ospf6_network.c0000644000175000017500000001557112476520570014420 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "memory.h" #include "sockunion.h" #include "sockopt.h" #include "privs.h" #include "libospf.h" #include "ospf6_proto.h" #include "ospf6_network.h" extern struct zebra_privs_t ospf6d_privs; int ospf6_sock; struct in6_addr allspfrouters6; struct in6_addr alldrouters6; /* setsockopt MulticastLoop to off */ static void ospf6_reset_mcastloop (void) { u_int off = 0; if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof (u_int)) < 0) zlog_warn ("Network: reset IPV6_MULTICAST_LOOP failed: %s", safe_strerror (errno)); } static void ospf6_set_pktinfo (void) { setsockopt_ipv6_pktinfo (ospf6_sock, 1); } static void ospf6_set_transport_class (void) { #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv6_tclass (ospf6_sock, IPTOS_PREC_INTERNETCONTROL); #endif } static void ospf6_set_checksum (void) { int offset = 12; #ifndef DISABLE_IPV6_CHECKSUM if (setsockopt (ospf6_sock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof (offset)) < 0) zlog_warn ("Network: set IPV6_CHECKSUM failed: %s", safe_strerror (errno)); #else zlog_warn ("Network: Don't set IPV6_CHECKSUM"); #endif /* DISABLE_IPV6_CHECKSUM */ } /* Make ospf6d's server socket. */ int ospf6_serv_sock (void) { if (ospf6d_privs.change (ZPRIVS_RAISE)) zlog_err ("ospf6_serv_sock: could not raise privs"); ospf6_sock = socket (AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf6_sock < 0) { zlog_warn ("Network: can't create OSPF6 socket."); if (ospf6d_privs.change (ZPRIVS_LOWER)) zlog_err ("ospf_sock_init: could not lower privs"); return -1; } if (ospf6d_privs.change (ZPRIVS_LOWER)) zlog_err ("ospf_sock_init: could not lower privs"); /* set socket options */ #if 1 sockopt_reuseaddr (ospf6_sock); #else ospf6_set_reuseaddr (); #endif /*1*/ ospf6_reset_mcastloop (); ospf6_set_pktinfo (); ospf6_set_transport_class (); ospf6_set_checksum (); /* setup global in6_addr, allspf6 and alldr6 for later use */ inet_pton (AF_INET6, ALLSPFROUTERS6, &allspfrouters6); inet_pton (AF_INET6, ALLDROUTERS6, &alldrouters6); return 0; } /* ospf6 set socket option */ void ospf6_sso (u_int ifindex, struct in6_addr *group, int option) { struct ipv6_mreq mreq6; int ret; assert (ifindex); mreq6.ipv6mr_interface = ifindex; memcpy (&mreq6.ipv6mr_multiaddr, group, sizeof (struct in6_addr)); ret = setsockopt (ospf6_sock, IPPROTO_IPV6, option, &mreq6, sizeof (mreq6)); if (ret < 0) zlog_err ("Network: setsockopt (%d) on ifindex %d failed: %s", option, ifindex, safe_strerror (errno)); } static int iov_count (struct iovec *iov) { int i; for (i = 0; iov[i].iov_base; i++) ; return i; } static int iov_totallen (struct iovec *iov) { int i; int totallen = 0; for (i = 0; iov[i].iov_base; i++) totallen += iov[i].iov_len; return totallen; } int ospf6_sendmsg (struct in6_addr *src, struct in6_addr *dst, unsigned int *ifindex, struct iovec *message) { int retval; struct msghdr smsghdr; struct cmsghdr *scmsgp; u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; struct in6_pktinfo *pktinfo; struct sockaddr_in6 dst_sin6; assert (dst); assert (*ifindex); scmsgp = (struct cmsghdr *)cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); memset (&dst_sin6, 0, sizeof (struct sockaddr_in6)); /* source address */ pktinfo->ipi6_ifindex = *ifindex; if (src) memcpy (&pktinfo->ipi6_addr, src, sizeof (struct in6_addr)); else memset (&pktinfo->ipi6_addr, 0, sizeof (struct in6_addr)); /* destination address */ dst_sin6.sin6_family = AF_INET6; #ifdef SIN6_LEN dst_sin6.sin6_len = sizeof (struct sockaddr_in6); #endif /*SIN6_LEN*/ memcpy (&dst_sin6.sin6_addr, dst, sizeof (struct in6_addr)); #ifdef HAVE_SIN6_SCOPE_ID dst_sin6.sin6_scope_id = *ifindex; #endif /* send control msg */ scmsgp->cmsg_level = IPPROTO_IPV6; scmsgp->cmsg_type = IPV6_PKTINFO; scmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); /* scmsgp = CMSG_NXTHDR (&smsghdr, scmsgp); */ /* send msg hdr */ memset (&smsghdr, 0, sizeof (smsghdr)); smsghdr.msg_iov = message; smsghdr.msg_iovlen = iov_count (message); smsghdr.msg_name = (caddr_t) &dst_sin6; smsghdr.msg_namelen = sizeof (struct sockaddr_in6); smsghdr.msg_control = (caddr_t) cmsgbuf; smsghdr.msg_controllen = scmsgp->cmsg_len; retval = sendmsg (ospf6_sock, &smsghdr, 0); if (retval != iov_totallen (message)) zlog_warn ("sendmsg failed: ifindex: %d: %s (%d)", *ifindex, safe_strerror (errno), errno); return retval; } int ospf6_recvmsg (struct in6_addr *src, struct in6_addr *dst, unsigned int *ifindex, struct iovec *message) { int retval; struct msghdr rmsghdr; struct cmsghdr *rcmsgp; u_char cmsgbuf[CMSG_SPACE(sizeof (struct in6_pktinfo))]; struct in6_pktinfo *pktinfo; struct sockaddr_in6 src_sin6; rcmsgp = (struct cmsghdr *)cmsgbuf; pktinfo = (struct in6_pktinfo *)(CMSG_DATA(rcmsgp)); memset (&src_sin6, 0, sizeof (struct sockaddr_in6)); /* receive control msg */ rcmsgp->cmsg_level = IPPROTO_IPV6; rcmsgp->cmsg_type = IPV6_PKTINFO; rcmsgp->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo)); /* rcmsgp = CMSG_NXTHDR (&rmsghdr, rcmsgp); */ /* receive msg hdr */ memset (&rmsghdr, 0, sizeof (rmsghdr)); rmsghdr.msg_iov = message; rmsghdr.msg_iovlen = iov_count (message); rmsghdr.msg_name = (caddr_t) &src_sin6; rmsghdr.msg_namelen = sizeof (struct sockaddr_in6); rmsghdr.msg_control = (caddr_t) cmsgbuf; rmsghdr.msg_controllen = sizeof (cmsgbuf); retval = recvmsg (ospf6_sock, &rmsghdr, 0); if (retval < 0) zlog_warn ("recvmsg failed: %s", safe_strerror (errno)); else if (retval == iov_totallen (message)) zlog_warn ("recvmsg read full buffer size: %d", retval); /* source address */ assert (src); memcpy (src, &src_sin6.sin6_addr, sizeof (struct in6_addr)); /* destination address */ if (ifindex) *ifindex = pktinfo->ipi6_ifindex; if (dst) memcpy (dst, &pktinfo->ipi6_addr, sizeof (struct in6_addr)); return retval; } quagga-0.99.24.1/ospf6d/README0000644000175000017500000000613412476520570012321 00000000000000 Zebra OSPF daemon for IPv6 network 2003/08/18 README for newer code is not yet. General usage should remain the same. For further usage, see command helps by typing '?' in vty, and then imagin ! ;p) Previous README contents follows. Zebra OSPF daemon for IPv6 network 2001/12/20 Zebra OSPF6d is OSPF version 3 daemon which is specified by "OSPF for IPv6" (RFC 2740). *** NOTE *** Zebra ospf6d is in development yet. It may lack some functionalities, and may have some bugs. Use the latest version from the anoncvs repository (http://www.zebra.org/cvs.html) ! This file README is like memo yet, so please feel free to ask by E-mail. Patches will be appriciated. ospf6d's vty port was default to 2606/tcp. Use commands below. VIEW NODE: show ipv6 ospf6 To see Router-ID, uptime of ospf6d, some statistics. show ipv6 ospf6 database ... This command shows LSA database. You can specify LS-type/LS-ID/Advertising-Router of LSAs. '*' is recognized. show ipv6 ospf6 interface ... To see the status of the OSPF interface, and the configuration like interface costs. show ipv6 ospf6 neighbor ... Shows state of neighbors and choosed (Backup) DR on the I/F. show ipv6 ospf6 route (X::X) This command shows internal routing table of the ospf6d. Routes not calculated by OSPFv3 (like connected routes) are not shown. If Address is specified (X::X), shows the route that the address matches. show ipv6 ospf6 route redistribute (X::X) Shows the routes advertised as AS-External routes by the router itself. If Address is specified (X::X), shows the route that the address matches. CONFIG NODE: interface NAME To enter INTERFACE NODE router ospf6 ... To enter OSPF6 NODE INTERFACE NODE: ipv6 ospf6 cost COST Sets the interface's output cost. Depends on interface bandwidth by default. ipv6 ospf6 hello-interval HELLOINTERVAL Sets the interface's Hello Interval. default 10 ipv6 ospf6 dead-interval DEADINTERVAL Sets the interface's Router Dead Interval. default 40 ipv6 ospf6 retransmit-interval RETRANSMITINTERVAL Sets the interface's Rxmt Interval. default 5 ipv6 ospf6 priority PRIORITY Sets the interface's Router Priority. default 1 ipv6 ospf6 transmit-delay TRANSMITDELAY Sets the interface's Inf-Trans-Delay. default 1 OSPF6 NODE: router-id A.B.C.D Sets the router's Router-ID interface NAME area AREA Binds interface to specified Area, and start sending OSPFv3 packets. auto-cost reference-bandwidth COST Sets the reference bandwidth for cost calculations, where this bandwidth is considered equivalent to an OSPF cost of 1, specified in Mbits/s. The default is 100Mbit/s (i.e. a link of bandwidth 100Mbit/s or higher will have a cost of 1. Cost of lower bandwidth links will be scaled with reference to this cost). This configuration setting MUST be consistent across all routers within the OSPF domain. Sample configuration is in ospf6d.conf.sample. -- Yasuhiro Ohara Kunihiro Ishiguro quagga-0.99.24.1/ospf6d/ospf6d.h0000644000175000017500000001160312476520570013010 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6D_H #define OSPF6D_H #define OSPF6_DAEMON_VERSION "0.9.7r" #include "libospf.h" #include "thread.h" /* global variables */ extern struct thread_master *master; /* Historical for KAME. */ #ifndef IPV6_JOIN_GROUP #ifdef IPV6_ADD_MEMBERSHIP #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif /* IPV6_ADD_MEMBERSHIP. */ #ifdef IPV6_JOIN_MEMBERSHIP #define IPV6_JOIN_GROUP IPV6_JOIN_MEMBERSHIP #endif /* IPV6_JOIN_MEMBERSHIP. */ #endif /* ! IPV6_JOIN_GROUP*/ #ifndef IPV6_LEAVE_GROUP #ifdef IPV6_DROP_MEMBERSHIP #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif /* IPV6_DROP_MEMBERSHIP */ #endif /* ! IPV6_LEAVE_GROUP */ #define MSG_OK 0 #define MSG_NG 1 /* cast macro: XXX - these *must* die, ick ick. */ #define OSPF6_PROCESS(x) ((struct ospf6 *) (x)) #define OSPF6_AREA(x) ((struct ospf6_area *) (x)) #define OSPF6_INTERFACE(x) ((struct ospf6_interface *) (x)) #define OSPF6_NEIGHBOR(x) ((struct ospf6_neighbor *) (x)) /* operation on timeval structure */ #ifndef timerclear #define timerclear(a) (a)->tv_sec = (tvp)->tv_usec = 0 #endif /*timerclear*/ #ifndef timersub #define timersub(a, b, res) \ do { \ (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((res)->tv_usec < 0) \ { \ (res)->tv_sec--; \ (res)->tv_usec += 1000000; \ } \ } while (0) #endif /*timersub*/ #define timerstring(tv, buf, size) \ do { \ if ((tv)->tv_sec / 60 / 60 / 24) \ snprintf (buf, size, "%ldd%02ld:%02ld:%02ld", \ (tv)->tv_sec / 60 / 60 / 24, \ (tv)->tv_sec / 60 / 60 % 24, \ (tv)->tv_sec / 60 % 60, \ (tv)->tv_sec % 60); \ else \ snprintf (buf, size, "%02ld:%02ld:%02ld", \ (tv)->tv_sec / 60 / 60 % 24, \ (tv)->tv_sec / 60 % 60, \ (tv)->tv_sec % 60); \ } while (0) #define timerstring_local(tv, buf, size) \ do { \ int ret; \ struct tm *tm; \ tm = localtime (&(tv)->tv_sec); \ ret = strftime (buf, size, "%Y/%m/%d %H:%M:%S", tm); \ if (ret == 0) \ zlog_warn ("strftime error"); \ } while (0) #define threadtimer_string(now, t, buf, size) \ do { \ struct timeval result; \ if (!t) \ snprintf(buf, size, "inactive"); \ else { \ timersub(&t->u.sands, &now, &result); \ timerstring(&result, buf, size); \ } \ } while (0) /* for commands */ #define OSPF6_AREA_STR "Area information\n" #define OSPF6_AREA_ID_STR "Area ID (as an IPv4 notation)\n" #define OSPF6_SPF_STR "Shortest Path First tree information\n" #define OSPF6_ROUTER_ID_STR "Specify Router-ID\n" #define OSPF6_LS_ID_STR "Specify Link State ID\n" #define VNL VTY_NEWLINE #define OSPF6_CMD_CHECK_RUNNING() \ if (ospf6 == NULL) \ { \ vty_out (vty, "OSPFv3 is not running%s", VTY_NEWLINE); \ return CMD_SUCCESS; \ } /* Function Prototypes */ extern struct route_node *route_prev (struct route_node *node); extern void ospf6_debug (void); extern void ospf6_init (void); #endif /* OSPF6D_H */ quagga-0.99.24.1/ospf6d/ospf6_snmp.h0000644000175000017500000000206412476520570013702 00000000000000/* OSPFv3 SNMP support * Copyright (C) 2004 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_SNMP_H #define OSPF6_SNMP_H extern void ospf6TrapNbrStateChange (struct ospf6_neighbor *); extern void ospf6TrapIfStateChange (struct ospf6_interface *); extern void ospf6_snmp_init (struct thread_master *); #endif /*OSPF6_SNMP_H*/ quagga-0.99.24.1/ospf6d/ospf6_abr.h0000644000175000017500000000505712476520570013476 00000000000000/* * Copyright (C) 2004 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_ABR_H #define OSPF6_ABR_H /* for struct ospf6_route */ #include "ospf6_route.h" /* for struct ospf6_prefix */ #include "ospf6_proto.h" /* Debug option */ extern unsigned char conf_debug_ospf6_abr; #define OSPF6_DEBUG_ABR_ON() \ (conf_debug_ospf6_abr = 1) #define OSPF6_DEBUG_ABR_OFF() \ (conf_debug_ospf6_abr = 0) #define IS_OSPF6_DEBUG_ABR \ (conf_debug_ospf6_abr) /* Inter-Area-Prefix-LSA */ #define OSPF6_INTER_PREFIX_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ struct ospf6_inter_prefix_lsa { u_int32_t metric; struct ospf6_prefix prefix; }; /* Inter-Area-Router-LSA */ #define OSPF6_INTER_ROUTER_LSA_FIX_SIZE 12U struct ospf6_inter_router_lsa { u_char mbz; u_char options[3]; u_int32_t metric; u_int32_t router_id; }; #define OSPF6_ABR_SUMMARY_METRIC(E) (ntohl ((E)->metric & htonl (0x00ffffff))) #define OSPF6_ABR_SUMMARY_METRIC_SET(E,C) \ { (E)->metric &= htonl (0x00000000); \ (E)->metric |= htonl (0x00ffffff) & htonl (C); } extern int ospf6_is_router_abr (struct ospf6 *o); extern void ospf6_abr_enable_area (struct ospf6_area *oa); extern void ospf6_abr_disable_area (struct ospf6_area *oa); extern void ospf6_abr_originate_summary_to_area (struct ospf6_route *route, struct ospf6_area *area); extern void ospf6_abr_originate_summary (struct ospf6_route *route); extern void ospf6_abr_examin_summary (struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_abr_examin_brouter (u_int32_t router_id); extern void ospf6_abr_reimport (struct ospf6_area *oa); extern int config_write_ospf6_debug_abr (struct vty *vty); extern void install_element_ospf6_debug_abr (void); extern int ospf6_abr_config_write (struct vty *vty); extern void ospf6_abr_init (void); #endif /*OSPF6_ABR_H*/ quagga-0.99.24.1/ospf6d/ospf6_asbr.h0000644000175000017500000000615112476520570013655 00000000000000/* * Copyright (C) 2001 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_ASBR_H #define OSPF6_ASBR_H /* for struct ospf6_prefix */ #include "ospf6_proto.h" /* for struct ospf6_lsa */ #include "ospf6_lsa.h" /* for struct ospf6_route */ #include "ospf6_route.h" /* Debug option */ extern unsigned char conf_debug_ospf6_asbr; #define OSPF6_DEBUG_ASBR_ON() \ (conf_debug_ospf6_asbr = 1) #define OSPF6_DEBUG_ASBR_OFF() \ (conf_debug_ospf6_asbr = 0) #define IS_OSPF6_DEBUG_ASBR \ (conf_debug_ospf6_asbr) struct ospf6_external_info { /* External route type */ int type; /* Originating Link State ID */ u_int32_t id; struct in6_addr forwarding; /* u_int32_t tag; */ unsigned int ifindex; }; /* AS-External-LSA */ #define OSPF6_AS_EXTERNAL_LSA_MIN_SIZE 4U /* w/o IPv6 prefix */ struct ospf6_as_external_lsa { u_int32_t bits_metric; struct ospf6_prefix prefix; /* followed by none or one forwarding address */ /* followed by none or one external route tag */ /* followed by none or one referenced LS-ID */ }; #define OSPF6_ASBR_BIT_T ntohl (0x01000000) #define OSPF6_ASBR_BIT_F ntohl (0x02000000) #define OSPF6_ASBR_BIT_E ntohl (0x04000000) #define OSPF6_ASBR_METRIC(E) (ntohl ((E)->bits_metric & htonl (0x00ffffff))) #define OSPF6_ASBR_METRIC_SET(E,C) \ { (E)->bits_metric &= htonl (0xff000000); \ (E)->bits_metric |= htonl (0x00ffffff) & htonl (C); } extern void ospf6_asbr_lsa_add (struct ospf6_lsa *lsa); extern void ospf6_asbr_lsa_remove (struct ospf6_lsa *lsa); extern void ospf6_asbr_lsentry_add (struct ospf6_route *asbr_entry); extern void ospf6_asbr_lsentry_remove (struct ospf6_route *asbr_entry); extern int ospf6_asbr_is_asbr (struct ospf6 *o); extern void ospf6_asbr_redistribute_add (int type, int ifindex, struct prefix *prefix, u_int nexthop_num, struct in6_addr *nexthop); extern void ospf6_asbr_redistribute_remove (int type, int ifindex, struct prefix *prefix); extern int ospf6_redistribute_config_write (struct vty *vty); extern void ospf6_asbr_init (void); extern void ospf6_asbr_redistribute_reset (void); extern void ospf6_asbr_terminate (void); extern int config_write_ospf6_debug_asbr (struct vty *vty); extern void install_element_ospf6_debug_asbr (void); #endif /* OSPF6_ASBR_H */ quagga-0.99.24.1/ospf6d/ospf6_proto.h0000644000175000017500000000741112476520570014071 00000000000000/* * Common protocol data and data structures. * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_PROTO_H #define OSPF6_PROTO_H /* OSPF protocol version */ #define OSPFV3_VERSION 3 /* TOS field normaly null */ #define DEFAULT_TOS_VALUE 0x0 #define ALLSPFROUTERS6 "ff02::5" #define ALLDROUTERS6 "ff02::6" #define OSPF6_ROUTER_BIT_W (1 << 3) #define OSPF6_ROUTER_BIT_V (1 << 2) #define OSPF6_ROUTER_BIT_E (1 << 1) #define OSPF6_ROUTER_BIT_B (1 << 0) /* OSPF options */ /* present in HELLO, DD, LSA */ #define OSPF6_OPT_SET(x,opt) ((x)[2] |= (opt)) #define OSPF6_OPT_ISSET(x,opt) ((x)[2] & (opt)) #define OSPF6_OPT_CLEAR(x,opt) ((x)[2] &= ~(opt)) #define OSPF6_OPT_CLEAR_ALL(x) ((x)[0] = (x)[1] = (x)[2] = 0) #define OSPF6_OPT_DC (1 << 5) /* Demand Circuit handling Capability */ #define OSPF6_OPT_R (1 << 4) /* Forwarding Capability (Any Protocol) */ #define OSPF6_OPT_N (1 << 3) /* Handling Type-7 LSA Capability */ #define OSPF6_OPT_MC (1 << 2) /* Multicasting Capability */ #define OSPF6_OPT_E (1 << 1) /* AS External Capability */ #define OSPF6_OPT_V6 (1 << 0) /* IPv6 forwarding Capability */ /* OSPF6 Prefix */ #define OSPF6_PREFIX_MIN_SIZE 4U /* .length == 0 */ struct ospf6_prefix { u_int8_t prefix_length; u_int8_t prefix_options; union { u_int16_t _prefix_metric; u_int16_t _prefix_referenced_lstype; } u; #define prefix_metric u._prefix_metric #define prefix_refer_lstype u._prefix_referenced_lstype /* followed by one address_prefix */ }; #define OSPF6_PREFIX_OPTION_NU (1 << 0) /* No Unicast */ #define OSPF6_PREFIX_OPTION_LA (1 << 1) /* Local Address */ #define OSPF6_PREFIX_OPTION_MC (1 << 2) /* MultiCast */ #define OSPF6_PREFIX_OPTION_P (1 << 3) /* Propagate (NSSA) */ /* caddr_t OSPF6_PREFIX_BODY (struct ospf6_prefix *); */ #define OSPF6_PREFIX_BODY(x) ((caddr_t)(x) + sizeof (struct ospf6_prefix)) /* size_t OSPF6_PREFIX_SPACE (int prefixlength); */ #define OSPF6_PREFIX_SPACE(x) ((((x) + 31) / 32) * 4) /* size_t OSPF6_PREFIX_SIZE (struct ospf6_prefix *); */ #define OSPF6_PREFIX_SIZE(x) \ (OSPF6_PREFIX_SPACE ((x)->prefix_length) + sizeof (struct ospf6_prefix)) /* struct ospf6_prefix *OSPF6_PREFIX_NEXT (struct ospf6_prefix *); */ #define OSPF6_PREFIX_NEXT(x) \ ((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE (x))) #define ospf6_prefix_in6_addr(in6, op) \ do { \ memset (in6, 0, sizeof (struct in6_addr)); \ memcpy (in6, (caddr_t) (op) + sizeof (struct ospf6_prefix), \ OSPF6_PREFIX_SPACE ((op)->prefix_length)); \ } while (0) extern void ospf6_prefix_apply_mask (struct ospf6_prefix *op); extern void ospf6_prefix_options_printbuf (u_int8_t prefix_options, char *buf, int size); extern void ospf6_capability_printbuf (char capability, char *buf, int size); extern void ospf6_options_printbuf (u_char *options, char *buf, int size); #endif /* OSPF6_PROTO_H */ quagga-0.99.24.1/ospf6d/ospf6_spf.h0000644000175000017500000001074612476520570013523 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_SPF_H #define OSPF6_SPF_H #include "ospf6_top.h" /* Debug option */ extern unsigned char conf_debug_ospf6_spf; #define OSPF6_DEBUG_SPF_PROCESS 0x01 #define OSPF6_DEBUG_SPF_TIME 0x02 #define OSPF6_DEBUG_SPF_DATABASE 0x04 #define OSPF6_DEBUG_SPF_ON(level) \ (conf_debug_ospf6_spf |= (level)) #define OSPF6_DEBUG_SPF_OFF(level) \ (conf_debug_ospf6_spf &= ~(level)) #define IS_OSPF6_DEBUG_SPF(level) \ (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_ ## level) /* Transit Vertex */ struct ospf6_vertex { /* type of this vertex */ u_int8_t type; /* Vertex Identifier */ struct prefix vertex_id; /* Identifier String */ char name[128]; /* Associated Area */ struct ospf6_area *area; /* Associated LSA */ struct ospf6_lsa *lsa; /* Distance from Root (i.e. Cost) */ u_int32_t cost; /* Router hops to this node */ u_char hops; /* nexthops to this node */ struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; /* capability bits */ u_char capability; /* Optional capabilities */ u_char options[3]; /* For tree display */ struct ospf6_vertex *parent; struct list *child_list; }; #define OSPF6_VERTEX_TYPE_ROUTER 0x01 #define OSPF6_VERTEX_TYPE_NETWORK 0x02 #define VERTEX_IS_TYPE(t, v) \ ((v)->type == OSPF6_VERTEX_TYPE_ ## t ? 1 : 0) /* What triggered the SPF? */ #define OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED (1 << 0) #define OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED (1 << 1) #define OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED (1 << 2) #define OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED (1 << 3) #define OSPF6_SPF_FLAGS_LINK_LSA_ADDED (1 << 4) #define OSPF6_SPF_FLAGS_LINK_LSA_REMOVED (1 << 5) #define OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED (1 << 6) #define OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED (1 << 7) static inline void ospf6_set_spf_reason (struct ospf6* ospf, unsigned int reason) { ospf->spf_reason |= reason; } static inline void ospf6_reset_spf_reason (struct ospf6 *ospf) { ospf->spf_reason = 0; } static inline unsigned int ospf6_lsadd_to_spf_reason (struct ospf6_lsa *lsa) { unsigned int reason = 0; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: reason = OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED; break; case OSPF6_LSTYPE_NETWORK: reason = OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED; break; case OSPF6_LSTYPE_LINK: reason = OSPF6_SPF_FLAGS_LINK_LSA_ADDED; break; default: break; } return (reason); } static inline unsigned int ospf6_lsremove_to_spf_reason (struct ospf6_lsa *lsa) { unsigned int reason = 0; switch (ntohs (lsa->header->type)) { case OSPF6_LSTYPE_ROUTER: reason = OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED; break; case OSPF6_LSTYPE_NETWORK: reason = OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED; break; case OSPF6_LSTYPE_LINK: reason = OSPF6_SPF_FLAGS_LINK_LSA_REMOVED; break; default: break; } return (reason); } extern void ospf6_spf_table_finish (struct ospf6_route_table *result_table); extern void ospf6_spf_calculation (u_int32_t router_id, struct ospf6_route_table *result_table, struct ospf6_area *oa); extern void ospf6_spf_schedule (struct ospf6 *ospf, unsigned int reason); extern void ospf6_spf_display_subtree (struct vty *vty, const char *prefix, int rest, struct ospf6_vertex *v); extern void ospf6_spf_config_write (struct vty *vty); extern int config_write_ospf6_debug_spf (struct vty *vty); extern void install_element_ospf6_debug_spf (void); extern void ospf6_spf_init (void); extern void ospf6_spf_reason_string (unsigned int reason, char *buf, int size); #endif /* OSPF6_SPF_H */ quagga-0.99.24.1/ospf6d/ospf6_zebra.h0000644000175000017500000000334612476520570014034 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_ZEBRA_H #define OSPF6_ZEBRA_H #include "zclient.h" /* Debug option */ extern unsigned char conf_debug_ospf6_zebra; #define OSPF6_DEBUG_ZEBRA_SEND 0x01 #define OSPF6_DEBUG_ZEBRA_RECV 0x02 #define OSPF6_DEBUG_ZEBRA_ON(level) \ (conf_debug_ospf6_zebra |= level) #define OSPF6_DEBUG_ZEBRA_OFF(level) \ (conf_debug_ospf6_zebra &= ~(level)) #define IS_OSPF6_DEBUG_ZEBRA(e) \ (conf_debug_ospf6_zebra & OSPF6_DEBUG_ZEBRA_ ## e) extern struct zclient *zclient; extern void ospf6_zebra_route_update_add (struct ospf6_route *request); extern void ospf6_zebra_route_update_remove (struct ospf6_route *request); extern void ospf6_zebra_redistribute (int); extern void ospf6_zebra_no_redistribute (int); #define ospf6_zebra_is_redistribute(type) (zclient->redist[type]) extern void ospf6_zebra_init (void); extern int config_write_ospf6_debug_zebra (struct vty *vty); extern void install_element_ospf6_debug_zebra (void); #endif /*OSPF6_ZEBRA_H*/ quagga-0.99.24.1/ospf6d/ospf6_intra.h0000644000175000017500000002133412476520570014043 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_INTRA_H #define OSPF6_INTRA_H /* Debug option */ extern unsigned char conf_debug_ospf6_brouter; extern u_int32_t conf_debug_ospf6_brouter_specific_router_id; extern u_int32_t conf_debug_ospf6_brouter_specific_area_id; #define OSPF6_DEBUG_BROUTER_SUMMARY 0x01 #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER 0x02 #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA 0x04 #define OSPF6_DEBUG_BROUTER_ON() \ (conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SUMMARY) #define OSPF6_DEBUG_BROUTER_OFF() \ (conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SUMMARY) #define IS_OSPF6_DEBUG_BROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SUMMARY) #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ON(router_id) \ do { \ conf_debug_ospf6_brouter_specific_router_id = (router_id); \ conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) #define OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF() \ do { \ conf_debug_ospf6_brouter_specific_router_id = 0; \ conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER; \ } while (0) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(router_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER && \ conf_debug_ospf6_brouter_specific_router_id == (router_id)) #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ON(area_id) \ do { \ conf_debug_ospf6_brouter_specific_area_id = (area_id); \ conf_debug_ospf6_brouter |= OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) #define OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF() \ do { \ conf_debug_ospf6_brouter_specific_area_id = 0; \ conf_debug_ospf6_brouter &= ~OSPF6_DEBUG_BROUTER_SPECIFIC_AREA; \ } while (0) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA \ (conf_debug_ospf6_brouter & OSPF6_DEBUG_BROUTER_SPECIFIC_AREA) #define IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(area_id) \ (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA && \ conf_debug_ospf6_brouter_specific_area_id == (area_id)) /* Router-LSA */ #define OSPF6_ROUTER_LSA_MIN_SIZE 4U struct ospf6_router_lsa { u_char bits; u_char options[3]; /* followed by ospf6_router_lsdesc(s) */ }; /* Link State Description in Router-LSA */ #define OSPF6_ROUTER_LSDESC_FIX_SIZE 16U struct ospf6_router_lsdesc { u_char type; u_char reserved; u_int16_t metric; /* output cost */ u_int32_t interface_id; u_int32_t neighbor_interface_id; u_int32_t neighbor_router_id; }; #define OSPF6_ROUTER_LSDESC_POINTTOPOINT 1 #define OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK 2 #define OSPF6_ROUTER_LSDESC_STUB_NETWORK 3 #define OSPF6_ROUTER_LSDESC_VIRTUAL_LINK 4 enum stub_router_mode { OSPF6_NOT_STUB_ROUTER, OSPF6_IS_STUB_ROUTER, OSPF6_IS_STUB_ROUTER_V6, }; #define ROUTER_LSDESC_IS_TYPE(t,x) \ ((((struct ospf6_router_lsdesc *)(x))->type == \ OSPF6_ROUTER_LSDESC_ ## t) ? 1 : 0) #define ROUTER_LSDESC_GET_METRIC(x) \ (ntohs (((struct ospf6_router_lsdesc *)(x))->metric)) #define ROUTER_LSDESC_GET_IFID(x) \ (ntohl (((struct ospf6_router_lsdesc *)(x))->interface_id)) #define ROUTER_LSDESC_GET_NBR_IFID(x) \ (ntohl (((struct ospf6_router_lsdesc *)(x))->neighbor_interface_id)) #define ROUTER_LSDESC_GET_NBR_ROUTERID(x) \ (((struct ospf6_router_lsdesc *)(x))->neighbor_router_id) /* Network-LSA */ #define OSPF6_NETWORK_LSA_MIN_SIZE 4U struct ospf6_network_lsa { u_char reserved; u_char options[3]; /* followed by ospf6_netowrk_lsd(s) */ }; /* Link State Description in Router-LSA */ #define OSPF6_NETWORK_LSDESC_FIX_SIZE 4U struct ospf6_network_lsdesc { u_int32_t router_id; }; #define NETWORK_LSDESC_GET_NBR_ROUTERID(x) \ (((struct ospf6_network_lsdesc *)(x))->router_id) /* Link-LSA */ #define OSPF6_LINK_LSA_MIN_SIZE 24U /* w/o 1st IPv6 prefix */ struct ospf6_link_lsa { u_char priority; u_char options[3]; struct in6_addr linklocal_addr; u_int32_t prefix_num; /* followed by ospf6 prefix(es) */ }; /* Intra-Area-Prefix-LSA */ #define OSPF6_INTRA_PREFIX_LSA_MIN_SIZE 12U /* w/o 1st IPv6 prefix */ struct ospf6_intra_prefix_lsa { u_int16_t prefix_num; u_int16_t ref_type; u_int32_t ref_id; u_int32_t ref_adv_router; /* followed by ospf6 prefix(es) */ }; #define OSPF6_ROUTER_LSA_SCHEDULE(oa) \ do { \ if (! (oa)->thread_router_lsa \ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (oa)->thread_router_lsa = \ thread_add_event (master, ospf6_router_lsa_originate, oa, 0); \ } while (0) #define OSPF6_NETWORK_LSA_SCHEDULE(oi) \ do { \ if (! (oi)->thread_network_lsa \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_network_lsa = \ thread_add_event (master, ospf6_network_lsa_originate, oi, 0); \ } while (0) #define OSPF6_LINK_LSA_SCHEDULE(oi) \ do { \ if (! (oi)->thread_link_lsa \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_link_lsa = \ thread_add_event (master, ospf6_link_lsa_originate, oi, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_STUB(oa) \ do { \ if (! (oa)->thread_intra_prefix_lsa \ && CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE)) \ (oa)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_stub, \ oa, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_SCHEDULE_TRANSIT(oi) \ do { \ if (! (oi)->thread_intra_prefix_lsa \ && ! CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE)) \ (oi)->thread_intra_prefix_lsa = \ thread_add_event (master, ospf6_intra_prefix_lsa_originate_transit, \ oi, 0); \ } while (0) #define OSPF6_NETWORK_LSA_EXECUTE(oi) \ do { \ THREAD_OFF ((oi)->thread_network_lsa); \ thread_execute (master, ospf6_network_lsa_originate, oi, 0); \ } while (0) #define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi) \ do { \ THREAD_OFF ((oi)->thread_intra_prefix_lsa); \ thread_execute (master, ospf6_intra_prefix_lsa_originate_transit, oi, 0); \ } while (0) /* Function Prototypes */ extern char *ospf6_router_lsdesc_lookup (u_char type, u_int32_t interface_id, u_int32_t neighbor_interface_id, u_int32_t neighbor_router_id, struct ospf6_lsa *lsa); extern char *ospf6_network_lsdesc_lookup (u_int32_t router_id, struct ospf6_lsa *lsa); extern int ospf6_router_is_stub_router (struct ospf6_lsa *lsa); extern int ospf6_router_lsa_originate (struct thread *); extern int ospf6_network_lsa_originate (struct thread *); extern int ospf6_link_lsa_originate (struct thread *); extern int ospf6_intra_prefix_lsa_originate_transit (struct thread *); extern int ospf6_intra_prefix_lsa_originate_stub (struct thread *); extern void ospf6_intra_prefix_lsa_add (struct ospf6_lsa *lsa); extern void ospf6_intra_prefix_lsa_remove (struct ospf6_lsa *lsa); extern void ospf6_intra_route_calculation (struct ospf6_area *oa); extern void ospf6_intra_brouter_calculation (struct ospf6_area *oa); extern void ospf6_intra_init (void); extern int config_write_ospf6_debug_brouter (struct vty *vty); extern void install_element_ospf6_debug_brouter (void); #endif /* OSPF6_LSA_H */ quagga-0.99.24.1/ospf6d/ospf6_route.h0000644000175000017500000002532012476520570014063 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_ROUTE_H #define OSPF6_ROUTE_H #define OSPF6_MULTI_PATH_LIMIT 4 /* Debug option */ extern unsigned char conf_debug_ospf6_route; #define OSPF6_DEBUG_ROUTE_TABLE 0x01 #define OSPF6_DEBUG_ROUTE_INTRA 0x02 #define OSPF6_DEBUG_ROUTE_INTER 0x04 #define OSPF6_DEBUG_ROUTE_MEMORY 0x80 #define OSPF6_DEBUG_ROUTE_ON(level) \ (conf_debug_ospf6_route |= (level)) #define OSPF6_DEBUG_ROUTE_OFF(level) \ (conf_debug_ospf6_route &= ~(level)) #define IS_OSPF6_DEBUG_ROUTE(e) \ (conf_debug_ospf6_route & OSPF6_DEBUG_ROUTE_ ## e) /* Nexthop */ struct ospf6_nexthop { /* Interface index */ unsigned int ifindex; /* IP address, if any */ struct in6_addr address; }; #define ospf6_nexthop_is_set(x) \ ((x)->ifindex || ! IN6_IS_ADDR_UNSPECIFIED (&(x)->address)) #define ospf6_nexthop_is_same(a,b) \ ((a)->ifindex == (b)->ifindex && \ IN6_ARE_ADDR_EQUAL (&(a)->address, &(b)->address)) #define ospf6_nexthop_clear(x) \ do { \ (x)->ifindex = 0; \ memset (&(x)->address, 0, sizeof (struct in6_addr)); \ } while (0) #define ospf6_nexthop_copy(a, b) \ do { \ (a)->ifindex = (b)->ifindex; \ memcpy (&(a)->address, &(b)->address, \ sizeof (struct in6_addr)); \ } while (0) /* Path */ struct ospf6_ls_origin { u_int16_t type; u_int32_t id; u_int32_t adv_router; }; struct ospf6_path { /* Link State Origin */ struct ospf6_ls_origin origin; /* Router bits */ u_char router_bits; /* Optional Capabilities */ u_char options[3]; /* Prefix Options */ u_char prefix_options; /* Associated Area */ u_int32_t area_id; /* Path-type */ u_char type; u_char subtype; /* only used for redistribute i.e ZEBRA_ROUTE_XXX */ /* Cost */ u_int8_t metric_type; u_int32_t cost; u_int32_t cost_e2; }; #define OSPF6_PATH_TYPE_NONE 0 #define OSPF6_PATH_TYPE_INTRA 1 #define OSPF6_PATH_TYPE_INTER 2 #define OSPF6_PATH_TYPE_EXTERNAL1 3 #define OSPF6_PATH_TYPE_EXTERNAL2 4 #define OSPF6_PATH_TYPE_REDISTRIBUTE 5 #define OSPF6_PATH_TYPE_MAX 6 #include "prefix.h" #include "table.h" struct ospf6_route { struct route_node *rnode; struct ospf6_route_table *table; struct ospf6_route *prev; struct ospf6_route *next; unsigned int lock; /* Destination Type */ u_char type; /* XXX: It would likely be better to use separate struct in_addr's * for the advertising router-ID and prefix IDs, instead of stuffing them * into one. See also XXX below. */ /* Destination ID */ struct prefix prefix; /* Time */ struct timeval installed; struct timeval changed; /* flag */ u_char flag; /* path */ struct ospf6_path path; /* nexthop */ struct ospf6_nexthop nexthop[OSPF6_MULTI_PATH_LIMIT]; /* route option */ void *route_option; /* link state id for advertising */ u_int32_t linkstate_id; }; #define OSPF6_DEST_TYPE_NONE 0 #define OSPF6_DEST_TYPE_ROUTER 1 #define OSPF6_DEST_TYPE_NETWORK 2 #define OSPF6_DEST_TYPE_DISCARD 3 #define OSPF6_DEST_TYPE_LINKSTATE 4 #define OSPF6_DEST_TYPE_RANGE 5 #define OSPF6_DEST_TYPE_MAX 6 #define OSPF6_ROUTE_CHANGE 0x01 #define OSPF6_ROUTE_ADD 0x02 #define OSPF6_ROUTE_REMOVE 0x04 #define OSPF6_ROUTE_BEST 0x08 #define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10 #define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20 #define OSPF6_ROUTE_WAS_REMOVED 0x40 struct ospf6_route_table { int scope_type; int table_type; void *scope; /* patricia tree */ struct route_table *table; u_int32_t count; /* hooks */ void (*hook_add) (struct ospf6_route *); void (*hook_change) (struct ospf6_route *); void (*hook_remove) (struct ospf6_route *); }; #define OSPF6_SCOPE_TYPE_NONE 0 #define OSPF6_SCOPE_TYPE_GLOBAL 1 #define OSPF6_SCOPE_TYPE_AREA 2 #define OSPF6_SCOPE_TYPE_INTERFACE 3 #define OSPF6_TABLE_TYPE_NONE 0 #define OSPF6_TABLE_TYPE_ROUTES 1 #define OSPF6_TABLE_TYPE_BORDER_ROUTERS 2 #define OSPF6_TABLE_TYPE_CONNECTED_ROUTES 3 #define OSPF6_TABLE_TYPE_EXTERNAL_ROUTES 4 #define OSPF6_TABLE_TYPE_SPF_RESULTS 5 #define OSPF6_TABLE_TYPE_PREFIX_RANGES 6 #define OSPF6_TABLE_TYPE_SUMMARY_PREFIXES 7 #define OSPF6_TABLE_TYPE_SUMMARY_ROUTERS 8 #define OSPF6_ROUTE_TABLE_CREATE(s, t) \ ospf6_route_table_create (OSPF6_SCOPE_TYPE_ ## s, \ OSPF6_TABLE_TYPE_ ## t) extern const char *ospf6_dest_type_str[OSPF6_DEST_TYPE_MAX]; extern const char *ospf6_dest_type_substr[OSPF6_DEST_TYPE_MAX]; #define OSPF6_DEST_TYPE_NAME(x) \ (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? \ ospf6_dest_type_str[(x)] : ospf6_dest_type_str[0]) #define OSPF6_DEST_TYPE_SUBSTR(x) \ (0 < (x) && (x) < OSPF6_DEST_TYPE_MAX ? \ ospf6_dest_type_substr[(x)] : ospf6_dest_type_substr[0]) extern const char *ospf6_path_type_str[OSPF6_PATH_TYPE_MAX]; extern const char *ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; #define OSPF6_PATH_TYPE_NAME(x) \ (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ? \ ospf6_path_type_str[(x)] : ospf6_path_type_str[0]) #define OSPF6_PATH_TYPE_SUBSTR(x) \ (0 < (x) && (x) < OSPF6_PATH_TYPE_MAX ? \ ospf6_path_type_substr[(x)] : ospf6_path_type_substr[0]) #define OSPF6_ROUTE_ADDRESS_STR "Display the route bestmatches the address\n" #define OSPF6_ROUTE_PREFIX_STR "Display the route\n" #define OSPF6_ROUTE_MATCH_STR "Display the route matches the prefix\n" #define ospf6_route_is_prefix(p, r) \ (memcmp (p, &(r)->prefix, sizeof (struct prefix)) == 0) #define ospf6_route_is_same(ra, rb) \ (prefix_same (&(ra)->prefix, &(rb)->prefix)) #define ospf6_route_is_same_origin(ra, rb) \ ((ra)->path.area_id == (rb)->path.area_id && \ memcmp (&(ra)->path.origin, &(rb)->path.origin, \ sizeof (struct ospf6_ls_origin)) == 0) #define ospf6_route_is_identical(ra, rb) \ ((ra)->type == (rb)->type && \ memcmp (&(ra)->prefix, &(rb)->prefix, sizeof (struct prefix)) == 0 && \ memcmp (&(ra)->path, &(rb)->path, sizeof (struct ospf6_path)) == 0 && \ memcmp (&(ra)->nexthop, &(rb)->nexthop, \ sizeof (struct ospf6_nexthop) * OSPF6_MULTI_PATH_LIMIT) == 0) #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) /* XXX: This gives GCC heartburn aboutbreaking aliasing rules. */ #define ospf6_linkstate_prefix_adv_router(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) #define ospf6_linkstate_prefix_id(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) #define ADV_ROUTER_IN_PREFIX(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[0])) #define ID_IN_PREFIX(x) \ (*(u_int32_t *)(&(x)->u.prefix6.s6_addr[4])) /* Function prototype */ extern void ospf6_linkstate_prefix (u_int32_t adv_router, u_int32_t id, struct prefix *prefix); extern void ospf6_linkstate_prefix2str (struct prefix *prefix, char *buf, int size); extern struct ospf6_route *ospf6_route_create (void); extern void ospf6_route_delete (struct ospf6_route *); extern struct ospf6_route *ospf6_route_copy (struct ospf6_route *route); extern void ospf6_route_lock (struct ospf6_route *route); extern void ospf6_route_unlock (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_lookup (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_lookup_identical (struct ospf6_route *route, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_lookup_bestmatch (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_add (struct ospf6_route *route, struct ospf6_route_table *table); extern void ospf6_route_remove (struct ospf6_route *route, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_head (struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_next (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_best_next (struct ospf6_route *route); extern struct ospf6_route *ospf6_route_match_head (struct prefix *prefix, struct ospf6_route_table *table); extern struct ospf6_route *ospf6_route_match_next (struct prefix *prefix, struct ospf6_route *route); extern void ospf6_route_remove_all (struct ospf6_route_table *); extern struct ospf6_route_table *ospf6_route_table_create (int s, int t); extern void ospf6_route_table_delete (struct ospf6_route_table *); extern void ospf6_route_dump (struct ospf6_route_table *table); extern void ospf6_route_show (struct vty *vty, struct ospf6_route *route); extern void ospf6_route_show_detail (struct vty *vty, struct ospf6_route *route); extern int ospf6_route_table_show (struct vty *, int, const char *[], struct ospf6_route_table *); extern int ospf6_linkstate_table_show (struct vty *vty, int argc, const char *argv[], struct ospf6_route_table *table); extern void ospf6_brouter_show_header (struct vty *vty); extern void ospf6_brouter_show (struct vty *vty, struct ospf6_route *route); extern int config_write_ospf6_debug_route (struct vty *vty); extern void install_element_ospf6_debug_route (void); extern void ospf6_route_init (void); extern void ospf6_clean (void); #endif /* OSPF6_ROUTE_H */ quagga-0.99.24.1/ospf6d/ospf6_flood.h0000644000175000017500000000472612476520570014037 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_FLOOD_H #define OSPF6_FLOOD_H /* Debug option */ extern unsigned char conf_debug_ospf6_flooding; #define OSPF6_DEBUG_FLOODING_ON() \ (conf_debug_ospf6_flooding = 1) #define OSPF6_DEBUG_FLOODING_OFF() \ (conf_debug_ospf6_flooding = 0) #define IS_OSPF6_DEBUG_FLOODING \ (conf_debug_ospf6_flooding) /* Function Prototypes */ extern struct ospf6_lsdb *ospf6_get_scoped_lsdb (struct ospf6_lsa *lsa); extern struct ospf6_lsdb *ospf6_get_scoped_lsdb_self (struct ospf6_lsa *lsa); /* origination & purging */ extern void ospf6_lsa_originate (struct ospf6_lsa *lsa); extern void ospf6_lsa_originate_process (struct ospf6_lsa *lsa, struct ospf6 *process); extern void ospf6_lsa_originate_area (struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_lsa_originate_interface (struct ospf6_lsa *lsa, struct ospf6_interface *oi); extern void ospf6_lsa_purge (struct ospf6_lsa *lsa); /* access method to retrans_count */ extern void ospf6_increment_retrans_count (struct ospf6_lsa *lsa); extern void ospf6_decrement_retrans_count (struct ospf6_lsa *lsa); /* flooding & clear flooding */ extern void ospf6_flood_clear (struct ospf6_lsa *lsa); extern void ospf6_flood (struct ospf6_neighbor *from, struct ospf6_lsa *lsa); /* receive & install */ extern void ospf6_receive_lsa (struct ospf6_neighbor *from, struct ospf6_lsa_header *header); extern void ospf6_install_lsa (struct ospf6_lsa *lsa); extern int config_write_ospf6_debug_flood (struct vty *vty); extern void install_element_ospf6_debug_flood (void); #endif /* OSPF6_FLOOD_H */ quagga-0.99.24.1/ospf6d/ospf6_neighbor.h0000644000175000017500000001147612476520570014531 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_NEIGHBOR_H #define OSPF6_NEIGHBOR_H /* Debug option */ extern unsigned char conf_debug_ospf6_neighbor; #define OSPF6_DEBUG_NEIGHBOR_STATE 0x01 #define OSPF6_DEBUG_NEIGHBOR_EVENT 0x02 #define OSPF6_DEBUG_NEIGHBOR_ON(level) \ (conf_debug_ospf6_neighbor |= (level)) #define OSPF6_DEBUG_NEIGHBOR_OFF(level) \ (conf_debug_ospf6_neighbor &= ~(level)) #define IS_OSPF6_DEBUG_NEIGHBOR(level) \ (conf_debug_ospf6_neighbor & OSPF6_DEBUG_NEIGHBOR_ ## level) /* Neighbor structure */ struct ospf6_neighbor { /* Neighbor Router ID String */ char name[32]; /* OSPFv3 Interface this neighbor belongs to */ struct ospf6_interface *ospf6_if; /* Neighbor state */ u_char state; /* timestamp of last changing state */ u_int32_t state_change; struct timeval last_changed; /* Neighbor Router ID */ u_int32_t router_id; /* Neighbor Interface ID */ u_int32_t ifindex; /* Router Priority of this neighbor */ u_char priority; u_int32_t drouter; u_int32_t bdrouter; u_int32_t prev_drouter; u_int32_t prev_bdrouter; /* Options field (Capability) */ char options[3]; /* IPaddr of I/F on our side link */ struct in6_addr linklocal_addr; /* For Database Exchange */ u_char dbdesc_bits; u_int32_t dbdesc_seqnum; /* Last received Database Description packet */ struct ospf6_dbdesc dbdesc_last; /* LS-list */ struct ospf6_lsdb *summary_list; struct ospf6_lsdb *request_list; struct ospf6_lsdb *retrans_list; /* LSA list for message transmission */ struct ospf6_lsdb *dbdesc_list; struct ospf6_lsdb *lsreq_list; struct ospf6_lsdb *lsupdate_list; struct ospf6_lsdb *lsack_list; struct ospf6_lsa *last_ls_req; /* Inactivity timer */ struct thread *inactivity_timer; /* Thread for sending message */ struct thread *thread_send_dbdesc; struct thread *thread_send_lsreq; struct thread *thread_send_lsupdate; struct thread *thread_send_lsack; }; /* Neighbor state */ #define OSPF6_NEIGHBOR_DOWN 1 #define OSPF6_NEIGHBOR_ATTEMPT 2 #define OSPF6_NEIGHBOR_INIT 3 #define OSPF6_NEIGHBOR_TWOWAY 4 #define OSPF6_NEIGHBOR_EXSTART 5 #define OSPF6_NEIGHBOR_EXCHANGE 6 #define OSPF6_NEIGHBOR_LOADING 7 #define OSPF6_NEIGHBOR_FULL 8 /* Neighbor Events */ #define OSPF6_NEIGHBOR_EVENT_NO_EVENT 0 #define OSPF6_NEIGHBOR_EVENT_HELLO_RCVD 1 #define OSPF6_NEIGHBOR_EVENT_TWOWAY_RCVD 2 #define OSPF6_NEIGHBOR_EVENT_NEGOTIATION_DONE 3 #define OSPF6_NEIGHBOR_EVENT_EXCHANGE_DONE 4 #define OSPF6_NEIGHBOR_EVENT_LOADING_DONE 5 #define OSPF6_NEIGHBOR_EVENT_ADJ_OK 6 #define OSPF6_NEIGHBOR_EVENT_SEQNUMBER_MISMATCH 7 #define OSPF6_NEIGHBOR_EVENT_BAD_LSREQ 8 #define OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD 9 #define OSPF6_NEIGHBOR_EVENT_INACTIVITY_TIMER 10 #define OSPF6_NEIGHBOR_EVENT_MAX_EVENT 11 extern const char *ospf6_neighbor_state_str[]; /* Function Prototypes */ int ospf6_neighbor_cmp (void *va, void *vb); void ospf6_neighbor_dbex_init (struct ospf6_neighbor *on); struct ospf6_neighbor *ospf6_neighbor_lookup (u_int32_t, struct ospf6_interface *); struct ospf6_neighbor *ospf6_neighbor_create (u_int32_t, struct ospf6_interface *); void ospf6_neighbor_delete (struct ospf6_neighbor *); /* Neighbor event */ extern int hello_received (struct thread *); extern int twoway_received (struct thread *); extern int negotiation_done (struct thread *); extern int exchange_done (struct thread *); extern int loading_done (struct thread *); extern int adj_ok (struct thread *); extern int seqnumber_mismatch (struct thread *); extern int bad_lsreq (struct thread *); extern int oneway_received (struct thread *); extern int inactivity_timer (struct thread *); extern void ospf6_check_nbr_loading (struct ospf6_neighbor *); extern void ospf6_neighbor_init (void); extern int config_write_ospf6_debug_neighbor (struct vty *vty); extern void install_element_ospf6_debug_neighbor (void); #endif /* OSPF6_NEIGHBOR_H */ quagga-0.99.24.1/ospf6d/ospf6_interface.h0000644000175000017500000001125112476520570014663 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_INTERFACE_H #define OSPF6_INTERFACE_H #include "if.h" /* Debug option */ extern unsigned char conf_debug_ospf6_interface; #define OSPF6_DEBUG_INTERFACE_ON() \ (conf_debug_ospf6_interface = 1) #define OSPF6_DEBUG_INTERFACE_OFF() \ (conf_debug_ospf6_interface = 0) #define IS_OSPF6_DEBUG_INTERFACE \ (conf_debug_ospf6_interface) /* Interface structure */ struct ospf6_interface { /* IF info from zebra */ struct interface *interface; /* back pointer */ struct ospf6_area *area; /* list of ospf6 neighbor */ struct list *neighbor_list; /* linklocal address of this I/F */ struct in6_addr *linklocal_addr; /* Interface ID; use interface->ifindex */ /* ospf6 instance id */ u_char instance_id; /* I/F transmission delay */ u_int32_t transdelay; /* Network Type */ u_char type; /* Router Priority */ u_char priority; /* Time Interval */ u_int16_t hello_interval; u_int16_t dead_interval; u_int32_t rxmt_interval; u_int32_t state_change; /* Cost */ u_int32_t cost; /* I/F MTU */ u_int32_t ifmtu; /* Interface State */ u_char state; /* OSPF6 Interface flag */ char flag; /* MTU mismatch check */ u_char mtu_ignore; /* Decision of DR Election */ u_int32_t drouter; u_int32_t bdrouter; u_int32_t prev_drouter; u_int32_t prev_bdrouter; /* Linklocal LSA Database: includes Link-LSA */ struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; struct ospf6_lsdb *lsupdate_list; struct ospf6_lsdb *lsack_list; /* Ongoing Tasks */ struct thread *thread_send_hello; struct thread *thread_send_lsupdate; struct thread *thread_send_lsack; struct thread *thread_network_lsa; struct thread *thread_link_lsa; struct thread *thread_intra_prefix_lsa; struct ospf6_route_table *route_connected; /* prefix-list name to filter connected prefix */ char *plist_name; }; /* interface state */ #define OSPF6_INTERFACE_NONE 0 #define OSPF6_INTERFACE_DOWN 1 #define OSPF6_INTERFACE_LOOPBACK 2 #define OSPF6_INTERFACE_WAITING 3 #define OSPF6_INTERFACE_POINTTOPOINT 4 #define OSPF6_INTERFACE_DROTHER 5 #define OSPF6_INTERFACE_BDR 6 #define OSPF6_INTERFACE_DR 7 #define OSPF6_INTERFACE_MAX 8 extern const char *ospf6_interface_state_str[]; /* flags */ #define OSPF6_INTERFACE_DISABLE 0x01 #define OSPF6_INTERFACE_PASSIVE 0x02 #define OSPF6_INTERFACE_NOAUTOCOST 0x04 /* default values */ #define OSPF6_INTERFACE_HELLO_INTERVAL 10 #define OSPF6_INTERFACE_DEAD_INTERVAL 40 #define OSPF6_INTERFACE_RXMT_INTERVAL 5 #define OSPF6_INTERFACE_COST 1 #define OSPF6_INTERFACE_PRIORITY 1 #define OSPF6_INTERFACE_TRANSDELAY 1 #define OSPF6_INTERFACE_INSTANCE_ID 0 #define OSPF6_INTERFACE_BANDWIDTH 10000 /* Kbps */ #define OSPF6_REFERENCE_BANDWIDTH 100000 /* Kbps */ /* Function Prototypes */ extern struct ospf6_interface *ospf6_interface_lookup_by_ifindex (int); extern struct ospf6_interface *ospf6_interface_create (struct interface *); extern void ospf6_interface_delete (struct ospf6_interface *); extern void ospf6_interface_enable (struct ospf6_interface *); extern void ospf6_interface_disable (struct ospf6_interface *); extern void ospf6_interface_if_add (struct interface *); extern void ospf6_interface_if_del (struct interface *); extern void ospf6_interface_state_update (struct interface *); extern void ospf6_interface_connected_route_update (struct interface *); /* interface event */ extern int interface_up (struct thread *); extern int interface_down (struct thread *); extern int wait_timer (struct thread *); extern int backup_seen (struct thread *); extern int neighbor_change (struct thread *); extern void ospf6_interface_init (void); extern int config_write_ospf6_debug_interface (struct vty *vty); extern void install_element_ospf6_debug_interface (void); #endif /* OSPF6_INTERFACE_H */ quagga-0.99.24.1/ospf6d/ospf6_area.h0000644000175000017500000000667612476520570013652 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF_AREA_H #define OSPF_AREA_H #include "ospf6_top.h" struct ospf6_area { /* Reference to Top data structure */ struct ospf6 *ospf6; /* Area-ID */ u_int32_t area_id; /* Area-ID string */ char name[16]; /* flag */ u_char flag; /* OSPF Option */ u_char options[3]; /* Summary routes to be originated (includes Configured Address Ranges) */ struct ospf6_route_table *range_table; struct ospf6_route_table *summary_prefix; struct ospf6_route_table *summary_router; /* OSPF interface list */ struct list *if_list; struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; struct ospf6_route_table *spf_table; struct ospf6_route_table *route_table; struct thread *thread_spf_calculation; struct thread *thread_route_calculation; u_int32_t spf_calculation; /* SPF calculation count */ struct thread *thread_router_lsa; struct thread *thread_intra_prefix_lsa; u_int32_t router_lsa_size_limit; /* Area announce list */ struct { char *name; struct access_list *list; } _export; #define EXPORT_NAME(A) (A)->_export.name #define EXPORT_LIST(A) (A)->_export.list /* Area acceptance list */ struct { char *name; struct access_list *list; } import; #define IMPORT_NAME(A) (A)->import.name #define IMPORT_LIST(A) (A)->import.list /* Type 3 LSA Area prefix-list */ struct { char *name; struct prefix_list *list; } plist_in; #define PREFIX_NAME_IN(A) (A)->plist_in.name #define PREFIX_LIST_IN(A) (A)->plist_in.list struct { char *name; struct prefix_list *list; } plist_out; #define PREFIX_NAME_OUT(A) (A)->plist_out.name #define PREFIX_LIST_OUT(A) (A)->plist_out.list }; #define OSPF6_AREA_ENABLE 0x01 #define OSPF6_AREA_ACTIVE 0x02 #define OSPF6_AREA_TRANSIT 0x04 /* TransitCapability */ #define OSPF6_AREA_STUB 0x08 #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE)) #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE)) #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT)) #define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB)) /* prototypes */ extern int ospf6_area_cmp (void *va, void *vb); extern struct ospf6_area *ospf6_area_create (u_int32_t, struct ospf6 *); extern void ospf6_area_delete (struct ospf6_area *); extern struct ospf6_area *ospf6_area_lookup (u_int32_t, struct ospf6 *); extern void ospf6_area_enable (struct ospf6_area *); extern void ospf6_area_disable (struct ospf6_area *); extern void ospf6_area_show (struct vty *, struct ospf6_area *); extern void ospf6_area_config_write (struct vty *vty); extern void ospf6_area_init (void); #endif /* OSPF_AREA_H */ quagga-0.99.24.1/ospf6d/ospf6_top.h0000644000175000017500000000533112476520570013527 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_TOP_H #define OSPF6_TOP_H #include "routemap.h" /* OSPFv3 top level data structure */ struct ospf6 { /* my router id */ u_int32_t router_id; /* static router id */ u_int32_t router_id_static; /* start time */ struct timeval starttime; /* list of areas */ struct list *area_list; struct ospf6_area *backbone; /* AS scope link state database */ struct ospf6_lsdb *lsdb; struct ospf6_lsdb *lsdb_self; struct ospf6_route_table *route_table; struct ospf6_route_table *brouter_table; struct ospf6_route_table *external_table; struct route_table *external_id_table; u_int32_t external_id; /* redistribute route-map */ struct { char *name; struct route_map *map; } rmap[ZEBRA_ROUTE_MAX]; u_char flag; /* Configured flags */ u_char config_flags; #define OSPF6_LOG_ADJACENCY_CHANGES (1 << 0) #define OSPF6_LOG_ADJACENCY_DETAIL (1 << 1) /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ unsigned int spf_reason; /* reason bits while scheduling SPF */ struct timeval ts_spf; /* SPF calculation time stamp. */ struct timeval ts_spf_duration; /* Execution time of last SPF */ unsigned int last_spf_reason; /* Last SPF reason */ /* Threads */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *maxage_remover; u_int32_t ref_bandwidth; }; #define OSPF6_DISABLED 0x01 #define OSPF6_STUB_ROUTER 0x02 /* global pointer for OSPF top data structure */ extern struct ospf6 *ospf6; /* prototypes */ extern void ospf6_top_init (void); extern void ospf6_delete (struct ospf6 *o); extern void ospf6_maxage_remove (struct ospf6 *o); #endif /* OSPF6_TOP_H */ quagga-0.99.24.1/ospf6d/ospf6_lsdb.h0000644000175000017500000000703312476520570013652 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_LSDB_H #define OSPF6_LSDB_H #include "prefix.h" #include "table.h" struct ospf6_lsdb { void *data; /* data structure that holds this lsdb */ struct route_table *table; u_int32_t count; void (*hook_add) (struct ospf6_lsa *); void (*hook_remove) (struct ospf6_lsa *); }; /* Function Prototypes */ extern struct ospf6_lsdb *ospf6_lsdb_create (void *data); extern void ospf6_lsdb_delete (struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_lookup (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_lookup_next (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_add (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_remove (struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_head (struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_next (struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsdb_type_router_head (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_type_router_next (u_int16_t type, u_int32_t adv_router, struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsdb_type_head (u_int16_t type, struct ospf6_lsdb *lsdb); extern struct ospf6_lsa *ospf6_lsdb_type_next (u_int16_t type, struct ospf6_lsa *lsa); extern void ospf6_lsdb_remove_all (struct ospf6_lsdb *lsdb); extern void ospf6_lsdb_lsa_unlock (struct ospf6_lsa *lsa); enum ospf_lsdb_show_level { OSPF6_LSDB_SHOW_LEVEL_NORMAL = 0, OSPF6_LSDB_SHOW_LEVEL_DETAIL, OSPF6_LSDB_SHOW_LEVEL_INTERNAL, OSPF6_LSDB_SHOW_LEVEL_DUMP, }; extern void ospf6_lsdb_show (struct vty *vty, enum ospf_lsdb_show_level level, u_int16_t *type, u_int32_t *id, u_int32_t *adv_router, struct ospf6_lsdb *lsdb); extern u_int32_t ospf6_new_ls_id (u_int16_t type, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern u_int32_t ospf6_new_ls_seqnum (u_int16_t type, u_int32_t id, u_int32_t adv_router, struct ospf6_lsdb *lsdb); extern int ospf6_lsdb_maxage_remover (struct ospf6_lsdb *lsdb); #endif /* OSPF6_LSDB_H */ quagga-0.99.24.1/ospf6d/ospf6_lsa.h0000644000175000017500000002377212476520570013515 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_LSA_H #define OSPF6_LSA_H /* Debug option */ #define OSPF6_LSA_DEBUG 0x01 #define OSPF6_LSA_DEBUG_ORIGINATE 0x02 #define OSPF6_LSA_DEBUG_EXAMIN 0x04 #define OSPF6_LSA_DEBUG_FLOOD 0x08 #define IS_OSPF6_DEBUG_LSA(name) \ (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ OSPF6_LSA_DEBUG) #define IS_OSPF6_DEBUG_ORIGINATE(name) \ (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ OSPF6_LSA_DEBUG_ORIGINATE) #define IS_OSPF6_DEBUG_EXAMIN(name) \ (ospf6_lstype_debug (htons (OSPF6_LSTYPE_ ## name)) & \ OSPF6_LSA_DEBUG_EXAMIN) #define IS_OSPF6_DEBUG_LSA_TYPE(type) \ (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG) #define IS_OSPF6_DEBUG_ORIGINATE_TYPE(type) \ (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_ORIGINATE) #define IS_OSPF6_DEBUG_EXAMIN_TYPE(type) \ (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_EXAMIN) #define IS_OSPF6_DEBUG_FLOOD_TYPE(type) \ (ospf6_lstype_debug (type) & OSPF6_LSA_DEBUG_FLOOD) /* LSA definition */ #define OSPF6_MAX_LSASIZE 4096 /* Type */ #define OSPF6_LSTYPE_UNKNOWN 0x0000 #define OSPF6_LSTYPE_ROUTER 0x2001 #define OSPF6_LSTYPE_NETWORK 0x2002 #define OSPF6_LSTYPE_INTER_PREFIX 0x2003 #define OSPF6_LSTYPE_INTER_ROUTER 0x2004 #define OSPF6_LSTYPE_AS_EXTERNAL 0x4005 #define OSPF6_LSTYPE_GROUP_MEMBERSHIP 0x2006 #define OSPF6_LSTYPE_TYPE_7 0x2007 #define OSPF6_LSTYPE_LINK 0x0008 #define OSPF6_LSTYPE_INTRA_PREFIX 0x2009 #define OSPF6_LSTYPE_SIZE 0x000a /* Masks for LS Type : RFC 2740 A.4.2.1 "LS type" */ #define OSPF6_LSTYPE_UBIT_MASK 0x8000 #define OSPF6_LSTYPE_SCOPE_MASK 0x6000 #define OSPF6_LSTYPE_FCODE_MASK 0x1fff /* LSA scope */ #define OSPF6_SCOPE_LINKLOCAL 0x0000 #define OSPF6_SCOPE_AREA 0x2000 #define OSPF6_SCOPE_AS 0x4000 #define OSPF6_SCOPE_RESERVED 0x6000 /* XXX U-bit handling should be treated here */ #define OSPF6_LSA_SCOPE(type) \ (ntohs (type) & OSPF6_LSTYPE_SCOPE_MASK) /* LSA Header */ #define OSPF6_LSA_HEADER_SIZE 20U struct ospf6_lsa_header { u_int16_t age; /* LS age */ u_int16_t type; /* LS type */ u_int32_t id; /* Link State ID */ u_int32_t adv_router; /* Advertising Router */ u_int32_t seqnum; /* LS sequence number */ u_int16_t checksum; /* LS checksum */ u_int16_t length; /* LSA length */ }; #define OSPF6_LSA_HEADER_END(h) \ ((caddr_t)(h) + sizeof (struct ospf6_lsa_header)) #define OSPF6_LSA_SIZE(h) \ (ntohs (((struct ospf6_lsa_header *) (h))->length)) #define OSPF6_LSA_END(h) \ ((caddr_t)(h) + ntohs (((struct ospf6_lsa_header *) (h))->length)) #define OSPF6_LSA_IS_TYPE(t, L) \ ((L)->header->type == htons (OSPF6_LSTYPE_ ## t) ? 1 : 0) #define OSPF6_LSA_IS_SAME(L1, L2) \ ((L1)->header->adv_router == (L2)->header->adv_router && \ (L1)->header->id == (L2)->header->id && \ (L1)->header->type == (L2)->header->type) #define OSPF6_LSA_IS_MATCH(t, i, a, L) \ ((L)->header->adv_router == (a) && (L)->header->id == (i) && \ (L)->header->type == (t)) #define OSPF6_LSA_IS_DIFFER(L1, L2) ospf6_lsa_is_differ (L1, L2) #define OSPF6_LSA_IS_MAXAGE(L) (ospf6_lsa_age_current (L) == OSPF_LSA_MAXAGE) #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2) #define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1)) struct ospf6_lsa { char name[64]; /* dump string */ struct route_node *rn; unsigned char lock; /* reference counter */ unsigned char flag; /* special meaning (e.g. floodback) */ struct timeval birth; /* tv_sec when LS age 0 */ struct timeval originated; /* used by MinLSInterval check */ struct timeval received; /* used by MinLSArrival check */ struct timeval installed; struct thread *expire; struct thread *refresh; /* For self-originated LSA */ int retrans_count; struct ospf6_lsdb *lsdb; /* lsa instance */ struct ospf6_lsa_header *header; }; #define OSPF6_LSA_HEADERONLY 0x01 #define OSPF6_LSA_FLOODBACK 0x02 #define OSPF6_LSA_DUPLICATE 0x04 #define OSPF6_LSA_IMPLIEDACK 0x08 #define OSPF6_LSA_SEQWRAPPED 0x20 struct ospf6_lsa_handler { u_int16_t type; /* host byte order */ const char *name; const char *short_name; int (*show) (struct vty *, struct ospf6_lsa *); char *(*get_prefix_str) (struct ospf6_lsa *, char *buf, int buflen, int pos); u_char debug; }; extern struct ospf6_lsa_handler unknown_handler; #define OSPF6_LSA_IS_KNOWN(type) \ (ospf6_get_lsa_handler (type) != &unknown_handler ? 1 : 0) /* Macro for LSA Origination */ /* addr is (struct prefix *) */ #define CONTINUE_IF_ADDRESS_LINKLOCAL(debug,addr) \ if (IN6_IS_ADDR_LINKLOCAL (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_debug ("Filter out Linklocal: %s", buf); \ continue; \ } #define CONTINUE_IF_ADDRESS_UNSPECIFIED(debug,addr) \ if (IN6_IS_ADDR_UNSPECIFIED (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_debug ("Filter out Unspecified: %s", buf);\ continue; \ } #define CONTINUE_IF_ADDRESS_LOOPBACK(debug,addr) \ if (IN6_IS_ADDR_LOOPBACK (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_debug ("Filter out Loopback: %s", buf); \ continue; \ } #define CONTINUE_IF_ADDRESS_V4COMPAT(debug,addr) \ if (IN6_IS_ADDR_V4COMPAT (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_debug ("Filter out V4Compat: %s", buf); \ continue; \ } #define CONTINUE_IF_ADDRESS_V4MAPPED(debug,addr) \ if (IN6_IS_ADDR_V4MAPPED (&(addr)->u.prefix6)) \ { \ char buf[64]; \ prefix2str (addr, buf, sizeof (buf)); \ if (debug) \ zlog_debug ("Filter out V4Mapped: %s", buf); \ continue; \ } /* Function Prototypes */ extern const char *ospf6_lstype_name (u_int16_t type); extern const char *ospf6_lstype_short_name (u_int16_t type); extern u_char ospf6_lstype_debug (u_int16_t type); extern int ospf6_lsa_is_differ (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern int ospf6_lsa_is_changed (struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2); extern u_int16_t ospf6_lsa_age_current (struct ospf6_lsa *); extern void ospf6_lsa_age_update_to_send (struct ospf6_lsa *, u_int32_t); extern void ospf6_lsa_premature_aging (struct ospf6_lsa *); extern int ospf6_lsa_compare (struct ospf6_lsa *, struct ospf6_lsa *); extern char *ospf6_lsa_printbuf (struct ospf6_lsa *lsa, char *buf, int size); extern void ospf6_lsa_header_print_raw (struct ospf6_lsa_header *header); extern void ospf6_lsa_header_print (struct ospf6_lsa *lsa); extern void ospf6_lsa_show_summary_header (struct vty *vty); extern void ospf6_lsa_show_summary (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show_dump (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show_internal (struct vty *vty, struct ospf6_lsa *lsa); extern void ospf6_lsa_show (struct vty *vty, struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_create (struct ospf6_lsa_header *header); extern struct ospf6_lsa *ospf6_lsa_create_headeronly (struct ospf6_lsa_header *header); extern void ospf6_lsa_delete (struct ospf6_lsa *lsa); extern struct ospf6_lsa *ospf6_lsa_copy (struct ospf6_lsa *); extern void ospf6_lsa_lock (struct ospf6_lsa *); extern void ospf6_lsa_unlock (struct ospf6_lsa *); extern int ospf6_lsa_expire (struct thread *); extern int ospf6_lsa_refresh (struct thread *); extern unsigned short ospf6_lsa_checksum (struct ospf6_lsa_header *); extern int ospf6_lsa_checksum_valid (struct ospf6_lsa_header *); extern int ospf6_lsa_prohibited_duration (u_int16_t type, u_int32_t id, u_int32_t adv_router, void *scope); extern void ospf6_install_lsa_handler (struct ospf6_lsa_handler *handler); extern struct ospf6_lsa_handler *ospf6_get_lsa_handler (u_int16_t type); extern void ospf6_lsa_init (void); extern void ospf6_lsa_terminate (void); extern int config_write_ospf6_debug_lsa (struct vty *vty); extern void install_element_ospf6_debug_lsa (void); #endif /* OSPF6_LSA_H */ quagga-0.99.24.1/ospf6d/ospf6_message.h0000644000175000017500000001075312476520570014355 00000000000000/* * Copyright (C) 1999-2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_MESSAGE_H #define OSPF6_MESSAGE_H #define OSPF6_MESSAGE_BUFSIZ 4096 /* Debug option */ extern unsigned char conf_debug_ospf6_message[]; #define OSPF6_DEBUG_MESSAGE_SEND 0x01 #define OSPF6_DEBUG_MESSAGE_RECV 0x02 #define OSPF6_DEBUG_MESSAGE_ON(type, level) \ (conf_debug_ospf6_message[type] |= (level)) #define OSPF6_DEBUG_MESSAGE_OFF(type, level) \ (conf_debug_ospf6_message[type] &= ~(level)) #define IS_OSPF6_DEBUG_MESSAGE(t, e) \ (conf_debug_ospf6_message[t] & OSPF6_DEBUG_MESSAGE_ ## e) /* Type */ #define OSPF6_MESSAGE_TYPE_UNKNOWN 0x0 #define OSPF6_MESSAGE_TYPE_HELLO 0x1 /* Discover/maintain neighbors */ #define OSPF6_MESSAGE_TYPE_DBDESC 0x2 /* Summarize database contents */ #define OSPF6_MESSAGE_TYPE_LSREQ 0x3 /* Database download request */ #define OSPF6_MESSAGE_TYPE_LSUPDATE 0x4 /* Database update */ #define OSPF6_MESSAGE_TYPE_LSACK 0x5 /* Flooding acknowledgment */ #define OSPF6_MESSAGE_TYPE_ALL 0x6 /* For debug option */ /* OSPFv3 packet header */ #define OSPF6_HEADER_SIZE 16U struct ospf6_header { u_char version; u_char type; u_int16_t length; u_int32_t router_id; u_int32_t area_id; u_int16_t checksum; u_char instance_id; u_char reserved; }; #define OSPF6_MESSAGE_END(H) ((caddr_t) (H) + ntohs ((H)->length)) /* Hello */ #define OSPF6_HELLO_MIN_SIZE 20U struct ospf6_hello { u_int32_t interface_id; u_char priority; u_char options[3]; u_int16_t hello_interval; u_int16_t dead_interval; u_int32_t drouter; u_int32_t bdrouter; /* Followed by Router-IDs */ }; /* Database Description */ #define OSPF6_DB_DESC_MIN_SIZE 12U struct ospf6_dbdesc { u_char reserved1; u_char options[3]; u_int16_t ifmtu; u_char reserved2; u_char bits; u_int32_t seqnum; /* Followed by LSA Headers */ }; #define OSPF6_DBDESC_MSBIT (0x01) /* master/slave bit */ #define OSPF6_DBDESC_MBIT (0x02) /* more bit */ #define OSPF6_DBDESC_IBIT (0x04) /* initial bit */ /* Link State Request */ #define OSPF6_LS_REQ_MIN_SIZE 0U /* It is just a sequence of entries below */ #define OSPF6_LSREQ_LSDESC_FIX_SIZE 12U struct ospf6_lsreq_entry { u_int16_t reserved; /* Must Be Zero */ u_int16_t type; /* LS type */ u_int32_t id; /* Link State ID */ u_int32_t adv_router; /* Advertising Router */ }; /* Link State Update */ #define OSPF6_LS_UPD_MIN_SIZE 4U struct ospf6_lsupdate { u_int32_t lsa_number; /* Followed by LSAs */ }; /* Link State Acknowledgement */ #define OSPF6_LS_ACK_MIN_SIZE 0U /* It is just a sequence of LSA Headers */ /* Function definition */ extern void ospf6_hello_print (struct ospf6_header *); extern void ospf6_dbdesc_print (struct ospf6_header *); extern void ospf6_lsreq_print (struct ospf6_header *); extern void ospf6_lsupdate_print (struct ospf6_header *); extern void ospf6_lsack_print (struct ospf6_header *); extern int ospf6_iobuf_size (unsigned int size); extern void ospf6_message_terminate (void); extern int ospf6_receive (struct thread *thread); extern int ospf6_hello_send (struct thread *thread); extern int ospf6_dbdesc_send (struct thread *thread); extern int ospf6_dbdesc_send_newone (struct thread *thread); extern int ospf6_lsreq_send (struct thread *thread); extern int ospf6_lsupdate_send_interface (struct thread *thread); extern int ospf6_lsupdate_send_neighbor (struct thread *thread); extern int ospf6_lsack_send_interface (struct thread *thread); extern int ospf6_lsack_send_neighbor (struct thread *thread); extern int config_write_ospf6_debug_message (struct vty *); extern void install_element_ospf6_debug_message (void); #endif /* OSPF6_MESSAGE_H */ quagga-0.99.24.1/ospf6d/ospf6_network.h0000644000175000017500000000250112476520570014412 00000000000000/* * Copyright (C) 2003 Yasuhiro Ohara * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef OSPF6_NETWORK_H #define OSPF6_NETWORK_H extern int ospf6_sock; extern struct in6_addr allspfrouters6; extern struct in6_addr alldrouters6; extern int ospf6_serv_sock (void); extern void ospf6_sso (u_int ifindex, struct in6_addr *group, int option); extern int ospf6_sendmsg (struct in6_addr *, struct in6_addr *, unsigned int *, struct iovec *); extern int ospf6_recvmsg (struct in6_addr *, struct in6_addr *, unsigned int *, struct iovec *); #endif /* OSPF6_NETWORK_H */ quagga-0.99.24.1/ospf6d/ospf6d.conf.sample0000644000175000017500000000212612476520570014766 00000000000000! ! Zebra configuration saved from vty ! 2003/11/28 00:49:49 ! hostname ospf6d@plant password zebra log stdout service advanced-vty ! debug ospf6 neighbor state ! interface fxp0 ipv6 ospf6 cost 1 ipv6 ospf6 hello-interval 10 ipv6 ospf6 dead-interval 40 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 priority 0 ipv6 ospf6 transmit-delay 1 ipv6 ospf6 instance-id 0 ! interface lo0 ipv6 ospf6 cost 1 ipv6 ospf6 hello-interval 10 ipv6 ospf6 dead-interval 40 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 priority 1 ipv6 ospf6 transmit-delay 1 ipv6 ospf6 instance-id 0 ! router ospf6 router-id 255.1.1.1 redistribute static route-map static-ospf6 interface fxp0 area 0.0.0.0 ! access-list access4 permit 127.0.0.1/32 ! ipv6 access-list access6 permit 3ffe:501::/32 ipv6 access-list access6 permit 2001:200::/48 ipv6 access-list access6 permit ::1/128 ! ipv6 prefix-list test-prefix seq 1000 deny any ! route-map static-ospf6 permit 10 match ipv6 address prefix-list test-prefix set metric-type type-2 set metric 2000 ! line vty access-class access4 ipv6 access-class access6 exec-timeout 0 0 ! quagga-0.99.24.1/ospf6d/Makefile.am0000644000175000017500000000203212476520570013466 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libospf6.a sbin_PROGRAMS = ospf6d libospf6_a_SOURCES = \ ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c ospf6_snmp.c \ ospf6d.c noinst_HEADERS = \ ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h ospf6_snmp.h \ ospf6d.h ospf6d_SOURCES = \ ospf6_main.c $(libospf6_a_SOURCES) ospf6d_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ospf6d.conf.sample quagga-0.99.24.1/ospf6d/Makefile.in0000644000175000017500000006373312476521251013513 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospf6d$(EXEEXT) subdir = ospf6d DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) \ README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libospf6_a_AR = $(AR) $(ARFLAGS) libospf6_a_LIBADD = am_libospf6_a_OBJECTS = ospf6_network.$(OBJEXT) \ ospf6_message.$(OBJEXT) ospf6_lsa.$(OBJEXT) \ ospf6_lsdb.$(OBJEXT) ospf6_top.$(OBJEXT) ospf6_area.$(OBJEXT) \ ospf6_interface.$(OBJEXT) ospf6_neighbor.$(OBJEXT) \ ospf6_flood.$(OBJEXT) ospf6_route.$(OBJEXT) \ ospf6_intra.$(OBJEXT) ospf6_zebra.$(OBJEXT) \ ospf6_spf.$(OBJEXT) ospf6_proto.$(OBJEXT) ospf6_asbr.$(OBJEXT) \ ospf6_abr.$(OBJEXT) ospf6_snmp.$(OBJEXT) ospf6d.$(OBJEXT) libospf6_a_OBJECTS = $(am_libospf6_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = ospf6_network.$(OBJEXT) ospf6_message.$(OBJEXT) \ ospf6_lsa.$(OBJEXT) ospf6_lsdb.$(OBJEXT) ospf6_top.$(OBJEXT) \ ospf6_area.$(OBJEXT) ospf6_interface.$(OBJEXT) \ ospf6_neighbor.$(OBJEXT) ospf6_flood.$(OBJEXT) \ ospf6_route.$(OBJEXT) ospf6_intra.$(OBJEXT) \ ospf6_zebra.$(OBJEXT) ospf6_spf.$(OBJEXT) \ ospf6_proto.$(OBJEXT) ospf6_asbr.$(OBJEXT) ospf6_abr.$(OBJEXT) \ ospf6_snmp.$(OBJEXT) ospf6d.$(OBJEXT) am_ospf6d_OBJECTS = ospf6_main.$(OBJEXT) $(am__objects_1) ospf6d_OBJECTS = $(am_ospf6d_OBJECTS) ospf6d_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) DIST_SOURCES = $(libospf6_a_SOURCES) $(ospf6d_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libospf6.a libospf6_a_SOURCES = \ ospf6_network.c ospf6_message.c ospf6_lsa.c ospf6_lsdb.c \ ospf6_top.c ospf6_area.c ospf6_interface.c ospf6_neighbor.c \ ospf6_flood.c ospf6_route.c ospf6_intra.c ospf6_zebra.c \ ospf6_spf.c ospf6_proto.c ospf6_asbr.c ospf6_abr.c ospf6_snmp.c \ ospf6d.c noinst_HEADERS = \ ospf6_network.h ospf6_message.h ospf6_lsa.h ospf6_lsdb.h \ ospf6_top.h ospf6_area.h ospf6_interface.h ospf6_neighbor.h \ ospf6_flood.h ospf6_route.h ospf6_intra.h ospf6_zebra.h \ ospf6_spf.h ospf6_proto.h ospf6_asbr.h ospf6_abr.h ospf6_snmp.h \ ospf6d.h ospf6d_SOURCES = \ ospf6_main.c $(libospf6_a_SOURCES) ospf6d_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ospf6d.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospf6d/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospf6d/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libospf6.a: $(libospf6_a_OBJECTS) $(libospf6_a_DEPENDENCIES) $(EXTRA_libospf6_a_DEPENDENCIES) $(AM_V_at)-rm -f libospf6.a $(AM_V_AR)$(libospf6_a_AR) libospf6.a $(libospf6_a_OBJECTS) $(libospf6_a_LIBADD) $(AM_V_at)$(RANLIB) libospf6.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospf6d$(EXEEXT): $(ospf6d_OBJECTS) $(ospf6d_DEPENDENCIES) $(EXTRA_ospf6d_DEPENDENCIES) @rm -f ospf6d$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ospf6d_OBJECTS) $(ospf6d_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_abr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_area.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_asbr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_flood.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_intra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_lsdb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_message.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_neighbor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_network.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_proto.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_snmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_spf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_top.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf6d.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/ospfd/0000755000175000017500000000000012476521355011431 500000000000000quagga-0.99.24.1/ospfd/ChangeLog.opaque.txt0000644000175000017500000002305012476520570015230 00000000000000----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2002.12.20 1. Bug fixes 1.1 When an opaque LSA is being removed from (or added to) the LSDB, it does not mean a change in network topology. Therefore, SPF recalculation should not be triggered in that case. There was an assertion failure problem "assert (rn && rn->info)" inside the function "ospf_ase_incremental_update()", because the upper function "ospf_lsa_maxage_walker_remover()" called it when a type-11 opaque LSA is removed due to MaxAge. 1.2 Type-9 LSA is defined to have "link-local" flooding scope. In the Database exchange procedure with a new neighbor, a type-9 LSA was added in the database summary of a DD message, even if the link is different from the one that have bound to. 2. Feature enhancements 2.1 Though a "wildcard" concept to handle type-9/10/11 LSAs altogether has introduced about a year ago, it was only a symbol definition and actual handling mechanism was not implemented. Now it works. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2002.7.8 1. Bug fixes 1.1 When "ospf_delete_opaque_functab()" is called, internal structure "oipt" remain unfreed. If register/delete functab is repeated, illegal memory access happens due to this "oipt". 1.2 In "free_opaque_info_per_id()", there was a crucial typo which ignores a condition test. "if (oipi->lsa != NULL);" <-- semicolon! 2. Feature enhancements None. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.12.03 1. Bug fixes 1.1 Though a new member "oi" has added to "struct ospf_lsa" to control flooding scope of type-9 Opaque-LSAs, the value was always NULL because no one set it. 1.2 In the function "show_ip_ospf_database_summary()" and "show_lsa_ detail_adv_router()", VTY output for type-11 Opaque-LSAs did not work properly. 1.3 URL for the opaque-type assignment reference has changed. 1.4 In the file "ospf_mpls_te.c", printf formats have changed to avoid compiler warning messages; "%lu" -> "%u", "%lx" -> "%x". Note that this hack depends on OS, compiler and their versions. 1.5 One of attached documentation "opaque_lsa.txt" has changed to reflect the latest coding. 2. Feature enhancements 2.1 Knowing that it is an ugly hack, an "officially unallocated" opaque-type value 0 has newly introduced as a "wildcard", which matches to all opaque-type. This value must not be flooded to the network, of course. 2.2 The Opaque-core module makes use of newly introduced hooks to dispatch every LSDB change (LSA installation and deletion) to preregistered opaque users. Therefore, by providing appropriate callback functions as new parameters of "ospf_register_opaque_functab()", an opaque user can refer to every LSA instance to be installed into, or to be deleted from, the LSDB. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.10.31 1. Bug fixes 1.1 Since each LSA has their own lifetime, they will remain in a routing domain (being stored in LSDB of each router), until their age naturally reach to MaxAge or explicitly being flushed by the originated router. Therefore, if a router restarted with a short downtime, it is possible that previously flooded self-originated LSAs might received if the NSM status is not less than Exchange. There were some problems in the way of handling self-originated Opaque-LSAs if they are contained in a received LSUpd message, but not installed to the local LSDB yet. Regardless of some conditions to start originating Opaque-LSAs (there should be at least one opaque-capable full-state neighbor), the function "ospf_flood()" will be called to flood and install this brand-new looking LSA. As the result, when the NSM of an opaque-capable neighbor gets full, internal state inconsistency happens; a user of Opaque-LSA such as MPLS-TE can refer to self-originated LSAs in the local LSDB, but cannot modify their contents... Above problems have fixed with a policy "flush it from the whole routing domain and keep silent until the flushing completed". By using this sweeping technique, we can be free from confusion caused by self-originated LSAs received via network. 1.2 The function "ospf_opaque_type_name()" contained massive ifdefs corresponding to each "opaque-type". These unnecessary ifdefs are removed completely. 1.3 In the function "ospf_delete_opaque_functab()", there was an improper loop control that causes illegal memory access. Original coding was "next = nextnode (node)". 1.4 The function "ospf_mpls_te_ism_change()" could not handle the case when the ISM changes from Waiting to DR/BDR/Other. So, there was a case that even if one of an ISM become operational and MPLS-TE module has started, the corresponding Opaque-LSA cannot be originated. 1.5 The function "ospf_opaque_lsa_reoriginate_schedule()" did not allow to be called multiple times, simply because handling module for the given "lsa-type & opaque-type" already exists. But this assumption seems to be wrong. Change the policy to allow this function to be called multiple times and let the caller to decide what should do when the corresponding callback function "(* functab->lsa_originator)()" is called. 2. Feature enhancements 2.1 The global bitmap "opaque" has introduced instead of former flag "OpaqueCapable", to store complex conditions to handle Opaque-LSAs. 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic -06.txt", no significant changes with 05 version, though. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.08.03 1. Bug fixes 1.1 Even if the ospfd started with opaque capability enabled, when the ospfd receives an unknown opaque-type (unregistered by the function "ospf_register_opaque_functab()" beforehand), the LSA was discarded. As the result, only the opaque-LSAs that have commonly registered by opaque-capable ospf routers can be flooded in a routing domain. This behavior has fixed so that arbitrary opaque-type LSAs can be flooded among opaque-capable ospf routers. If the ospfd has opaque-LSA capability but disabled at runtime, received opaque-LSAs can be accepted and registered to LSDB as is, but not be flooded to the network; those opaque LSAs will remain in LSDB until explicitly flushed by incoming LSUpd messages with MaxAge, or their age naturally reaches to MaxAge. 1.2 The function "ospf_register_opaque_functab()" did not check if the entry corresponding to the given "lsa-type, opaque-type" combination already exists or not. This problem has fixed not to allow multiple registration. 1.3 Since type-11 (AS external) LSAs will be flooded beyond areas, there is little relationship between "struct lsa" and "struct area". More specifically, the pointer address "lsa->area" can be NULL if the lsa-type is 11, thus an illegal memory access will happen. This problem has fixed. 1.4 When self-originated opaque-LSAs are received via network and if the corresponding opaque-type functions are not available (they have already deleted) at that time, those LSAs were dropped due to "unknown opaque-type" error. After the problem 1.1 has fixed, those "self-originated" LSAs were registered to LSDB and then flooded to the network, even if the processing functions did not exist... After all, this problem has fixed so that those LSAs should explicitly be flushed from the routing domain immediately, if the processing functions cannot find at that time. 1.5 Some typo have fixed. --- EXAMPLE --- static int opaque_lsa_originate_callback (list funclist, void *lsa_type_dependent) ^^^^^ --- EXAMPLE --- 2. Feature enhancements 2.1 According to the description of rfc2328 in section 10.8, any change in the router's optional capabilities should trigger the option re-negotiation procedures with neighbors. --- EXCERPT --- If for some reason the router's optional capabilities change, the Database Exchange procedure should be restarted by reverting to neighbor state ExStart. --- EXCERPT --- For the opaque-capability changes, this feature has implemented. More specifically, if "ospf opaque-lsa" or "no ospf opaque-lsa" VTY command is given at runtime, all self-originated LSAs will be flushed immediately and then all neighbor status will be forced to ExStart by generating SeqNumberMismatch events. 2.1 When we change opaque-capability dynamically (ON -> OFF -> ON), there was no trigger at "OFF->ON" timing to reactivate opaque LSA handling modules (such as MPLS-TE) that have once forcibly stopped at "ON->OFF" timing. Now this dynamic reactivation feature has added. 2.2 The MPLS-TE module now referes to "draft-katz-yeung-ospf-traffic -05.txt", no significant changes with 04 version, though. ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- * ----- Changes 2001.03.28 Initial release of Opaque-LSA/MPLS-TE extensions for the zebra/ospfd. quagga-0.99.24.1/ospfd/OSPF-TRAP-MIB.txt0000644000175000017500000003733712476520570014045 00000000000000OSPF-TRAP-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress FROM SNMPv2-SMI MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF ospfRouterId, ospfIfIpAddress, ospfAddressLessIf, ospfIfState, ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState, ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, ospfNbrState, ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbAreaId, ospfExtLsdbLimit, ospf FROM OSPF-MIB; ospfTrap MODULE-IDENTITY LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 ORGANIZATION "IETF OSPF Working Group" CONTACT-INFO " Fred Baker Postal: Cisco Systems 519 Lado Drive Santa Barbara, California 93111 Tel: +1 805 681 0115 E-Mail: fred@cisco.com Rob Coltun Postal: RainbowBridge Communications Tel: (301) 340-9416 E-Mail: rcoltun@rainbow-bridge.com" DESCRIPTION "The MIB module to describe traps for the OSPF Version 2 Protocol." ::= { ospf 16 } -- Trap Support Objects -- The following are support objects for the OSPF traps. ospfTrapControl OBJECT IDENTIFIER ::= { ospfTrap 1 } ospfTraps OBJECT IDENTIFIER ::= { ospfTrap 2 } ospfSetTrap OBJECT-TYPE SYNTAX OCTET STRING (SIZE(4)) MAX-ACCESS read-write STATUS current DESCRIPTION "A four-octet string serving as a bit map for the trap events defined by the OSPF traps. This object is used to enable and disable specific OSPF traps where a 1 in the bit field represents enabled. The right-most bit (least significant) represents trap 0." ::= { ospfTrapControl 1 } ospfConfigErrorType OBJECT-TYPE SYNTAX INTEGER { badVersion (1), areaMismatch (2), unknownNbmaNbr (3), -- Router is Dr eligible unknownVirtualNbr (4), authTypeMismatch(5), authFailure (6), netMaskMismatch (7), helloIntervalMismatch (8), deadIntervalMismatch (9), optionMismatch (10) } MAX-ACCESS read-only STATUS current DESCRIPTION "Potential types of configuration conflicts. Used by the ospfConfigError and ospfConfigVir- tError traps." ::= { ospfTrapControl 2 } ospfPacketType OBJECT-TYPE SYNTAX INTEGER { hello (1), dbDescript (2), lsReq (3), lsUpdate (4), lsAck (5) } MAX-ACCESS read-only STATUS current DESCRIPTION "OSPF packet types." ::= { ospfTrapControl 3 } ospfPacketSrc OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address of an inbound packet that can- not be identified by a neighbor instance." ::= { ospfTrapControl 4 } -- Traps ospfIfStateChange NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfIfIpAddress, ospfAddressLessIf, ospfIfState -- The new state } STATUS current DESCRIPTION "An ospfIfStateChange trap signifies that there has been a change in the state of a non-virtual OSPF interface. This trap should be generated when the interface state regresses (e.g., goes from Dr to Down) or progresses to a terminal state (i.e., Point-to-Point, DR Other, Dr, or Backup)." ::= { ospfTraps 16 } ospfVirtIfStateChange NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfState -- The new state } STATUS current DESCRIPTION "An ospfIfStateChange trap signifies that there has been a change in the state of an OSPF vir- tual interface. This trap should be generated when the inter- face state regresses (e.g., goes from Point- to-Point to Down) or progresses to a terminal state (i.e., Point-to-Point)." ::= { ospfTraps 1 } ospfNbrStateChange NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, ospfNbrState -- The new state } STATUS current DESCRIPTION "An ospfNbrStateChange trap signifies that there has been a change in the state of a non- virtual OSPF neighbor. This trap should be generated when the neighbor state regresses (e.g., goes from Attempt or Full to 1-Way or Down) or progresses to a terminal state (e.g., 2-Way or Full). When an neighbor transitions from or to Full on non-broadcast multi-access and broadcast networks, the trap should be gen- erated by the designated router. A designated router transitioning to Down will be noted by ospfIfStateChange." ::= { ospfTraps 2 } ospfVirtNbrStateChange NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrState -- The new state } STATUS current DESCRIPTION "An ospfIfStateChange trap signifies that there has been a change in the state of an OSPF vir- tual neighbor. This trap should be generated when the neighbor state regresses (e.g., goes from Attempt or Full to 1-Way or Down) or progresses to a terminal state (e.g., Full)." ::= { ospfTraps 3 } ospfIfConfigError NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfIfIpAddress, ospfAddressLessIf, ospfPacketSrc, -- The source IP address ospfConfigErrorType, -- Type of error ospfPacketType } STATUS current DESCRIPTION "An ospfIfConfigError trap signifies that a packet has been received on a non-virtual in- terface from a router whose configuration parameters conflict with this router's confi- guration parameters. Note that the event op- tionMismatch should cause a trap only if it prevents an adjacency from forming." ::= { ospfTraps 4 } ospfVirtIfConfigError NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfConfigErrorType, -- Type of error ospfPacketType } STATUS current DESCRIPTION "An ospfConfigError trap signifies that a pack- et has been received on a virtual interface from a router whose configuration parameters conflict with this router's configuration parameters. Note that the event optionMismatch should cause a trap only if it prevents an ad- jacency from forming." ::= { ospfTraps 5 } ospfIfAuthFailure NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfIfIpAddress, ospfAddressLessIf, ospfPacketSrc, -- The source IP address ospfConfigErrorType, -- authTypeMismatch or -- authFailure ospfPacketType } STATUS current DESCRIPTION "An ospfIfAuthFailure trap signifies that a packet has been received on a non-virtual in- terface from a router whose authentication key or authentication type conflicts with this router's authentication key or authentication type." ::= { ospfTraps 6 } ospfVirtIfAuthFailure NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfConfigErrorType, -- authTypeMismatch or -- authFailure ospfPacketType } STATUS current DESCRIPTION "An ospfVirtIfAuthFailure trap signifies that a packet has been received on a virtual interface from a router whose authentication key or au- thentication type conflicts with this router's authentication key or authentication type." ::= { ospfTraps 7 } ospfIfRxBadPacket NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfIfIpAddress, ospfAddressLessIf, ospfPacketSrc, -- The source IP address ospfPacketType } STATUS current DESCRIPTION "An ospfIfRxBadPacket trap signifies that an OSPF packet has been received on a non-virtual interface that cannot be parsed." ::= { ospfTraps 8 } ospfVirtIfRxBadPacket NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfPacketType } STATUS current DESCRIPTION "An ospfRxBadPacket trap signifies that an OSPF packet has been received on a virtual interface that cannot be parsed." ::= { ospfTraps 9 } ospfTxRetransmit NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfIfIpAddress, ospfAddressLessIf, ospfNbrRtrId, -- Destination ospfPacketType, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } STATUS current DESCRIPTION "An ospfTxRetransmit trap signifies than an OSPF packet has been retransmitted on a non- virtual interface. All packets that may be re- transmitted are associated with an LSDB entry. The LS type, LS ID, and Router ID are used to identify the LSDB entry." ::= { ospfTraps 10 } ospfVirtIfTxRetransmit NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfPacketType, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } STATUS current DESCRIPTION "An ospfTxRetransmit trap signifies than an OSPF packet has been retransmitted on a virtual interface. All packets that may be retransmit- ted are associated with an LSDB entry. The LS type, LS ID, and Router ID are used to identify the LSDB entry." ::= { ospfTraps 11 } ospfOriginateLsa NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfLsdbAreaId, -- 0.0.0.0 for AS Externals ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } STATUS current DESCRIPTION "An ospfOriginateLsa trap signifies that a new LSA has been originated by this router. This trap should not be invoked for simple refreshes of LSAs (which happesn every 30 minutes), but instead will only be invoked when an LSA is (re)originated due to a topology change. Addi- tionally, this trap does not include LSAs that are being flushed because they have reached MaxAge." ::= { ospfTraps 12 } ospfMaxAgeLsa NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfLsdbAreaId, -- 0.0.0.0 for AS Externals ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } STATUS current DESCRIPTION "An ospfMaxAgeLsa trap signifies that one of the LSA in the router's link-state database has aged to MaxAge." ::= { ospfTraps 13 } ospfLsdbOverflow NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfExtLsdbLimit } STATUS current DESCRIPTION "An ospfLsdbOverflow trap signifies that the number of LSAs in the router's link-state data- base has exceeded ospfExtLsdbLimit." ::= { ospfTraps 14 } ospfLsdbApproachingOverflow NOTIFICATION-TYPE OBJECTS { ospfRouterId, -- The originator of the trap ospfExtLsdbLimit } STATUS current DESCRIPTION "An ospfLsdbApproachingOverflow trap signifies that the number of LSAs in the router's link- state database has exceeded ninety percent of ospfExtLsdbLimit." ::= { ospfTraps 15 } -- conformance information ospfTrapConformance OBJECT IDENTIFIER ::= { ospfTrap 3 } ospfTrapGroups OBJECT IDENTIFIER ::= { ospfTrapConformance 1 } ospfTrapCompliances OBJECT IDENTIFIER ::= { ospfTrapConformance 2 } -- compliance statements ospfTrapCompliance MODULE-COMPLIANCE STATUS current DESCRIPTION "The compliance statement " MODULE -- this module MANDATORY-GROUPS { ospfTrapControlGroup } GROUP ospfTrapControlGroup DESCRIPTION "This group is optional but recommended for all OSPF systems" ::= { ospfTrapCompliances 1 } -- units of conformance ospfTrapControlGroup OBJECT-GROUP OBJECTS { ospfSetTrap, ospfConfigErrorType, ospfPacketType, ospfPacketSrc } STATUS current DESCRIPTION "These objects are required to control traps from OSPF systems." ::= { ospfTrapGroups 1 } END quagga-0.99.24.1/ospfd/OSPF-MIB.txt0000644000175000017500000025014412476520570013272 00000000000000OSPF-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, Counter32, Gauge32, Integer32, IpAddress FROM SNMPv2-SMI TEXTUAL-CONVENTION, TruthValue, RowStatus FROM SNMPv2-TC MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF mib-2 FROM RFC1213-MIB; -- This MIB module uses the extended OBJECT-TYPE macro as -- defined in [9]. ospf MODULE-IDENTITY LAST-UPDATED "9501201225Z" -- Fri Jan 20 12:25:50 PST 1995 ORGANIZATION "IETF OSPF Working Group" CONTACT-INFO " Fred Baker Postal: Cisco Systems 519 Lado Drive Santa Barbara, California 93111 Tel: +1 805 681 0115 E-Mail: fred@cisco.com Rob Coltun Postal: RainbowBridge Communications Tel: (301) 340-9416 E-Mail: rcoltun@rainbow-bridge.com" DESCRIPTION "The MIB module to describe the OSPF Version 2 Protocol" ::= { mib-2 14 } -- The Area ID, in OSPF, has the same format as an IP Address, -- but has the function of defining a summarization point for -- Link State Advertisements AreaID ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "An OSPF Area Identifier." SYNTAX IpAddress -- The Router ID, in OSPF, has the same format as an IP Address, -- but identifies the router independent of its IP Address. RouterID ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "A OSPF Router Identifier." SYNTAX IpAddress -- The OSPF Metric is defined as an unsigned value in the range Metric ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The OSPF Internal Metric." SYNTAX Integer32 (0..'FFFF'h) BigMetric ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The OSPF External Metric." SYNTAX Integer32 (0..'FFFFFF'h) -- Status Values Status ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The status of an interface: 'enabled' indicates that it is willing to communicate with other OSPF Routers, while 'disabled' indicates that it is not." SYNTAX INTEGER { enabled (1), disabled (2) } -- Time Durations measured in seconds PositiveInteger ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "A positive integer. Values in excess are precluded as unnecessary and prone to interoperability issues." SYNTAX Integer32 (0..'7FFFFFFF'h) HelloRange ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The range of intervals on which hello messages are exchanged." SYNTAX Integer32 (1..'FFFF'h) UpToMaxAge ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The values that one might find or configure for variables bounded by the maximum age of an LSA." SYNTAX Integer32 (0..3600) -- The range of ifIndex InterfaceIndex ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The range of ifIndex." SYNTAX Integer32 -- Potential Priorities for the Designated Router Election DesignatedRouterPriority ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "The values defined for the priority of a system for becoming the designated router." SYNTAX Integer32 (0..'FF'h) TOSType ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "Type of Service is defined as a mapping to the IP Type of Service Flags as defined in the IP Forwarding Table MIB +-----+-----+-----+-----+-----+-----+-----+-----+ | | | | | PRECEDENCE | TYPE OF SERVICE | 0 | | | | | +-----+-----+-----+-----+-----+-----+-----+-----+ IP TOS IP TOS Field Policy Field Policy Contents Code Contents Code 0 0 0 0 ==> 0 0 0 0 1 ==> 2 0 0 1 0 ==> 4 0 0 1 1 ==> 6 0 1 0 0 ==> 8 0 1 0 1 ==> 10 0 1 1 0 ==> 12 0 1 1 1 ==> 14 1 0 0 0 ==> 16 1 0 0 1 ==> 18 1 0 1 0 ==> 20 1 0 1 1 ==> 22 1 1 0 0 ==> 24 1 1 0 1 ==> 26 1 1 1 0 ==> 28 1 1 1 1 ==> 30 The remaining values are left for future definition." SYNTAX Integer32 (0..30) -- OSPF General Variables -- These parameters apply globally to the Router's -- OSPF Process. ospfGeneralGroup OBJECT IDENTIFIER ::= { ospf 1 } ospfRouterId OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-write STATUS current DESCRIPTION "A 32-bit integer uniquely identifying the router in the Autonomous System. By convention, to ensure uniqueness, this should default to the value of one of the router's IP interface addresses." REFERENCE "OSPF Version 2, C.1 Global parameters" ::= { ospfGeneralGroup 1 } ospfAdminStat OBJECT-TYPE SYNTAX Status MAX-ACCESS read-write STATUS current DESCRIPTION "The administrative status of OSPF in the router. The value 'enabled' denotes that the OSPF Process is active on at least one inter- face; 'disabled' disables it on all inter- faces." ::= { ospfGeneralGroup 2 } ospfVersionNumber OBJECT-TYPE SYNTAX INTEGER { version2 (2) } MAX-ACCESS read-only STATUS current DESCRIPTION "The current version number of the OSPF proto- col is 2." REFERENCE "OSPF Version 2, Title" ::= { ospfGeneralGroup 3 } ospfAreaBdrRtrStatus OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-only STATUS current DESCRIPTION "A flag to note whether this router is an area border router." REFERENCE "OSPF Version 2, Section 3 Splitting the AS into Areas" ::= { ospfGeneralGroup 4 } ospfASBdrRtrStatus OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-write STATUS current DESCRIPTION "A flag to note whether this router is config- ured as an Autonomous System border router." REFERENCE "OSPF Version 2, Section 3.3 Classification of routers" ::= { ospfGeneralGroup 5 } ospfExternLsaCount OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of external (LS type 5) link-state advertisements in the link-state database." REFERENCE "OSPF Version 2, Appendix A.4.5 AS external link advertisements" ::= { ospfGeneralGroup 6 } ospfExternLsaCksumSum OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "The 32-bit unsigned sum of the LS checksums of the external link-state advertisements con- tained in the link-state database. This sum can be used to determine if there has been a change in a router's link state database, and to compare the link-state database of two routers." ::= { ospfGeneralGroup 7 } ospfTOSSupport OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-write STATUS current DESCRIPTION "The router's support for type-of-service rout- ing." REFERENCE "OSPF Version 2, Appendix F.1.2 Optional TOS support" ::= { ospfGeneralGroup 8 } ospfOriginateNewLsas OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of new link-state advertisements that have been originated. This number is in- cremented each time the router originates a new LSA." ::= { ospfGeneralGroup 9 } ospfRxNewLsas OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of link-state advertisements re- ceived determined to be new instantiations. This number does not include newer instantia- tions of self-originated link-state advertise- ments." ::= { ospfGeneralGroup 10 } ospfExtLsdbLimit OBJECT-TYPE SYNTAX Integer32 (-1..'7FFFFFFF'h) MAX-ACCESS read-write STATUS current DESCRIPTION "The maximum number of non-default AS- external-LSAs entries that can be stored in the link-state database. If the value is -1, then there is no limit. When the number of non-default AS-external-LSAs in a router's link-state database reaches ospfExtLsdbLimit, the router enters Overflow- State. The router never holds more than ospfExtLsdbLimit non-default AS-external-LSAs in its database. OspfExtLsdbLimit MUST be set identically in all routers attached to the OSPF backbone and/or any regular OSPF area. (i.e., OSPF stub areas and NSSAs are excluded)." DEFVAL { -1 } ::= { ospfGeneralGroup 11 } ospfMulticastExtensions OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-write STATUS current DESCRIPTION "A Bit Mask indicating whether the router is forwarding IP multicast (Class D) datagrams based on the algorithms defined in the Multi- cast Extensions to OSPF. Bit 0, if set, indicates that the router can forward IP multicast datagrams in the router's directly attached areas (called intra-area mul- ticast routing). Bit 1, if set, indicates that the router can forward IP multicast datagrams between OSPF areas (called inter-area multicast routing). Bit 2, if set, indicates that the router can forward IP multicast datagrams between Auto- nomous Systems (called inter-AS multicast rout- ing). Only certain combinations of bit settings are allowed, namely: 0 (no multicast forwarding is enabled), 1 (intra-area multicasting only), 3 (intra-area and inter-area multicasting), 5 (intra-area and inter-AS multicasting) and 7 (multicasting everywhere). By default, no mul- ticast forwarding is enabled." DEFVAL { 0 } ::= { ospfGeneralGroup 12 } ospfExitOverflowInterval OBJECT-TYPE SYNTAX PositiveInteger MAX-ACCESS read-write STATUS current DESCRIPTION "The number of seconds that, after entering OverflowState, a router will attempt to leave OverflowState. This allows the router to again originate non-default AS-external-LSAs. When set to 0, the router will not leave Overflow- State until restarted." DEFVAL { 0 } ::= { ospfGeneralGroup 13 } ospfDemandExtensions OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-write STATUS current DESCRIPTION "The router's support for demand routing." REFERENCE "OSPF Version 2, Appendix on Demand Routing" ::= { ospfGeneralGroup 14 } -- The OSPF Area Data Structure contains information -- regarding the various areas. The interfaces and -- virtual links are configured as part of these areas. -- Area 0.0.0.0, by definition, is the Backbone Area ospfAreaTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfAreaEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing the configured parame- ters and cumulative statistics of the router's attached areas." REFERENCE "OSPF Version 2, Section 6 The Area Data Struc- ture" ::= { ospf 2 } ospfAreaEntry OBJECT-TYPE SYNTAX OspfAreaEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information describing the configured parame- ters and cumulative statistics of one of the router's attached areas." INDEX { ospfAreaId } ::= { ospfAreaTable 1 } OspfAreaEntry ::= SEQUENCE { ospfAreaId AreaID, ospfAuthType Integer32, ospfImportAsExtern INTEGER, ospfSpfRuns Counter32, ospfAreaBdrRtrCount Gauge32, ospfAsBdrRtrCount Gauge32, ospfAreaLsaCount Gauge32, ospfAreaLsaCksumSum Integer32, ospfAreaSummary INTEGER, ospfAreaStatus RowStatus } ospfAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "A 32-bit integer uniquely identifying an area. Area ID 0.0.0.0 is used for the OSPF backbone." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaEntry 1 } ospfAuthType OBJECT-TYPE SYNTAX Integer32 -- none (0), -- simplePassword (1) -- md5 (2) -- reserved for specification by IANA (> 2) MAX-ACCESS read-create STATUS obsolete DESCRIPTION "The authentication type specified for an area. Additional authentication types may be assigned locally on a per Area basis." REFERENCE "OSPF Version 2, Appendix E Authentication" DEFVAL { 0 } -- no authentication, by default ::= { ospfAreaEntry 2 } ospfImportAsExtern OBJECT-TYPE SYNTAX INTEGER { importExternal (1), importNoExternal (2), importNssa (3) } MAX-ACCESS read-create STATUS current DESCRIPTION "The area's support for importing AS external link- state advertisements." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" DEFVAL { importExternal } ::= { ospfAreaEntry 3 } ospfSpfRuns OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of times that the intra-area route table has been calculated using this area's link-state database. This is typically done using Dijkstra's algorithm." ::= { ospfAreaEntry 4 } ospfAreaBdrRtrCount OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of area border routers reach- able within this area. This is initially zero, and is calculated in each SPF Pass." ::= { ospfAreaEntry 5 } ospfAsBdrRtrCount OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of Autonomous System border routers reachable within this area. This is initially zero, and is calculated in each SPF Pass." ::= { ospfAreaEntry 6 } ospfAreaLsaCount OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of link-state advertisements in this area's link-state database, excluding AS External LSA's." ::= { ospfAreaEntry 7 } ospfAreaLsaCksumSum OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "The 32-bit unsigned sum of the link-state ad- vertisements' LS checksums contained in this area's link-state database. This sum excludes external (LS type 5) link-state advertisements. The sum can be used to determine if there has been a change in a router's link state data- base, and to compare the link-state database of two routers." DEFVAL { 0 } ::= { ospfAreaEntry 8 } ospfAreaSummary OBJECT-TYPE SYNTAX INTEGER { noAreaSummary (1), sendAreaSummary (2) } MAX-ACCESS read-create STATUS current DESCRIPTION "The variable ospfAreaSummary controls the im- port of summary LSAs into stub areas. It has no effect on other areas. If it is noAreaSummary, the router will neither originate nor propagate summary LSAs into the stub area. It will rely entirely on its de- fault route. If it is sendAreaSummary, the router will both summarize and propagate summary LSAs." DEFVAL { noAreaSummary } ::= { ospfAreaEntry 9 } ospfAreaStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfAreaEntry 10 } -- OSPF Area Default Metric Table -- The OSPF Area Default Metric Table describes the metrics -- that a default Area Border Router will advertise into a -- Stub area. ospfStubAreaTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfStubAreaEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The set of metrics that will be advertised by a default Area Border Router into a stub area." REFERENCE "OSPF Version 2, Appendix C.2, Area Parameters" ::= { ospf 3 } ospfStubAreaEntry OBJECT-TYPE SYNTAX OspfStubAreaEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The metric for a given Type of Service that will be advertised by a default Area Border Router into a stub area." REFERENCE "OSPF Version 2, Appendix C.2, Area Parameters" INDEX { ospfStubAreaId, ospfStubTOS } ::= { ospfStubAreaTable 1 } OspfStubAreaEntry ::= SEQUENCE { ospfStubAreaId AreaID, ospfStubTOS TOSType, ospfStubMetric BigMetric, ospfStubStatus RowStatus, ospfStubMetricType INTEGER } ospfStubAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The 32 bit identifier for the Stub Area. On creation, this can be derived from the in- stance." ::= { ospfStubAreaEntry 1 } ospfStubTOS OBJECT-TYPE SYNTAX TOSType MAX-ACCESS read-only STATUS current DESCRIPTION "The Type of Service associated with the metric. On creation, this can be derived from the instance." ::= { ospfStubAreaEntry 2 } ospfStubMetric OBJECT-TYPE SYNTAX BigMetric MAX-ACCESS read-create STATUS current DESCRIPTION "The metric value applied at the indicated type of service. By default, this equals the least metric at the type of service among the inter- faces to other areas." ::= { ospfStubAreaEntry 3 } ospfStubStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfStubAreaEntry 4 } ospfStubMetricType OBJECT-TYPE SYNTAX INTEGER { ospfMetric (1), -- OSPF Metric comparableCost (2), -- external type 1 nonComparable (3) -- external type 2 } MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the type of metric ad- vertised as a default route." DEFVAL { ospfMetric } ::= { ospfStubAreaEntry 5 } -- OSPF Link State Database -- The Link State Database contains the Link State -- Advertisements from throughout the areas that the -- device is attached to. ospfLsdbTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfLsdbEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The OSPF Process's Link State Database." REFERENCE "OSPF Version 2, Section 12 Link State Adver- tisements" ::= { ospf 4 } ospfLsdbEntry OBJECT-TYPE SYNTAX OspfLsdbEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A single Link State Advertisement." INDEX { ospfLsdbAreaId, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } ::= { ospfLsdbTable 1 } OspfLsdbEntry ::= SEQUENCE { ospfLsdbAreaId AreaID, ospfLsdbType INTEGER, ospfLsdbLsid IpAddress, ospfLsdbRouterId RouterID, ospfLsdbSequence Integer32, ospfLsdbAge Integer32, ospfLsdbChecksum Integer32, ospfLsdbAdvertisement OCTET STRING } ospfLsdbAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The 32 bit identifier of the Area from which the LSA was received." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfLsdbEntry 1 } -- External Link State Advertisements are permitted -- for backward compatibility, but should be displayed in -- the ospfExtLsdbTable rather than here. ospfLsdbType OBJECT-TYPE SYNTAX INTEGER { routerLink (1), networkLink (2), summaryLink (3), asSummaryLink (4), asExternalLink (5), -- but see ospfExtLsdbTable multicastLink (6), nssaExternalLink (7) } MAX-ACCESS read-only STATUS current DESCRIPTION "The type of the link state advertisement. Each link state type has a separate advertise- ment format." REFERENCE "OSPF Version 2, Appendix A.4.1 The Link State Advertisement header" ::= { ospfLsdbEntry 2 } ospfLsdbLsid OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The Link State ID is an LS Type Specific field containing either a Router ID or an IP Address; it identifies the piece of the routing domain that is being described by the advertisement." REFERENCE "OSPF Version 2, Section 12.1.4 Link State ID" ::= { ospfLsdbEntry 3 } ospfLsdbRouterId OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-only STATUS current DESCRIPTION "The 32 bit number that uniquely identifies the originating router in the Autonomous System." REFERENCE "OSPF Version 2, Appendix C.1 Global parameters" ::= { ospfLsdbEntry 4 } -- Note that the OSPF Sequence Number is a 32 bit signed -- integer. It starts with the value '80000001'h, -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h -- Thus, a typical sequence number will be very negative. ospfLsdbSequence OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "The sequence number field is a signed 32-bit integer. It is used to detect old and dupli- cate link state advertisements. The space of sequence numbers is linearly ordered. The larger the sequence number the more recent the advertisement." REFERENCE "OSPF Version 2, Section 12.1.6 LS sequence number" ::= { ospfLsdbEntry 5 } ospfLsdbAge OBJECT-TYPE SYNTAX Integer32 -- Should be 0..MaxAge MAX-ACCESS read-only STATUS current DESCRIPTION "This field is the age of the link state adver- tisement in seconds." REFERENCE "OSPF Version 2, Section 12.1.1 LS age" ::= { ospfLsdbEntry 6 } ospfLsdbChecksum OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "This field is the checksum of the complete contents of the advertisement, excepting the age field. The age field is excepted so that an advertisement's age can be incremented without updating the checksum. The checksum used is the same that is used for ISO connec- tionless datagrams; it is commonly referred to as the Fletcher checksum." REFERENCE "OSPF Version 2, Section 12.1.7 LS checksum" ::= { ospfLsdbEntry 7 } ospfLsdbAdvertisement OBJECT-TYPE SYNTAX OCTET STRING (SIZE (1..65535)) MAX-ACCESS read-only STATUS current DESCRIPTION "The entire Link State Advertisement, including its header." REFERENCE "OSPF Version 2, Section 12 Link State Adver- tisements" ::= { ospfLsdbEntry 8 } -- Address Range Table -- The Address Range Table acts as an adjunct to the Area -- Table; It describes those Address Range Summaries that -- are configured to be propagated from an Area to reduce -- the amount of information about it which is known beyond -- its borders. ospfAreaRangeTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfAreaRangeEntry MAX-ACCESS not-accessible STATUS obsolete DESCRIPTION "A range if IP addresses specified by an IP address/IP network mask pair. For example, class B address range of X.X.X.X with a network mask of 255.255.0.0 includes all IP addresses from X.X.0.0 to X.X.255.255" REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospf 5 } ospfAreaRangeEntry OBJECT-TYPE SYNTAX OspfAreaRangeEntry MAX-ACCESS not-accessible STATUS obsolete DESCRIPTION "A range if IP addresses specified by an IP address/IP network mask pair. For example, class B address range of X.X.X.X with a network mask of 255.255.0.0 includes all IP addresses from X.X.0.0 to X.X.255.255" REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" INDEX { ospfAreaRangeAreaId, ospfAreaRangeNet } ::= { ospfAreaRangeTable 1 } OspfAreaRangeEntry ::= SEQUENCE { ospfAreaRangeAreaId AreaID, ospfAreaRangeNet IpAddress, ospfAreaRangeMask IpAddress, ospfAreaRangeStatus RowStatus, ospfAreaRangeEffect INTEGER } ospfAreaRangeAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The Area the Address Range is to be found within." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaRangeEntry 1 } ospfAreaRangeNet OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The IP Address of the Net or Subnet indicated by the range." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaRangeEntry 2 } ospfAreaRangeMask OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-create STATUS obsolete DESCRIPTION "The Subnet Mask that pertains to the Net or Subnet." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaRangeEntry 3 } ospfAreaRangeStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS obsolete DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfAreaRangeEntry 4 } ospfAreaRangeEffect OBJECT-TYPE SYNTAX INTEGER { advertiseMatching (1), doNotAdvertiseMatching (2) } MAX-ACCESS read-create STATUS obsolete DESCRIPTION "Subnets subsumed by ranges either trigger the advertisement of the indicated summary (adver- tiseMatching), or result in the subnet's not being advertised at all outside the area." DEFVAL { advertiseMatching } ::= { ospfAreaRangeEntry 5 } -- OSPF Host Table -- The Host/Metric Table indicates what hosts are directly -- attached to the Router, and what metrics and types of -- service should be advertised for them. ospfHostTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfHostEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The list of Hosts, and their metrics, that the router will advertise as host routes." REFERENCE "OSPF Version 2, Appendix C.6 Host route param- eters" ::= { ospf 6 } ospfHostEntry OBJECT-TYPE SYNTAX OspfHostEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A metric to be advertised, for a given type of service, when a given host is reachable." INDEX { ospfHostIpAddress, ospfHostTOS } ::= { ospfHostTable 1 } OspfHostEntry ::= SEQUENCE { ospfHostIpAddress IpAddress, ospfHostTOS TOSType, ospfHostMetric Metric, ospfHostStatus RowStatus, ospfHostAreaID AreaID } ospfHostIpAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of the Host." REFERENCE "OSPF Version 2, Appendix C.6 Host route parame- ters" ::= { ospfHostEntry 1 } ospfHostTOS OBJECT-TYPE SYNTAX TOSType MAX-ACCESS read-only STATUS current DESCRIPTION "The Type of Service of the route being config- ured." REFERENCE "OSPF Version 2, Appendix C.6 Host route parame- ters" ::= { ospfHostEntry 2 } ospfHostMetric OBJECT-TYPE SYNTAX Metric MAX-ACCESS read-create STATUS current DESCRIPTION "The Metric to be advertised." REFERENCE "OSPF Version 2, Appendix C.6 Host route parame- ters" ::= { ospfHostEntry 3 } ospfHostStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfHostEntry 4 } ospfHostAreaID OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The Area the Host Entry is to be found within. By default, the area that a subsuming OSPF in- terface is in, or 0.0.0.0" REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfHostEntry 5 } -- OSPF Interface Table -- The OSPF Interface Table augments the ipAddrTable -- with OSPF specific information. ospfIfTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfIfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The OSPF Interface Table describes the inter- faces from the viewpoint of OSPF." REFERENCE "OSPF Version 2, Appendix C.3 Router interface parameters" ::= { ospf 7 } ospfIfEntry OBJECT-TYPE SYNTAX OspfIfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The OSPF Interface Entry describes one inter- face from the viewpoint of OSPF." INDEX { ospfIfIpAddress, ospfAddressLessIf } ::= { ospfIfTable 1 } OspfIfEntry ::= SEQUENCE { ospfIfIpAddress IpAddress, ospfAddressLessIf Integer32, ospfIfAreaId AreaID, ospfIfType INTEGER, ospfIfAdminStat Status, ospfIfRtrPriority DesignatedRouterPriority, ospfIfTransitDelay UpToMaxAge, ospfIfRetransInterval UpToMaxAge, ospfIfHelloInterval HelloRange, ospfIfRtrDeadInterval PositiveInteger, ospfIfPollInterval PositiveInteger, ospfIfState INTEGER, ospfIfDesignatedRouter IpAddress, ospfIfBackupDesignatedRouter IpAddress, ospfIfEvents Counter32, ospfIfAuthType INTEGER, ospfIfAuthKey OCTET STRING, ospfIfStatus RowStatus, ospfIfMulticastForwarding INTEGER, ospfIfDemand TruthValue } ospfIfIpAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address of this OSPF interface." ::= { ospfIfEntry 1 } ospfAddressLessIf OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "For the purpose of easing the instancing of addressed and addressless interfaces; This variable takes the value 0 on interfaces with IP Addresses, and the corresponding value of ifIndex for interfaces having no IP Address." ::= { ospfIfEntry 2 } ospfIfAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-create STATUS current DESCRIPTION "A 32-bit integer uniquely identifying the area to which the interface connects. Area ID 0.0.0.0 is used for the OSPF backbone." DEFVAL { '00000000'H } -- 0.0.0.0 ::= { ospfIfEntry 3 } ospfIfType OBJECT-TYPE SYNTAX INTEGER { broadcast (1), nbma (2), pointToPoint (3), pointToMultipoint (5) } MAX-ACCESS read-create STATUS current DESCRIPTION "The OSPF interface type. By way of a default, this field may be intuited from the corresponding value of ifType. Broad- cast LANs, such as Ethernet and IEEE 802.5, take the value 'broadcast', X.25 and similar technologies take the value 'nbma', and links that are definitively point to point take the value 'pointToPoint'." ::= { ospfIfEntry 4 } ospfIfAdminStat OBJECT-TYPE SYNTAX Status MAX-ACCESS read-create STATUS current DESCRIPTION "The OSPF interface's administrative status. The value formed on the interface, and the in- terface will be advertised as an internal route to some area. The value 'disabled' denotes that the interface is external to OSPF." DEFVAL { enabled } ::= { ospfIfEntry 5 } ospfIfRtrPriority OBJECT-TYPE SYNTAX DesignatedRouterPriority MAX-ACCESS read-create STATUS current DESCRIPTION "The priority of this interface. Used in multi-access networks, this field is used in the designated router election algorithm. The value 0 signifies that the router is not eligi- ble to become the designated router on this particular network. In the event of a tie in this value, routers will use their Router ID as a tie breaker." DEFVAL { 1 } ::= { ospfIfEntry 6 } ospfIfTransitDelay OBJECT-TYPE SYNTAX UpToMaxAge MAX-ACCESS read-create STATUS current DESCRIPTION "The estimated number of seconds it takes to transmit a link state update packet over this interface." DEFVAL { 1 } ::= { ospfIfEntry 7 } ospfIfRetransInterval OBJECT-TYPE SYNTAX UpToMaxAge MAX-ACCESS read-create STATUS current DESCRIPTION "The number of seconds between link-state ad- vertisement retransmissions, for adjacencies belonging to this interface. This value is also used when retransmitting database descrip- tion and link-state request packets." DEFVAL { 5 } ::= { ospfIfEntry 8 } ospfIfHelloInterval OBJECT-TYPE SYNTAX HelloRange MAX-ACCESS read-create STATUS current DESCRIPTION "The length of time, in seconds, between the Hello packets that the router sends on the in- terface. This value must be the same for all routers attached to a common network." DEFVAL { 10 } ::= { ospfIfEntry 9 } ospfIfRtrDeadInterval OBJECT-TYPE SYNTAX PositiveInteger MAX-ACCESS read-create STATUS current DESCRIPTION "The number of seconds that a router's Hello packets have not been seen before it's neigh- bors declare the router down. This should be some multiple of the Hello interval. This value must be the same for all routers attached to a common network." DEFVAL { 40 } ::= { ospfIfEntry 10 } ospfIfPollInterval OBJECT-TYPE SYNTAX PositiveInteger MAX-ACCESS read-create STATUS current DESCRIPTION "The larger time interval, in seconds, between the Hello packets sent to an inactive non- broadcast multi- access neighbor." DEFVAL { 120 } ::= { ospfIfEntry 11 } ospfIfState OBJECT-TYPE SYNTAX INTEGER { down (1), loopback (2), waiting (3), pointToPoint (4), designatedRouter (5), backupDesignatedRouter (6), otherDesignatedRouter (7) } MAX-ACCESS read-only STATUS current DESCRIPTION "The OSPF Interface State." DEFVAL { down } ::= { ospfIfEntry 12 } ospfIfDesignatedRouter OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of the Designated Router." DEFVAL { '00000000'H } -- 0.0.0.0 ::= { ospfIfEntry 13 } ospfIfBackupDesignatedRouter OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of the Backup Designated Router." DEFVAL { '00000000'H } -- 0.0.0.0 ::= { ospfIfEntry 14 } ospfIfEvents OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of times this OSPF interface has changed its state, or an error has occurred." ::= { ospfIfEntry 15 } ospfIfAuthKey OBJECT-TYPE SYNTAX OCTET STRING (SIZE (0..256)) MAX-ACCESS read-create STATUS current DESCRIPTION "The Authentication Key. If the Area's Author- ization Type is simplePassword, and the key length is shorter than 8 octets, the agent will left adjust and zero fill to 8 octets. Note that unauthenticated interfaces need no authentication key, and simple password authen- tication cannot use a key of more than 8 oc- tets. Larger keys are useful only with authen- tication mechanisms not specified in this docu- ment. When read, ospfIfAuthKey always returns an Oc- tet String of length zero." REFERENCE "OSPF Version 2, Section 9 The Interface Data Structure" DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 ::= { ospfIfEntry 16 } ospfIfStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfIfEntry 17 } ospfIfMulticastForwarding OBJECT-TYPE SYNTAX INTEGER { blocked (1), -- no multicast forwarding multicast (2), -- using multicast address unicast (3) -- to each OSPF neighbor } MAX-ACCESS read-create STATUS current DESCRIPTION "The way multicasts should forwarded on this interface; not forwarded, forwarded as data link multicasts, or forwarded as data link uni- casts. Data link multicasting is not meaning- ful on point to point and NBMA interfaces, and setting ospfMulticastForwarding to 0 effective- ly disables all multicast forwarding." DEFVAL { blocked } ::= { ospfIfEntry 18 } ospfIfDemand OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-create STATUS current DESCRIPTION "Indicates whether Demand OSPF procedures (hel- lo suppression to FULL neighbors and setting the DoNotAge flag on proogated LSAs) should be per- formed on this interface." DEFVAL { false } ::= { ospfIfEntry 19 } ospfIfAuthType OBJECT-TYPE SYNTAX INTEGER (0..255) -- none (0), -- simplePassword (1) -- md5 (2) -- reserved for specification by IANA (> 2) MAX-ACCESS read-create STATUS current DESCRIPTION "The authentication type specified for an in- terface. Additional authentication types may be assigned locally." REFERENCE "OSPF Version 2, Appendix E Authentication" DEFVAL { 0 } -- no authentication, by default ::= { ospfIfEntry 20 } -- OSPF Interface Metric Table -- The Metric Table describes the metrics to be advertised -- for a specified interface at the various types of service. -- As such, this table is an adjunct of the OSPF Interface -- Table. -- Types of service, as defined by RFC 791, have the ability -- to request low delay, high bandwidth, or reliable linkage. -- For the purposes of this specification, the measure of -- bandwidth -- Metric = 10^8 / ifSpeed -- is the default value. For multiple link interfaces, note -- that ifSpeed is the sum of the individual link speeds. -- This yields a number having the following typical values: -- Network Type/bit rate Metric -- >= 100 MBPS 1 -- Ethernet/802.3 10 -- E1 48 -- T1 (ESF) 65 -- 64 KBPS 1562 -- 56 KBPS 1785 -- 19.2 KBPS 5208 -- 9.6 KBPS 10416 -- Routes that are not specified use the default (TOS 0) metric ospfIfMetricTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfIfMetricEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The TOS metrics for a non-virtual interface identified by the interface index." REFERENCE "OSPF Version 2, Appendix C.3 Router interface parameters" ::= { ospf 8 } ospfIfMetricEntry OBJECT-TYPE SYNTAX OspfIfMetricEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A particular TOS metric for a non-virtual in- terface identified by the interface index." REFERENCE "OSPF Version 2, Appendix C.3 Router interface parameters" INDEX { ospfIfMetricIpAddress, ospfIfMetricAddressLessIf, ospfIfMetricTOS } ::= { ospfIfMetricTable 1 } OspfIfMetricEntry ::= SEQUENCE { ospfIfMetricIpAddress IpAddress, ospfIfMetricAddressLessIf Integer32, ospfIfMetricTOS TOSType, ospfIfMetricValue Metric, ospfIfMetricStatus RowStatus } ospfIfMetricIpAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address of this OSPF interface. On row creation, this can be derived from the in- stance." ::= { ospfIfMetricEntry 1 } ospfIfMetricAddressLessIf OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "For the purpose of easing the instancing of addressed and addressless interfaces; This variable takes the value 0 on interfaces with IP Addresses, and the value of ifIndex for in- terfaces having no IP Address. On row crea- tion, this can be derived from the instance." ::= { ospfIfMetricEntry 2 } ospfIfMetricTOS OBJECT-TYPE SYNTAX TOSType MAX-ACCESS read-only STATUS current DESCRIPTION "The type of service metric being referenced. On row creation, this can be derived from the instance." ::= { ospfIfMetricEntry 3 } ospfIfMetricValue OBJECT-TYPE SYNTAX Metric MAX-ACCESS read-create STATUS current DESCRIPTION "The metric of using this type of service on this interface. The default value of the TOS 0 Metric is 10^8 / ifSpeed." ::= { ospfIfMetricEntry 4 } ospfIfMetricStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfIfMetricEntry 5 } -- OSPF Virtual Interface Table -- The Virtual Interface Table describes the virtual -- links that the OSPF Process is configured to -- carry on. ospfVirtIfTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfVirtIfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information about this router's virtual inter- faces." REFERENCE "OSPF Version 2, Appendix C.4 Virtual link parameters" ::= { ospf 9 } ospfVirtIfEntry OBJECT-TYPE SYNTAX OspfVirtIfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information about a single Virtual Interface." INDEX { ospfVirtIfAreaId, ospfVirtIfNeighbor } ::= { ospfVirtIfTable 1 } OspfVirtIfEntry ::= SEQUENCE { ospfVirtIfAreaId AreaID, ospfVirtIfNeighbor RouterID, ospfVirtIfTransitDelay UpToMaxAge, ospfVirtIfRetransInterval UpToMaxAge, ospfVirtIfHelloInterval HelloRange, ospfVirtIfRtrDeadInterval PositiveInteger, ospfVirtIfState INTEGER, ospfVirtIfEvents Counter32, ospfVirtIfAuthType INTEGER, ospfVirtIfAuthKey OCTET STRING, ospfVirtIfStatus RowStatus } ospfVirtIfAreaId OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The Transit Area that the Virtual Link traverses. By definition, this is not 0.0.0.0" ::= { ospfVirtIfEntry 1 } ospfVirtIfNeighbor OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-only STATUS current DESCRIPTION "The Router ID of the Virtual Neighbor." ::= { ospfVirtIfEntry 2 } ospfVirtIfTransitDelay OBJECT-TYPE SYNTAX UpToMaxAge MAX-ACCESS read-create STATUS current DESCRIPTION "The estimated number of seconds it takes to transmit a link- state update packet over this interface." DEFVAL { 1 } ::= { ospfVirtIfEntry 3 } ospfVirtIfRetransInterval OBJECT-TYPE SYNTAX UpToMaxAge MAX-ACCESS read-create STATUS current DESCRIPTION "The number of seconds between link-state ad- vertisement retransmissions, for adjacencies belonging to this interface. This value is also used when retransmitting database descrip- tion and link-state request packets. This value should be well over the expected round- trip time." DEFVAL { 5 } ::= { ospfVirtIfEntry 4 } ospfVirtIfHelloInterval OBJECT-TYPE SYNTAX HelloRange MAX-ACCESS read-create STATUS current DESCRIPTION "The length of time, in seconds, between the Hello packets that the router sends on the in- terface. This value must be the same for the virtual neighbor." DEFVAL { 10 } ::= { ospfVirtIfEntry 5 } ospfVirtIfRtrDeadInterval OBJECT-TYPE SYNTAX PositiveInteger MAX-ACCESS read-create STATUS current DESCRIPTION "The number of seconds that a router's Hello packets have not been seen before it's neigh- bors declare the router down. This should be some multiple of the Hello interval. This value must be the same for the virtual neigh- bor." DEFVAL { 60 } ::= { ospfVirtIfEntry 6 } ospfVirtIfState OBJECT-TYPE SYNTAX INTEGER { down (1), -- these use the same encoding pointToPoint (4) -- as the ospfIfTable } MAX-ACCESS read-only STATUS current DESCRIPTION "OSPF virtual interface states." DEFVAL { down } ::= { ospfVirtIfEntry 7 } ospfVirtIfEvents OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of state changes or error events on this Virtual Link" ::= { ospfVirtIfEntry 8 } ospfVirtIfAuthKey OBJECT-TYPE SYNTAX OCTET STRING (SIZE(0..256)) MAX-ACCESS read-create STATUS current DESCRIPTION "If Authentication Type is simplePassword, the device will left adjust and zero fill to 8 oc- tets. Note that unauthenticated interfaces need no authentication key, and simple password authen- tication cannot use a key of more than 8 oc- tets. Larger keys are useful only with authen- tication mechanisms not specified in this docu- ment. When read, ospfVifAuthKey always returns a string of length zero." REFERENCE "OSPF Version 2, Section 9 The Interface Data Structure" DEFVAL { '0000000000000000'H } -- 0.0.0.0.0.0.0.0 ::= { ospfVirtIfEntry 9 } ospfVirtIfStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfVirtIfEntry 10 } ospfVirtIfAuthType OBJECT-TYPE SYNTAX INTEGER (0..255) -- none (0), -- simplePassword (1) -- md5 (2) -- reserved for specification by IANA (> 2) MAX-ACCESS read-create STATUS current DESCRIPTION "The authentication type specified for a virtu- al interface. Additional authentication types may be assigned locally." REFERENCE "OSPF Version 2, Appendix E Authentication" DEFVAL { 0 } -- no authentication, by default ::= { ospfVirtIfEntry 11 } -- OSPF Neighbor Table -- The OSPF Neighbor Table describes all neighbors in -- the locality of the subject router. ospfNbrTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfNbrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A table of non-virtual neighbor information." REFERENCE "OSPF Version 2, Section 10 The Neighbor Data Structure" ::= { ospf 10 } ospfNbrEntry OBJECT-TYPE SYNTAX OspfNbrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The information regarding a single neighbor." REFERENCE "OSPF Version 2, Section 10 The Neighbor Data Structure" INDEX { ospfNbrIpAddr, ospfNbrAddressLessIndex } ::= { ospfNbrTable 1 } OspfNbrEntry ::= SEQUENCE { ospfNbrIpAddr IpAddress, ospfNbrAddressLessIndex InterfaceIndex, ospfNbrRtrId RouterID, ospfNbrOptions Integer32, ospfNbrPriority DesignatedRouterPriority, ospfNbrState INTEGER, ospfNbrEvents Counter32, ospfNbrLsRetransQLen Gauge32, ospfNbmaNbrStatus RowStatus, ospfNbmaNbrPermanence INTEGER, ospfNbrHelloSuppressed TruthValue } ospfNbrIpAddr OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address this neighbor is using in its IP Source Address. Note that, on addressless links, this will not be 0.0.0.0, but the ad- dress of another of the neighbor's interfaces." ::= { ospfNbrEntry 1 } ospfNbrAddressLessIndex OBJECT-TYPE SYNTAX InterfaceIndex MAX-ACCESS read-only STATUS current DESCRIPTION "On an interface having an IP Address, zero. On addressless interfaces, the corresponding value of ifIndex in the Internet Standard MIB. On row creation, this can be derived from the instance." ::= { ospfNbrEntry 2 } ospfNbrRtrId OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-only STATUS current DESCRIPTION "A 32-bit integer (represented as a type IpAd- dress) uniquely identifying the neighboring router in the Autonomous System." DEFVAL { '00000000'H } -- 0.0.0.0 ::= { ospfNbrEntry 3 } ospfNbrOptions OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "A Bit Mask corresponding to the neighbor's op- tions field. Bit 0, if set, indicates that the system will operate on Type of Service metrics other than TOS 0. If zero, the neighbor will ignore all metrics except the TOS 0 metric. Bit 1, if set, indicates that the associated area accepts and operates on external informa- tion; if zero, it is a stub area. Bit 2, if set, indicates that the system is ca- pable of routing IP Multicast datagrams; i.e., that it implements the Multicast Extensions to OSPF. Bit 3, if set, indicates that the associated area is an NSSA. These areas are capable of carrying type 7 external advertisements, which are translated into type 5 external advertise- ments at NSSA borders." REFERENCE "OSPF Version 2, Section 12.1.2 Options" DEFVAL { 0 } ::= { ospfNbrEntry 4 } ospfNbrPriority OBJECT-TYPE SYNTAX DesignatedRouterPriority MAX-ACCESS read-create STATUS current DESCRIPTION "The priority of this neighbor in the designat- ed router election algorithm. The value 0 sig- nifies that the neighbor is not eligible to be- come the designated router on this particular network." DEFVAL { 1 } ::= { ospfNbrEntry 5 } ospfNbrState OBJECT-TYPE SYNTAX INTEGER { down (1), attempt (2), init (3), twoWay (4), exchangeStart (5), exchange (6), loading (7), full (8) } MAX-ACCESS read-only STATUS current DESCRIPTION "The State of the relationship with this Neigh- bor." REFERENCE "OSPF Version 2, Section 10.1 Neighbor States" DEFVAL { down } ::= { ospfNbrEntry 6 } ospfNbrEvents OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of times this neighbor relationship has changed state, or an error has occurred." ::= { ospfNbrEntry 7 } ospfNbrLsRetransQLen OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The current length of the retransmission queue." ::= { ospfNbrEntry 8 } ospfNbmaNbrStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfNbrEntry 9 } ospfNbmaNbrPermanence OBJECT-TYPE SYNTAX INTEGER { dynamic (1), -- learned through protocol permanent (2) -- configured address } MAX-ACCESS read-only STATUS current DESCRIPTION "This variable displays the status of the en- try. 'dynamic' and 'permanent' refer to how the neighbor became known." DEFVAL { permanent } ::= { ospfNbrEntry 10 } ospfNbrHelloSuppressed OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-only STATUS current DESCRIPTION "Indicates whether Hellos are being suppressed to the neighbor" ::= { ospfNbrEntry 11 } -- OSPF Virtual Neighbor Table -- This table describes all virtual neighbors. -- Since Virtual Links are configured in the -- virtual interface table, this table is read-only. ospfVirtNbrTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfVirtNbrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A table of virtual neighbor information." REFERENCE "OSPF Version 2, Section 15 Virtual Links" ::= { ospf 11 } ospfVirtNbrEntry OBJECT-TYPE SYNTAX OspfVirtNbrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Virtual neighbor information." INDEX { ospfVirtNbrArea, ospfVirtNbrRtrId } ::= { ospfVirtNbrTable 1 } OspfVirtNbrEntry ::= SEQUENCE { ospfVirtNbrArea AreaID, ospfVirtNbrRtrId RouterID, ospfVirtNbrIpAddr IpAddress, ospfVirtNbrOptions Integer32, ospfVirtNbrState INTEGER, ospfVirtNbrEvents Counter32, ospfVirtNbrLsRetransQLen Gauge32, ospfVirtNbrHelloSuppressed TruthValue } ospfVirtNbrArea OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The Transit Area Identifier." ::= { ospfVirtNbrEntry 1 } ospfVirtNbrRtrId OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-only STATUS current DESCRIPTION "A 32-bit integer uniquely identifying the neighboring router in the Autonomous System." ::= { ospfVirtNbrEntry 2 } ospfVirtNbrIpAddr OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address this Virtual Neighbor is us- ing." ::= { ospfVirtNbrEntry 3 } ospfVirtNbrOptions OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "A Bit Mask corresponding to the neighbor's op- tions field. Bit 1, if set, indicates that the system will operate on Type of Service metrics other than TOS 0. If zero, the neighbor will ignore all metrics except the TOS 0 metric. Bit 2, if set, indicates that the system is Network Multicast capable; ie, that it imple- ments OSPF Multicast Routing." ::= { ospfVirtNbrEntry 4 } ospfVirtNbrState OBJECT-TYPE SYNTAX INTEGER { down (1), attempt (2), init (3), twoWay (4), exchangeStart (5), exchange (6), loading (7), full (8) } MAX-ACCESS read-only STATUS current DESCRIPTION "The state of the Virtual Neighbor Relation- ship." ::= { ospfVirtNbrEntry 5 } ospfVirtNbrEvents OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of times this virtual link has changed its state, or an error has occurred." ::= { ospfVirtNbrEntry 6 } ospfVirtNbrLsRetransQLen OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "The current length of the retransmission queue." ::= { ospfVirtNbrEntry 7 } ospfVirtNbrHelloSuppressed OBJECT-TYPE SYNTAX TruthValue MAX-ACCESS read-only STATUS current DESCRIPTION "Indicates whether Hellos are being suppressed to the neighbor" ::= { ospfVirtNbrEntry 8 } -- OSPF Link State Database, External -- The Link State Database contains the Link State -- Advertisements from throughout the areas that the -- device is attached to. -- This table is identical to the OSPF LSDB Table in -- format, but contains only External Link State -- Advertisements. The purpose is to allow external -- LSAs to be displayed once for the router rather -- than once in each non-stub area. ospfExtLsdbTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfExtLsdbEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The OSPF Process's Links State Database." REFERENCE "OSPF Version 2, Section 12 Link State Adver- tisements" ::= { ospf 12 } ospfExtLsdbEntry OBJECT-TYPE SYNTAX OspfExtLsdbEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A single Link State Advertisement." INDEX { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId } ::= { ospfExtLsdbTable 1 } OspfExtLsdbEntry ::= SEQUENCE { ospfExtLsdbType INTEGER, ospfExtLsdbLsid IpAddress, ospfExtLsdbRouterId RouterID, ospfExtLsdbSequence Integer32, ospfExtLsdbAge Integer32, ospfExtLsdbChecksum Integer32, ospfExtLsdbAdvertisement OCTET STRING } ospfExtLsdbType OBJECT-TYPE SYNTAX INTEGER { asExternalLink (5) } MAX-ACCESS read-only STATUS current DESCRIPTION "The type of the link state advertisement. Each link state type has a separate advertise- ment format." REFERENCE "OSPF Version 2, Appendix A.4.1 The Link State Advertisement header" ::= { ospfExtLsdbEntry 1 } ospfExtLsdbLsid OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The Link State ID is an LS Type Specific field containing either a Router ID or an IP Address; it identifies the piece of the routing domain that is being described by the advertisement." REFERENCE "OSPF Version 2, Section 12.1.4 Link State ID" ::= { ospfExtLsdbEntry 2 } ospfExtLsdbRouterId OBJECT-TYPE SYNTAX RouterID MAX-ACCESS read-only STATUS current DESCRIPTION "The 32 bit number that uniquely identifies the originating router in the Autonomous System." REFERENCE "OSPF Version 2, Appendix C.1 Global parameters" ::= { ospfExtLsdbEntry 3 } -- Note that the OSPF Sequence Number is a 32 bit signed -- integer. It starts with the value '80000001'h, -- or -'7FFFFFFF'h, and increments until '7FFFFFFF'h -- Thus, a typical sequence number will be very negative. ospfExtLsdbSequence OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "The sequence number field is a signed 32-bit integer. It is used to detect old and dupli- cate link state advertisements. The space of sequence numbers is linearly ordered. The larger the sequence number the more recent the advertisement." REFERENCE "OSPF Version 2, Section 12.1.6 LS sequence number" ::= { ospfExtLsdbEntry 4 } ospfExtLsdbAge OBJECT-TYPE SYNTAX Integer32 -- Should be 0..MaxAge MAX-ACCESS read-only STATUS current DESCRIPTION "This field is the age of the link state adver- tisement in seconds." REFERENCE "OSPF Version 2, Section 12.1.1 LS age" ::= { ospfExtLsdbEntry 5 } ospfExtLsdbChecksum OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "This field is the checksum of the complete contents of the advertisement, excepting the age field. The age field is excepted so that an advertisement's age can be incremented without updating the checksum. The checksum used is the same that is used for ISO connec- tionless datagrams; it is commonly referred to as the Fletcher checksum." REFERENCE "OSPF Version 2, Section 12.1.7 LS checksum" ::= { ospfExtLsdbEntry 6 } ospfExtLsdbAdvertisement OBJECT-TYPE SYNTAX OCTET STRING (SIZE(36)) MAX-ACCESS read-only STATUS current DESCRIPTION "The entire Link State Advertisement, including its header." REFERENCE "OSPF Version 2, Section 12 Link State Adver- tisements" ::= { ospfExtLsdbEntry 7 } -- OSPF Use of the CIDR Route Table ospfRouteGroup OBJECT IDENTIFIER ::= { ospf 13 } -- The IP Forwarding Table defines a number of objects for use by -- the routing protocol to externalize its information. Most of -- the variables (ipForwardDest, ipForwardMask, ipForwardPolicy, -- ipForwardNextHop, ipForwardIfIndex, ipForwardType, -- ipForwardProto, ipForwardAge, and ipForwardNextHopAS) are -- defined there. -- Those that leave some discretion are defined here. -- ipCidrRouteProto is, of course, ospf (13). -- ipCidrRouteAge is the time since the route was first calculated, -- as opposed to the time since the last SPF run. -- ipCidrRouteInfo is an OBJECT IDENTIFIER for use by the routing -- protocol. The following values shall be found there depending -- on the way the route was calculated. ospfIntraArea OBJECT IDENTIFIER ::= { ospfRouteGroup 1 } ospfInterArea OBJECT IDENTIFIER ::= { ospfRouteGroup 2 } ospfExternalType1 OBJECT IDENTIFIER ::= { ospfRouteGroup 3 } ospfExternalType2 OBJECT IDENTIFIER ::= { ospfRouteGroup 4 } -- ipCidrRouteMetric1 is, by definition, the primary routing -- metric. Therefore, it should be the metric that route -- selection is based on. For intra-area and inter-area routes, -- it is an OSPF metric. For External Type 1 (comparable value) -- routes, it is an OSPF metric plus the External Metric. For -- external Type 2 (non-comparable value) routes, it is the -- external metric. -- ipCidrRouteMetric2 is, by definition, a secondary routing -- metric. Therefore, it should be the metric that breaks a tie -- among routes having equal metric1 values and the same -- calculation rule. For intra-area, inter-area routes, and -- External Type 1 (comparable value) routes, it is unused. For -- external Type 2 (non-comparable value) routes, it is the metric -- to the AS border router. -- ipCidrRouteMetric3, ipCidrRouteMetric4, and ipCidrRouteMetric5 are -- unused. -- -- The OSPF Area Aggregate Table -- -- This table replaces the OSPF Area Summary Table, being an -- extension of that for CIDR routers. ospfAreaAggregateTable OBJECT-TYPE SYNTAX SEQUENCE OF OspfAreaAggregateEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A range of IP addresses specified by an IP address/IP network mask pair. For example, class B address range of X.X.X.X with a network mask of 255.255.0.0 includes all IP addresses from X.X.0.0 to X.X.255.255. Note that if ranges are configured such that one range sub- sumes another range (e.g., 10.0.0.0 mask 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the most specific match is the preferred one." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospf 14 } ospfAreaAggregateEntry OBJECT-TYPE SYNTAX OspfAreaAggregateEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A range of IP addresses specified by an IP address/IP network mask pair. For example, class B address range of X.X.X.X with a network mask of 255.255.0.0 includes all IP addresses from X.X.0.0 to X.X.255.255. Note that if ranges are range configured such that one range subsumes another range (e.g., 10.0.0.0 mask 255.0.0.0 and 10.1.0.0 mask 255.255.0.0), the most specific match is the preferred one." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" INDEX { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType, ospfAreaAggregateNet, ospfAreaAggregateMask } ::= { ospfAreaAggregateTable 1 } OspfAreaAggregateEntry ::= SEQUENCE { ospfAreaAggregateAreaID AreaID, ospfAreaAggregateLsdbType INTEGER, ospfAreaAggregateNet IpAddress, ospfAreaAggregateMask IpAddress, ospfAreaAggregateStatus RowStatus, ospfAreaAggregateEffect INTEGER } ospfAreaAggregateAreaID OBJECT-TYPE SYNTAX AreaID MAX-ACCESS read-only STATUS current DESCRIPTION "The Area the Address Aggregate is to be found within." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaAggregateEntry 1 } ospfAreaAggregateLsdbType OBJECT-TYPE SYNTAX INTEGER { summaryLink (3), nssaExternalLink (7) } MAX-ACCESS read-only STATUS current DESCRIPTION "The type of the Address Aggregate. This field specifies the Lsdb type that this Address Ag- gregate applies to." REFERENCE "OSPF Version 2, Appendix A.4.1 The Link State Advertisement header" ::= { ospfAreaAggregateEntry 2 } ospfAreaAggregateNet OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of the Net or Subnet indicated by the range." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaAggregateEntry 3 } ospfAreaAggregateMask OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The Subnet Mask that pertains to the Net or Subnet." REFERENCE "OSPF Version 2, Appendix C.2 Area parameters" ::= { ospfAreaAggregateEntry 4 } ospfAreaAggregateStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "This variable displays the status of the en- try. Setting it to 'invalid' has the effect of rendering it inoperative. The internal effect (row removal) is implementation dependent." ::= { ospfAreaAggregateEntry 5 } ospfAreaAggregateEffect OBJECT-TYPE SYNTAX INTEGER { advertiseMatching (1), doNotAdvertiseMatching (2) } MAX-ACCESS read-create STATUS current DESCRIPTION "Subnets subsumed by ranges either trigger the advertisement of the indicated aggregate (ad- vertiseMatching), or result in the subnet's not being advertised at all outside the area." DEFVAL { advertiseMatching } ::= { ospfAreaAggregateEntry 6 } -- conformance information ospfConformance OBJECT IDENTIFIER ::= { ospf 15 } ospfGroups OBJECT IDENTIFIER ::= { ospfConformance 1 } ospfCompliances OBJECT IDENTIFIER ::= { ospfConformance 2 } -- compliance statements ospfCompliance MODULE-COMPLIANCE STATUS current DESCRIPTION "The compliance statement " MODULE -- this module MANDATORY-GROUPS { ospfBasicGroup, ospfAreaGroup, ospfStubAreaGroup, ospfIfGroup, ospfIfMetricGroup, ospfVirtIfGroup, ospfNbrGroup, ospfVirtNbrGroup, ospfAreaAggregateGroup } ::= { ospfCompliances 1 } -- units of conformance ospfBasicGroup OBJECT-GROUP OBJECTS { ospfRouterId, ospfAdminStat, ospfVersionNumber, ospfAreaBdrRtrStatus, ospfASBdrRtrStatus, ospfExternLsaCount, ospfExternLsaCksumSum, ospfTOSSupport, ospfOriginateNewLsas, ospfRxNewLsas, ospfExtLsdbLimit, ospfMulticastExtensions, ospfExitOverflowInterval, ospfDemandExtensions } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 1 } ospfAreaGroup OBJECT-GROUP OBJECTS { ospfAreaId, ospfImportAsExtern, ospfSpfRuns, ospfAreaBdrRtrCount, ospfAsBdrRtrCount, ospfAreaLsaCount, ospfAreaLsaCksumSum, ospfAreaSummary, ospfAreaStatus } STATUS current DESCRIPTION "These objects are required for OSPF systems supporting areas." ::= { ospfGroups 2 } ospfStubAreaGroup OBJECT-GROUP OBJECTS { ospfStubAreaId, ospfStubTOS, ospfStubMetric, ospfStubStatus, ospfStubMetricType } STATUS current DESCRIPTION "These objects are required for OSPF systems supporting stub areas." ::= { ospfGroups 3 } ospfLsdbGroup OBJECT-GROUP OBJECTS { ospfLsdbAreaId, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId, ospfLsdbSequence, ospfLsdbAge, ospfLsdbChecksum, ospfLsdbAdvertisement } STATUS current DESCRIPTION "These objects are required for OSPF systems that display their link state database." ::= { ospfGroups 4 } ospfAreaRangeGroup OBJECT-GROUP OBJECTS { ospfAreaRangeAreaId, ospfAreaRangeNet, ospfAreaRangeMask, ospfAreaRangeStatus, ospfAreaRangeEffect } STATUS obsolete DESCRIPTION "These objects are required for non-CIDR OSPF systems that support multiple areas." ::= { ospfGroups 5 } ospfHostGroup OBJECT-GROUP OBJECTS { ospfHostIpAddress, ospfHostTOS, ospfHostMetric, ospfHostStatus, ospfHostAreaID } STATUS current DESCRIPTION "These objects are required for OSPF systems that support attached hosts." ::= { ospfGroups 6 } ospfIfGroup OBJECT-GROUP OBJECTS { ospfIfIpAddress, ospfAddressLessIf, ospfIfAreaId, ospfIfType, ospfIfAdminStat, ospfIfRtrPriority, ospfIfTransitDelay, ospfIfRetransInterval, ospfIfHelloInterval, ospfIfRtrDeadInterval, ospfIfPollInterval, ospfIfState, ospfIfDesignatedRouter, ospfIfBackupDesignatedRouter, ospfIfEvents, ospfIfAuthType, ospfIfAuthKey, ospfIfStatus, ospfIfMulticastForwarding, ospfIfDemand } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 7 } ospfIfMetricGroup OBJECT-GROUP OBJECTS { ospfIfMetricIpAddress, ospfIfMetricAddressLessIf, ospfIfMetricTOS, ospfIfMetricValue, ospfIfMetricStatus } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 8 } ospfVirtIfGroup OBJECT-GROUP OBJECTS { ospfVirtIfAreaId, ospfVirtIfNeighbor, ospfVirtIfTransitDelay, ospfVirtIfRetransInterval, ospfVirtIfHelloInterval, ospfVirtIfRtrDeadInterval, ospfVirtIfState, ospfVirtIfEvents, ospfVirtIfAuthType, ospfVirtIfAuthKey, ospfVirtIfStatus } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 9 } ospfNbrGroup OBJECT-GROUP OBJECTS { ospfNbrIpAddr, ospfNbrAddressLessIndex, ospfNbrRtrId, ospfNbrOptions, ospfNbrPriority, ospfNbrState, ospfNbrEvents, ospfNbrLsRetransQLen, ospfNbmaNbrStatus, ospfNbmaNbrPermanence, ospfNbrHelloSuppressed } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 10 } ospfVirtNbrGroup OBJECT-GROUP OBJECTS { ospfVirtNbrArea, ospfVirtNbrRtrId, ospfVirtNbrIpAddr, ospfVirtNbrOptions, ospfVirtNbrState, ospfVirtNbrEvents, ospfVirtNbrLsRetransQLen, ospfVirtNbrHelloSuppressed } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 11 } ospfExtLsdbGroup OBJECT-GROUP OBJECTS { ospfExtLsdbType, ospfExtLsdbLsid, ospfExtLsdbRouterId, ospfExtLsdbSequence, ospfExtLsdbAge, ospfExtLsdbChecksum, ospfExtLsdbAdvertisement } STATUS current DESCRIPTION "These objects are required for OSPF systems that display their link state database." ::= { ospfGroups 12 } ospfAreaAggregateGroup OBJECT-GROUP OBJECTS { ospfAreaAggregateAreaID, ospfAreaAggregateLsdbType, ospfAreaAggregateNet, ospfAreaAggregateMask, ospfAreaAggregateStatus, ospfAreaAggregateEffect } STATUS current DESCRIPTION "These objects are required for OSPF systems." ::= { ospfGroups 13 } END quagga-0.99.24.1/ospfd/ospf_main.c0000644000175000017500000001753012476520570013474 00000000000000/* * OSPFd main routine. * Copyright (C) 1998, 99 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "thread.h" #include "prefix.h" #include "linklist.h" #include "if.h" #include "vector.h" #include "vty.h" #include "command.h" #include "filter.h" #include "plist.h" #include "stream.h" #include "log.h" #include "memory.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_vty.h" /* ospfd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, }; struct zebra_privs_t ospfd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; /* Configuration filename and directory. */ char config_default[] = SYSCONFDIR OSPF_DEFAULT_CONFIG; /* OSPFd options. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "apiserver", no_argument, NULL, 'a'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* OSPFd program name */ /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_OSPFD_PID; #ifdef SUPPORT_OSPF_API extern int ospf_apiserver_enable; #endif /* SUPPORT_OSPF_API */ /* Help information display. */ static void __attribute__ ((noreturn)) usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages OSPF.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -a. --apiserver Enable OSPF apiserver\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog (NULL, LOG_INFO, "SIGHUP received"); } /* SIGINT / SIGTERM handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); ospf_terminate (); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t ospf_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* OSPFd main routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = OSPF_VTY_PORT; int daemon_mode = 0; char *config_file = NULL; char *progname; struct thread thread; int dryrun = 0; /* Set umask before anything for security */ umask (0027); #ifdef SUPPORT_OSPF_API /* OSPF apiserver is disabled by default. */ ospf_apiserver_enable = 0; #endif /* SUPPORT_OSPF_API */ /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:avC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ospfd not listening on ospfd port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = OSPF_VTY_PORT; break; case 'u': ospfd_privs.user = optarg; break; case 'g': ospfd_privs.group = optarg; break; #ifdef SUPPORT_OSPF_API case 'a': ospf_apiserver_enable = 1; break; #endif /* SUPPORT_OSPF_API */ case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Invoked by a priviledged user? -- endo. */ if (geteuid () != 0) { errno = EPERM; perror (progname); exit (1); } zlog_default = openzlog (progname, ZLOG_OSPF, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* OSPF master init. */ ospf_master_init (); /* Initializations. */ master = om->master; /* Library inits. */ zprivs_init (&ospfd_privs); signal_init (master, array_size(ospf_signals), ospf_signals); cmd_init (1); debug_init (); vty_init (master); memory_init (); access_list_init (); prefix_list_init (); /* OSPFd inits. */ ospf_if_init (); ospf_zebra_init (); /* OSPF vty inits. */ ospf_vty_init (); ospf_vty_show_init (); ospf_route_map_init (); #ifdef HAVE_SNMP ospf_snmp_init (); #endif /* HAVE_SNMP */ #ifdef HAVE_OPAQUE_LSA ospf_opaque_init (); #endif /* HAVE_OPAQUE_LSA */ /* Need to initialize the default ospf structure, so the interface mode commands can be duly processed if they are received before 'router ospf', when quagga(ospfd) is restarted */ if (!ospf_get()) { zlog_err("OSPF instance init failed: %s", strerror(errno)); exit (1); } /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if (dryrun) return(0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("OSPFd daemon failed: %s", strerror(errno)); exit (1); } /* Process id file create. */ pid_output (pid_file); /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, OSPF_VTYSH_PATH); /* Print banner. */ zlog_notice ("OSPFd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Fetch next active thread. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.24.1/ospfd/ospf_apiserver.c0000644000175000017500000020440212476520570014544 00000000000000/* * Server side of OSPF API. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #ifdef SUPPORT_OSPF_API #ifndef HAVE_OPAQUE_LSA #error "Core Opaque-LSA module must be configured." #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "buffer.h" #include #include "ospfd/ospfd.h" /* for "struct thread_master" */ #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_api.h" #include "ospfd/ospf_apiserver.h" /* This is an implementation of an API to the OSPF daemon that allows * external applications to access the OSPF daemon through socket * connections. The application can use this API to inject its own * opaque LSAs and flood them to other OSPF daemons. Other OSPF * daemons then receive these LSAs and inform applications through the * API by sending a corresponding message. The application can also * register to receive all LSA types (in addition to opaque types) and * use this information to reconstruct the OSPF's LSDB. The OSPF * daemon supports multiple applications concurrently. */ /* List of all active connections. */ struct list *apiserver_list; /* ----------------------------------------------------------- * Functions to lookup interfaces * ----------------------------------------------------------- */ struct ospf_interface * ospf_apiserver_if_lookup_by_addr (struct in_addr address) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf *ospf; if (!(ospf = ospf_lookup ())) return NULL; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4)) return oi; return NULL; } struct ospf_interface * ospf_apiserver_if_lookup_by_ifp (struct interface *ifp) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf *ospf; if (!(ospf = ospf_lookup ())) return NULL; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->ifp == ifp) return oi; return NULL; } /* ----------------------------------------------------------- * Initialization * ----------------------------------------------------------- */ unsigned short ospf_apiserver_getport (void) { struct servent *sp = getservbyname ("ospfapi", "tcp"); return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT; } /* Initialize OSPF API module. Invoked from ospf_opaque_init() */ int ospf_apiserver_init (void) { int fd; int rc = -1; /* Create new socket for synchronous messages. */ fd = ospf_apiserver_serv_sock_family (ospf_apiserver_getport (), AF_INET); if (fd < 0) goto out; /* Schedule new thread that handles accepted connections. */ ospf_apiserver_event (OSPF_APISERVER_ACCEPT, fd, NULL); /* Initialize list that keeps track of all connections. */ apiserver_list = list_new (); /* Register opaque-independent call back functions. These functions are invoked on ISM, NSM changes and LSA update and LSA deletes */ rc = ospf_register_opaque_functab (0 /* all LSAs */, 0 /* all opaque types */, ospf_apiserver_new_if, ospf_apiserver_del_if, ospf_apiserver_ism_change, ospf_apiserver_nsm_change, NULL, NULL, NULL, NULL, /* ospf_apiserver_show_info */ NULL, /* originator_func */ NULL, /* ospf_apiserver_lsa_refresher */ ospf_apiserver_lsa_update, ospf_apiserver_lsa_delete); if (rc != 0) { zlog_warn ("ospf_apiserver_init: Failed to register opaque type [0/0]"); } rc = 0; out: return rc; } /* Terminate OSPF API module. */ void ospf_apiserver_term (void) { struct ospf_apiserver *apiserv; /* Unregister wildcard [0/0] type */ ospf_delete_opaque_functab (0 /* all LSAs */, 0 /* all opaque types */); /* * Free all client instances. ospf_apiserver_free removes the node * from the list, so we examine the head of the list anew each time. */ while ( apiserver_list && (apiserv = listgetdata (listhead (apiserver_list))) != NULL) ospf_apiserver_free (apiserv); /* Free client list itself */ if (apiserver_list) list_delete (apiserver_list); /* Free wildcard list */ /* XXX */ } static struct ospf_apiserver * lookup_apiserver (u_char lsa_type, u_char opaque_type) { struct listnode *n1, *n2; struct registered_opaque_type *r; struct ospf_apiserver *apiserv, *found = NULL; /* XXX: this approaches O(n**2) */ for (ALL_LIST_ELEMENTS_RO (apiserver_list, n1, apiserv)) { for (ALL_LIST_ELEMENTS_RO (apiserv->opaque_types, n2, r)) if (r->lsa_type == lsa_type && r->opaque_type == opaque_type) { found = apiserv; goto out; } } out: return found; } static struct ospf_apiserver * lookup_apiserver_by_lsa (struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct ospf_apiserver *found = NULL; if (IS_OPAQUE_LSA (lsah->type)) { found = lookup_apiserver (lsah->type, GET_OPAQUE_TYPE (ntohl (lsah->id.s_addr))); } return found; } /* ----------------------------------------------------------- * Followings are functions to manage client connections. * ----------------------------------------------------------- */ static int ospf_apiserver_new_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Put LSA(%p)[%s] into reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total); return 0; } static int ospf_apiserver_del_lsa_hook (struct ospf_lsa *lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Get LSA(%p)[%s] from reserve, total=%ld", lsa, dump_lsa_key (lsa), lsa->lsdb->total); return 0; } /* Allocate new connection structure. */ struct ospf_apiserver * ospf_apiserver_new (int fd_sync, int fd_async) { struct ospf_apiserver *new = XMALLOC (MTYPE_OSPF_APISERVER, sizeof (struct ospf_apiserver)); new->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, sizeof (struct lsa_filter_type)); new->fd_sync = fd_sync; new->fd_async = fd_async; /* list of registered opaque types that application uses */ new->opaque_types = list_new (); /* Initialize temporary strage for LSA instances to be refreshed. */ memset (&new->reserve, 0, sizeof (struct ospf_lsdb)); ospf_lsdb_init (&new->reserve); new->reserve.new_lsa_hook = ospf_apiserver_new_lsa_hook; /* debug */ new->reserve.del_lsa_hook = ospf_apiserver_del_lsa_hook; /* debug */ new->out_sync_fifo = msg_fifo_new (); new->out_async_fifo = msg_fifo_new (); new->t_sync_read = NULL; #ifdef USE_ASYNC_READ new->t_async_read = NULL; #endif /* USE_ASYNC_READ */ new->t_sync_write = NULL; new->t_async_write = NULL; new->filter->typemask = 0; /* filter all LSAs */ new->filter->origin = ANY_ORIGIN; new->filter->num_areas = 0; return new; } void ospf_apiserver_event (enum event event, int fd, struct ospf_apiserver *apiserv) { switch (event) { case OSPF_APISERVER_ACCEPT: (void)thread_add_read (master, ospf_apiserver_accept, apiserv, fd); break; case OSPF_APISERVER_SYNC_READ: apiserv->t_sync_read = thread_add_read (master, ospf_apiserver_read, apiserv, fd); break; #ifdef USE_ASYNC_READ case OSPF_APISERVER_ASYNC_READ: apiserv->t_async_read = thread_add_read (master, ospf_apiserver_read, apiserv, fd); break; #endif /* USE_ASYNC_READ */ case OSPF_APISERVER_SYNC_WRITE: if (!apiserv->t_sync_write) { apiserv->t_sync_write = thread_add_write (master, ospf_apiserver_sync_write, apiserv, fd); } break; case OSPF_APISERVER_ASYNC_WRITE: if (!apiserv->t_async_write) { apiserv->t_async_write = thread_add_write (master, ospf_apiserver_async_write, apiserv, fd); } break; } } /* Free instance. First unregister all opaque types used by application, flush opaque LSAs injected by application from network and close connection. */ void ospf_apiserver_free (struct ospf_apiserver *apiserv) { struct listnode *node; /* Cancel read and write threads. */ if (apiserv->t_sync_read) { thread_cancel (apiserv->t_sync_read); } #ifdef USE_ASYNC_READ if (apiserv->t_async_read) { thread_cancel (apiserv->t_async_read); } #endif /* USE_ASYNC_READ */ if (apiserv->t_sync_write) { thread_cancel (apiserv->t_sync_write); } if (apiserv->t_async_write) { thread_cancel (apiserv->t_async_write); } /* Unregister all opaque types that application registered and flush opaque LSAs if still in LSDB. */ while ((node = listhead (apiserv->opaque_types)) != NULL) { struct registered_opaque_type *regtype = listgetdata(node); ospf_apiserver_unregister_opaque_type (apiserv, regtype->lsa_type, regtype->opaque_type); } /* Close connections to OSPFd. */ if (apiserv->fd_sync > 0) { close (apiserv->fd_sync); } if (apiserv->fd_async > 0) { close (apiserv->fd_async); } /* Free fifos */ msg_fifo_free (apiserv->out_sync_fifo); msg_fifo_free (apiserv->out_async_fifo); /* Clear temporary strage for LSA instances to be refreshed. */ ospf_lsdb_delete_all (&apiserv->reserve); ospf_lsdb_cleanup (&apiserv->reserve); /* Remove from the list of active clients. */ listnode_delete (apiserver_list, apiserv); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Delete apiserv(%p), total#(%d)", apiserv, apiserver_list->count); /* And free instance. */ XFREE (MTYPE_OSPF_APISERVER, apiserv); } int ospf_apiserver_read (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; enum event event; apiserv = THREAD_ARG (thread); fd = THREAD_FD (thread); if (fd == apiserv->fd_sync) { event = OSPF_APISERVER_SYNC_READ; apiserv->t_sync_read = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u", inet_ntoa (apiserv->peer_sync.sin_addr), ntohs (apiserv->peer_sync.sin_port)); } #ifdef USE_ASYNC_READ else if (fd == apiserv->fd_async) { event = OSPF_APISERVER_ASYNC_READ; apiserv->t_async_read = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_read: Peer: %s/%u", inet_ntoa (apiserv->peer_async.sin_addr), ntohs (apiserv->peer_async.sin_port)); } #endif /* USE_ASYNC_READ */ else { zlog_warn ("ospf_apiserver_read: Unknown fd(%d)", fd); ospf_apiserver_free (apiserv); goto out; } /* Read message from fd. */ msg = msg_read (fd); if (msg == NULL) { zlog_warn ("ospf_apiserver_read: read failed on fd=%d, closing connection", fd); /* Perform cleanup. */ ospf_apiserver_free (apiserv); goto out; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); /* Dispatch to corresponding message handler. */ rc = ospf_apiserver_handle_msg (apiserv, msg); /* Prepare for next message, add read thread. */ ospf_apiserver_event (event, fd, apiserv); msg_free (msg); out: return rc; } int ospf_apiserver_sync_write (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; apiserv = THREAD_ARG (thread); assert (apiserv); fd = THREAD_FD (thread); apiserv->t_sync_write = NULL; /* Sanity check */ if (fd != apiserv->fd_sync) { zlog_warn ("ospf_apiserver_sync_write: Unknown fd=%d", fd); goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_sync_write: Peer: %s/%u", inet_ntoa (apiserv->peer_sync.sin_addr), ntohs (apiserv->peer_sync.sin_port)); /* Check whether there is really a message in the fifo. */ msg = msg_fifo_pop (apiserv->out_sync_fifo); if (!msg) { zlog_warn ("API: ospf_apiserver_sync_write: No message in Sync-FIFO?"); return 0; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); rc = msg_write (fd, msg); /* Once a message is dequeued, it should be freed anyway. */ msg_free (msg); if (rc < 0) { zlog_warn ("ospf_apiserver_sync_write: write failed on fd=%d", fd); goto out; } /* If more messages are in sync message fifo, schedule write thread. */ if (msg_fifo_head (apiserv->out_sync_fifo)) { ospf_apiserver_event (OSPF_APISERVER_SYNC_WRITE, apiserv->fd_sync, apiserv); } out: if (rc < 0) { /* Perform cleanup and disconnect with peer */ ospf_apiserver_free (apiserv); } return rc; } int ospf_apiserver_async_write (struct thread *thread) { struct ospf_apiserver *apiserv; struct msg *msg; int fd; int rc = -1; apiserv = THREAD_ARG (thread); assert (apiserv); fd = THREAD_FD (thread); apiserv->t_async_write = NULL; /* Sanity check */ if (fd != apiserv->fd_async) { zlog_warn ("ospf_apiserver_async_write: Unknown fd=%d", fd); goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_async_write: Peer: %s/%u", inet_ntoa (apiserv->peer_async.sin_addr), ntohs (apiserv->peer_async.sin_port)); /* Check whether there is really a message in the fifo. */ msg = msg_fifo_pop (apiserv->out_async_fifo); if (!msg) { zlog_warn ("API: ospf_apiserver_async_write: No message in Async-FIFO?"); return 0; } if (IS_DEBUG_OSPF_EVENT) msg_print (msg); rc = msg_write (fd, msg); /* Once a message is dequeued, it should be freed anyway. */ msg_free (msg); if (rc < 0) { zlog_warn ("ospf_apiserver_async_write: write failed on fd=%d", fd); goto out; } /* If more messages are in async message fifo, schedule write thread. */ if (msg_fifo_head (apiserv->out_async_fifo)) { ospf_apiserver_event (OSPF_APISERVER_ASYNC_WRITE, apiserv->fd_async, apiserv); } out: if (rc < 0) { /* Perform cleanup and disconnect with peer */ ospf_apiserver_free (apiserv); } return rc; } int ospf_apiserver_serv_sock_family (unsigned short port, int family) { union sockunion su; int accept_sock; int rc; memset (&su, 0, sizeof (union sockunion)); su.sa.sa_family = family; /* Make new socket */ accept_sock = sockunion_stream_socket (&su); if (accept_sock < 0) return accept_sock; /* This is a server, so reuse address and port */ sockopt_reuseaddr (accept_sock); sockopt_reuseport (accept_sock); /* Bind socket to address and given port. */ rc = sockunion_bind (accept_sock, &su, port, NULL); if (rc < 0) { close (accept_sock); /* Close socket */ return rc; } /* Listen socket under queue length 3. */ rc = listen (accept_sock, 3); if (rc < 0) { zlog_warn ("ospf_apiserver_serv_sock_family: listen: %s", safe_strerror (errno)); close (accept_sock); /* Close socket */ return rc; } return accept_sock; } /* Accept connection request from external applications. For each accepted connection allocate own connection instance. */ int ospf_apiserver_accept (struct thread *thread) { int accept_sock; int new_sync_sock; int new_async_sock; union sockunion su; struct ospf_apiserver *apiserv; struct sockaddr_in peer_async; struct sockaddr_in peer_sync; unsigned int peerlen; int ret; /* THREAD_ARG (thread) is NULL */ accept_sock = THREAD_FD (thread); /* Keep hearing on socket for further connections. */ ospf_apiserver_event (OSPF_APISERVER_ACCEPT, accept_sock, NULL); memset (&su, 0, sizeof (union sockunion)); /* Accept connection for synchronous messages */ new_sync_sock = sockunion_accept (accept_sock, &su); if (new_sync_sock < 0) { zlog_warn ("ospf_apiserver_accept: accept: %s", safe_strerror (errno)); return -1; } /* Get port address and port number of peer to make reverse connection. The reverse channel uses the port number of the peer port+1. */ memset(&peer_sync, 0, sizeof(struct sockaddr_in)); peerlen = sizeof (struct sockaddr_in); ret = getpeername (new_sync_sock, (struct sockaddr *)&peer_sync, &peerlen); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: getpeername: %s", safe_strerror (errno)); close (new_sync_sock); return -1; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: ospf_apiserver_accept: New peer: %s/%u", inet_ntoa (peer_sync.sin_addr), ntohs (peer_sync.sin_port)); /* Create new socket for asynchronous messages. */ peer_async = peer_sync; peer_async.sin_port = htons(ntohs(peer_sync.sin_port) + 1); /* Check if remote port number to make reverse connection is valid one. */ if (ntohs (peer_async.sin_port) == ospf_apiserver_getport ()) { zlog_warn ("API: ospf_apiserver_accept: Peer(%s/%u): Invalid async port number?", inet_ntoa (peer_async.sin_addr), ntohs (peer_async.sin_port)); close (new_sync_sock); return -1; } new_async_sock = socket (AF_INET, SOCK_STREAM, 0); if (new_async_sock < 0) { zlog_warn ("ospf_apiserver_accept: socket: %s", safe_strerror (errno)); close (new_sync_sock); return -1; } ret = connect (new_async_sock, (struct sockaddr *) &peer_async, sizeof (struct sockaddr_in)); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: connect: %s", safe_strerror (errno)); close (new_sync_sock); close (new_async_sock); return -1; } #ifdef USE_ASYNC_READ #else /* USE_ASYNC_READ */ /* Make the asynchronous channel write-only. */ ret = shutdown (new_async_sock, SHUT_RD); if (ret < 0) { zlog_warn ("ospf_apiserver_accept: shutdown: %s", safe_strerror (errno)); close (new_sync_sock); close (new_async_sock); return -1; } #endif /* USE_ASYNC_READ */ /* Allocate new server-side connection structure */ apiserv = ospf_apiserver_new (new_sync_sock, new_async_sock); /* Add to active connection list */ listnode_add (apiserver_list, apiserv); apiserv->peer_sync = peer_sync; apiserv->peer_async = peer_async; /* And add read threads for new connection */ ospf_apiserver_event (OSPF_APISERVER_SYNC_READ, new_sync_sock, apiserv); #ifdef USE_ASYNC_READ ospf_apiserver_event (OSPF_APISERVER_ASYNC_READ, new_async_sock, apiserv); #endif /* USE_ASYNC_READ */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: New apiserv(%p), total#(%d)", apiserv, apiserver_list->count); return 0; } /* ----------------------------------------------------------- * Send reply with return code to client application * ----------------------------------------------------------- */ static int ospf_apiserver_send_msg (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_fifo *fifo; struct msg *msg2; enum event event; int fd; switch (msg->hdr.msgtype) { case MSG_REPLY: fifo = apiserv->out_sync_fifo; fd = apiserv->fd_sync; event = OSPF_APISERVER_SYNC_WRITE; break; case MSG_READY_NOTIFY: case MSG_LSA_UPDATE_NOTIFY: case MSG_LSA_DELETE_NOTIFY: case MSG_NEW_IF: case MSG_DEL_IF: case MSG_ISM_CHANGE: case MSG_NSM_CHANGE: fifo = apiserv->out_async_fifo; fd = apiserv->fd_async; event = OSPF_APISERVER_ASYNC_WRITE; break; default: zlog_warn ("ospf_apiserver_send_msg: Unknown message type %d", msg->hdr.msgtype); return -1; } /* Make a copy of the message and put in the fifo. Once the fifo gets drained by the write thread, the message will be freed. */ /* NB: Given "msg" is untouched in this function. */ msg2 = msg_dup (msg); /* Enqueue message into corresponding fifo queue */ msg_fifo_push (fifo, msg2); /* Schedule write thread */ ospf_apiserver_event (event, fd, apiserv); return 0; } int ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr, u_char rc) { struct msg *msg = new_msg_reply (seqnr, rc); int ret; if (!msg) { zlog_warn ("ospf_apiserver_send_reply: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif return -1; } ret = ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); return ret; } /* ----------------------------------------------------------- * Generic message dispatching handler function * ----------------------------------------------------------- */ int ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg) { int rc; /* Call corresponding message handler function. */ switch (msg->hdr.msgtype) { case MSG_REGISTER_OPAQUETYPE: rc = ospf_apiserver_handle_register_opaque_type (apiserv, msg); break; case MSG_UNREGISTER_OPAQUETYPE: rc = ospf_apiserver_handle_unregister_opaque_type (apiserv, msg); break; case MSG_REGISTER_EVENT: rc = ospf_apiserver_handle_register_event (apiserv, msg); break; case MSG_SYNC_LSDB: rc = ospf_apiserver_handle_sync_lsdb (apiserv, msg); break; case MSG_ORIGINATE_REQUEST: rc = ospf_apiserver_handle_originate_request (apiserv, msg); break; case MSG_DELETE_REQUEST: rc = ospf_apiserver_handle_delete_request (apiserv, msg); break; default: zlog_warn ("ospf_apiserver_handle_msg: Unknown message type: %d", msg->hdr.msgtype); rc = -1; } return rc; } /* ----------------------------------------------------------- * Following are functions for opaque type registration * ----------------------------------------------------------- */ int ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct registered_opaque_type *regtype; int (*originator_func) (void *arg); int rc; switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: originator_func = ospf_apiserver_lsa9_originator; break; case OSPF_OPAQUE_AREA_LSA: originator_func = ospf_apiserver_lsa10_originator; break; case OSPF_OPAQUE_AS_LSA: originator_func = ospf_apiserver_lsa11_originator; break; default: zlog_warn ("ospf_apiserver_register_opaque_type: lsa_type(%d)", lsa_type); return OSPF_API_ILLEGALLSATYPE; } /* Register opaque function table */ /* NB: Duplicated registration will be detected inside the function. */ rc = ospf_register_opaque_functab (lsa_type, opaque_type, NULL, /* ospf_apiserver_new_if */ NULL, /* ospf_apiserver_del_if */ NULL, /* ospf_apiserver_ism_change */ NULL, /* ospf_apiserver_nsm_change */ NULL, NULL, NULL, ospf_apiserver_show_info, originator_func, ospf_apiserver_lsa_refresher, NULL, /* ospf_apiserver_lsa_update */ NULL /* ospf_apiserver_lsa_delete */); if (rc != 0) { zlog_warn ("Failed to register opaque type [%d/%d]", lsa_type, opaque_type); return OSPF_API_OPAQUETYPEINUSE; } /* Remember the opaque type that application registers so when connection shuts down, we can flush all LSAs of this opaque type. */ regtype = XCALLOC (MTYPE_OSPF_APISERVER, sizeof (struct registered_opaque_type)); regtype->lsa_type = lsa_type; regtype->opaque_type = opaque_type; /* Add to list of registered opaque types */ listnode_add (apiserv->opaque_types, regtype); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Add LSA-type(%d)/Opaque-type(%d) into" " apiserv(%p), total#(%d)", lsa_type, opaque_type, apiserv, listcount (apiserv->opaque_types)); return 0; } int ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct listnode *node, *nnode; struct registered_opaque_type *regtype; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype)) { /* Check if we really registered this opaque type */ if (regtype->lsa_type == lsa_type && regtype->opaque_type == opaque_type) { /* Yes, we registered this opaque type. Flush all existing opaque LSAs of this type */ ospf_apiserver_flush_opaque_lsa (apiserv, lsa_type, opaque_type); ospf_delete_opaque_functab (lsa_type, opaque_type); /* Remove from list of registered opaque types */ listnode_delete (apiserv->opaque_types, regtype); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("API: Del LSA-type(%d)/Opaque-type(%d)" " from apiserv(%p), total#(%d)", lsa_type, opaque_type, apiserv, listcount (apiserv->opaque_types)); return 0; } } /* Opaque type is not registered */ zlog_warn ("Failed to unregister opaque type [%d/%d]", lsa_type, opaque_type); return OSPF_API_OPAQUETYPENOTREGISTERED; } static int apiserver_is_opaque_type_registered (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct listnode *node, *nnode; struct registered_opaque_type *regtype; /* XXX: how many types are there? if few, why not just a bitmap? */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, regtype)) { /* Check if we really registered this opaque type */ if (regtype->lsa_type == lsa_type && regtype->opaque_type == opaque_type) { /* Yes registered */ return 1; } } /* Not registered */ return 0; } int ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_register_opaque_type *rmsg; u_char lsa_type; u_char opaque_type; int rc = 0; /* Extract parameters from register opaque type message */ rmsg = (struct msg_register_opaque_type *) STREAM_DATA (msg->s); lsa_type = rmsg->lsatype; opaque_type = rmsg->opaquetype; rc = ospf_apiserver_register_opaque_type (apiserv, lsa_type, opaque_type); /* Send a reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); if (rc < 0) goto out; /* Now inform application about opaque types that are ready */ switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: ospf_apiserver_notify_ready_type9 (apiserv); break; case OSPF_OPAQUE_AREA_LSA: ospf_apiserver_notify_ready_type10 (apiserv); break; case OSPF_OPAQUE_AS_LSA: ospf_apiserver_notify_ready_type11 (apiserv); break; } out: return rc; } /* Notify specific client about all opaque types 9 that are ready. */ void ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf *ospf; struct ospf_interface *oi; struct registered_opaque_type *r; ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { /* Check if this interface is indeed ready for type 9 */ if (!ospf_apiserver_is_ready_type9 (oi)) continue; /* Check for registered opaque type 9 types */ /* XXX: loop-de-loop - optimise me */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { struct msg *msg; if (r->lsa_type == OSPF_OPAQUE_LINK_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA, r->opaque_type, oi->address->u.prefix4); if (!msg) { zlog_warn ("apiserver_notify_ready_type9: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } /* Notify specific client about all opaque types 10 that are ready. */ void ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf *ospf; struct ospf_area *area; ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { struct registered_opaque_type *r; if (!ospf_apiserver_is_ready_type10 (area)) { continue; } /* Check for registered opaque type 10 types */ /* XXX: loop in loop - optimise me */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { struct msg *msg; if (r->lsa_type == OSPF_OPAQUE_AREA_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA, r->opaque_type, area->area_id); if (!msg) { zlog_warn ("apiserver_notify_ready_type10: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } /* Notify specific client about all opaque types 11 that are ready */ void ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv) { struct listnode *node, *nnode; struct ospf *ospf; struct registered_opaque_type *r; ospf = ospf_lookup (); /* Can type 11 be originated? */ if (!ospf_apiserver_is_ready_type11 (ospf)) goto out; /* Check for registered opaque type 11 types */ for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node, nnode, r)) { struct msg *msg; struct in_addr noarea_id = { .s_addr = 0L }; if (r->lsa_type == OSPF_OPAQUE_AS_LSA) { /* Yes, this opaque type is ready */ msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA, r->opaque_type, noarea_id); if (!msg) { zlog_warn ("apiserver_notify_ready_type11: msg_new failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } out: return; } int ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_unregister_opaque_type *umsg; u_char ltype; u_char otype; int rc = 0; /* Extract parameters from unregister opaque type message */ umsg = (struct msg_unregister_opaque_type *) STREAM_DATA (msg->s); ltype = umsg->lsatype; otype = umsg->opaquetype; rc = ospf_apiserver_unregister_opaque_type (apiserv, ltype, otype); /* Send a reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* ----------------------------------------------------------- * Following are functions for event (filter) registration. * ----------------------------------------------------------- */ int ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_register_event *rmsg; int rc; u_int32_t seqnum; rmsg = (struct msg_register_event *) STREAM_DATA (msg->s); /* Get request sequence number */ seqnum = msg_get_seq (msg); /* Free existing filter in apiserv. */ XFREE (MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter); /* Alloc new space for filter. */ apiserv->filter = XMALLOC (MTYPE_OSPF_APISERVER_MSGFILTER, ntohs (msg->hdr.msglen)); if (apiserv->filter) { /* copy it over. */ memcpy (apiserv->filter, &rmsg->filter, ntohs (msg->hdr.msglen)); rc = OSPF_API_OK; } else { rc = OSPF_API_NOMEMORY; } /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, seqnum, rc); return rc; } /* ----------------------------------------------------------- * Followings are functions for LSDB synchronization. * ----------------------------------------------------------- */ static int apiserver_sync_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg) { struct ospf_apiserver *apiserv; int seqnum; struct msg *msg; struct param_t { struct ospf_apiserver *apiserv; struct lsa_filter_type *filter; } *param; int rc = -1; /* Sanity check */ assert (lsa->data); assert (p_arg); param = (struct param_t *) p_arg; apiserv = param->apiserv; seqnum = (u_int32_t) int_arg; /* Check origin in filter. */ if ((param->filter->origin == ANY_ORIGIN) || (param->filter->origin == (lsa->flags & OSPF_LSA_SELF))) { /* Default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* Default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { ifaddr = lsa->oi->address->u.prefix4; } msg = new_msg_lsa_change_notify (MSG_LSA_UPDATE_NOTIFY, seqnum, ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("apiserver_sync_callback: new_msg_update failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ /* ospf_apiserver_free (apiserv);*//* Do nothing here XXX */ #endif goto out; } /* Send LSA */ ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } rc = 0; out: return rc; } int ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv, struct msg *msg) { struct listnode *node, *nnode; u_int32_t seqnum; int rc = 0; struct msg_sync_lsdb *smsg; struct ospf_apiserver_param_t { struct ospf_apiserver *apiserv; struct lsa_filter_type *filter; } param; u_int16_t mask; struct route_node *rn; struct ospf_lsa *lsa; struct ospf *ospf; struct ospf_area *area; ospf = ospf_lookup (); /* Get request sequence number */ seqnum = msg_get_seq (msg); /* Set sync msg. */ smsg = (struct msg_sync_lsdb *) STREAM_DATA (msg->s); /* Set parameter struct. */ param.apiserv = apiserv; param.filter = &smsg->filter; /* Remember mask. */ mask = ntohs (smsg->filter.typemask); /* Iterate over all areas. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { int i; u_int32_t *area_id = NULL; /* Compare area_id with area_ids in sync request. */ if ((i = smsg->filter.num_areas) > 0) { /* Let area_id point to the list of area IDs, * which is at the end of smsg->filter. */ area_id = (u_int32_t *) (&smsg->filter + 1); while (i) { if (*area_id == area->area_id.s_addr) { break; } i--; area_id++; } } else { i = 1; } /* If area was found, then i>0 here. */ if (i) { /* Check msg type. */ if (mask & Power2[OSPF_ROUTER_LSA]) LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_NETWORK_LSA]) LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_SUMMARY_LSA]) LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_ASBR_SUMMARY_LSA]) LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_LINK_LSA]) LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); if (mask & Power2[OSPF_OPAQUE_AREA_LSA]) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } } /* For AS-external LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_AS_EXTERNAL_LSA]) LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } /* For AS-external opaque LSAs */ if (ospf->lsdb) { if (mask & Power2[OSPF_OPAQUE_AS_LSA]) LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) apiserver_sync_callback(lsa, (void *) ¶m, seqnum); } /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, seqnum, rc); return rc; } /* ----------------------------------------------------------- * Followings are functions to originate or update LSA * from an application. * ----------------------------------------------------------- */ /* Create a new internal opaque LSA by taking prototype and filling in missing fields such as age, sequence number, advertising router, checksum and so on. The interface parameter is used for type 9 LSAs, area parameter for type 10. Type 11 LSAs do neither need area nor interface. */ struct ospf_lsa * ospf_apiserver_opaque_lsa_new (struct ospf_area *area, struct ospf_interface *oi, struct lsa_header *protolsa) { struct stream *s; struct lsa_header *newlsa; struct ospf_lsa *new = NULL; u_char options = 0x0; u_int16_t length; struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Create a stream for internal opaque LSA */ if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: stream_new failed"); return NULL; } newlsa = (struct lsa_header *) STREAM_DATA (s); /* XXX If this is a link-local LSA or an AS-external LSA, how do we have to set options? */ if (area) { options = LSA_OPTIONS_GET (area); options |= LSA_OPTIONS_NSSA_GET (area); } options |= OSPF_OPTION_O; /* Don't forget to set option bit */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Creating an Opaque-LSA instance", protolsa->type, inet_ntoa (protolsa->id)); } /* Set opaque-LSA header fields. */ lsa_header_set (s, options, protolsa->type, protolsa->id, ospf->router_id); /* Set opaque-LSA body fields. */ stream_put (s, ((u_char *) protolsa) + sizeof (struct lsa_header), ntohs (protolsa->length) - sizeof (struct lsa_header)); /* Determine length of LSA. */ length = stream_get_endp (s); newlsa->length = htons (length); /* Create OSPF LSA. */ if ((new = ospf_lsa_new ()) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_new() ?"); stream_free (s); return NULL; } if ((new->data = ospf_lsa_data_new (length)) == NULL) { zlog_warn ("ospf_apiserver_opaque_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock (&new); stream_free (s); return NULL; } new->area = area; new->oi = oi; SET_FLAG (new->flags, OSPF_LSA_SELF); memcpy (new->data, newlsa, length); stream_free (s); return new; } int ospf_apiserver_is_ready_type9 (struct ospf_interface *oi) { /* Type 9 opaque LSA can be originated if there is at least one active opaque-capable neighbor attached to the outgoing interface. */ return (ospf_nbr_count_opaque_capable (oi) > 0); } int ospf_apiserver_is_ready_type10 (struct ospf_area *area) { /* Type 10 opaque LSA can be originated if there is at least one interface belonging to the area that has an active opaque-capable neighbor. */ struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) /* Is there an active neighbor attached to this interface? */ if (ospf_apiserver_is_ready_type9 (oi)) return 1; /* No active neighbor in area */ return 0; } int ospf_apiserver_is_ready_type11 (struct ospf *ospf) { /* Type 11 opaque LSA can be originated if there is at least one interface that has an active opaque-capable neighbor. */ struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) /* Is there an active neighbor attached to this interface? */ if (ospf_apiserver_is_ready_type9 (oi)) return 1; /* No active neighbor at all */ return 0; } int ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_originate_request *omsg; struct lsa_header *data; struct ospf_lsa *new; struct ospf_lsa *old; struct ospf_area *area = NULL; struct ospf_interface *oi = NULL; struct ospf_lsdb *lsdb = NULL; struct ospf *ospf; int lsa_type, opaque_type; int ready = 0; int rc = 0; ospf = ospf_lookup(); /* Extract opaque LSA data from message */ omsg = (struct msg_originate_request *) STREAM_DATA (msg->s); data = &omsg->data; /* Determine interface for type9 or area for type10 LSAs. */ switch (data->type) { case OSPF_OPAQUE_LINK_LSA: oi = ospf_apiserver_if_lookup_by_addr (omsg->ifaddr); if (!oi) { zlog_warn ("apiserver_originate: unknown interface %s", inet_ntoa (omsg->ifaddr)); rc = OSPF_API_NOSUCHINTERFACE; goto out; } area = oi->area; lsdb = area->lsdb; break; case OSPF_OPAQUE_AREA_LSA: area = ospf_area_lookup_by_area_id (ospf, omsg->area_id); if (!area) { zlog_warn ("apiserver_originate: unknown area %s", inet_ntoa (omsg->area_id)); rc = OSPF_API_NOSUCHAREA; goto out; } lsdb = area->lsdb; break; case OSPF_OPAQUE_AS_LSA: lsdb = ospf->lsdb; break; default: /* We can only handle opaque types here */ zlog_warn ("apiserver_originate: Cannot originate non-opaque LSA type %d", data->type); rc = OSPF_API_ILLEGALLSATYPE; goto out; } /* Check if we registered this opaque type */ lsa_type = data->type; opaque_type = GET_OPAQUE_TYPE (ntohl (data->id.s_addr)); if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type)) { zlog_warn ("apiserver_originate: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type); rc = OSPF_API_OPAQUETYPENOTREGISTERED; goto out; } /* Make sure that the neighbors are ready before we can originate */ switch (data->type) { case OSPF_OPAQUE_LINK_LSA: ready = ospf_apiserver_is_ready_type9 (oi); break; case OSPF_OPAQUE_AREA_LSA: ready = ospf_apiserver_is_ready_type10 (area); break; case OSPF_OPAQUE_AS_LSA: ready = ospf_apiserver_is_ready_type11 (ospf); break; default: break; } if (!ready) { zlog_warn ("Neighbors not ready to originate type %d", data->type); rc = OSPF_API_NOTREADY; goto out; } /* Create OSPF's internal opaque LSA representation */ new = ospf_apiserver_opaque_lsa_new (area, oi, data); if (!new) { rc = OSPF_API_NOMEMORY; /* XXX */ goto out; } /* Determine if LSA is new or an update for an existing one. */ old = ospf_lsdb_lookup (lsdb, new); if (!old) { /* New LSA install in LSDB. */ rc = ospf_apiserver_originate1 (new); } else { /* * Keep the new LSA instance in the "waiting place" until the next * refresh timing. If several LSA update requests for the same LSID * have issued by peer, the last one takes effect. */ new->lsdb = &apiserv->reserve; ospf_lsdb_add (&apiserv->reserve, new); /* Kick the scheduler function. */ ospf_opaque_lsa_refresh_schedule (old); } out: /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* ----------------------------------------------------------- * Flood an LSA within its flooding scope. * ----------------------------------------------------------- */ /* XXX We can probably use ospf_flood_through instead of this function but then we need the neighbor parameter. If we set nbr to NULL then ospf_flood_through crashes due to dereferencing NULL. */ void ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa) { assert (lsa); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: /* Increment counters? XXX */ /* Flood LSA through local network. */ ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa); break; case OSPF_OPAQUE_AREA_LSA: /* Update LSA origination count. */ assert (lsa->area); lsa->area->ospf->lsa_originate_count++; /* Flood LSA through area. */ ospf_flood_through_area (lsa->area, NULL /*nbr */ , lsa); break; case OSPF_OPAQUE_AS_LSA: { struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Increment counters? XXX */ /* Flood LSA through AS. */ ospf_flood_through_as (ospf, NULL /*nbr */ , lsa); break; } } } int ospf_apiserver_originate1 (struct ospf_lsa *lsa) { struct ospf *ospf; ospf = ospf_lookup(); assert(ospf); /* Install this LSA into LSDB. */ if (ospf_lsa_install (ospf, lsa->oi, lsa) == NULL) { zlog_warn ("ospf_apiserver_originate1: ospf_lsa_install failed"); return -1; } /* Flood LSA within scope */ #ifdef NOTYET /* * NB: Modified version of "ospf_flood_though ()" accepts NULL "inbr" * parameter, and thus it does not cause SIGSEGV error. */ ospf_flood_through (NULL /*nbr */ , lsa); #else /* NOTYET */ ospf_apiserver_flood_opaque_lsa (lsa); #endif /* NOTYET */ return 0; } /* Opaque LSAs of type 9 on a specific interface can now be originated. Tell clients that registered type 9. */ int ospf_apiserver_lsa9_originator (void *arg) { struct ospf_interface *oi; oi = (struct ospf_interface *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type9 (oi); } return 0; } int ospf_apiserver_lsa10_originator (void *arg) { struct ospf_area *area; area = (struct ospf_area *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type10 (area); } return 0; } int ospf_apiserver_lsa11_originator (void *arg) { struct ospf *ospf; ospf = (struct ospf *) arg; if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ready_type11 (ospf); } return 0; } /* Periodically refresh opaque LSAs so that they do not expire in other routers. */ struct ospf_lsa * ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa) { struct ospf_apiserver *apiserv; struct ospf_lsa *new = NULL; struct ospf * ospf; ospf = ospf_lookup(); assert(ospf); apiserv = lookup_apiserver_by_lsa (lsa); if (!apiserv) { zlog_warn ("ospf_apiserver_lsa_refresher: LSA[%s]: No apiserver?", dump_lsa_key (lsa)); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } if (IS_LSA_MAXAGE (lsa)) { ospf_opaque_lsa_flush_schedule (lsa); goto out; } /* Check if updated version of LSA instance has already prepared. */ new = ospf_lsdb_lookup (&apiserv->reserve, lsa); if (!new) { /* This is a periodic refresh, driven by core OSPF mechanism. */ new = ospf_apiserver_opaque_lsa_new (lsa->area, lsa->oi, lsa->data); if (!new) { zlog_warn ("ospf_apiserver_lsa_refresher: Cannot create a new LSA?"); goto out; } } else { /* This is a forcible refresh, requested by OSPF-API client. */ ospf_lsdb_delete (&apiserv->reserve, new); new->lsdb = NULL; } /* Increment sequence number */ new->data->ls_seqnum = lsa_seqnum_increment (lsa); /* New LSA is in same area. */ new->area = lsa->area; SET_FLAG (new->flags, OSPF_LSA_SELF); /* Install LSA into LSDB. */ if (ospf_lsa_install (ospf, new->oi, new) == NULL) { zlog_warn ("ospf_apiserver_lsa_refresher: ospf_lsa_install failed"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through interface, area or AS */ #ifdef NOTYET ospf_flood_through (NULL /*nbr */ , new); #endif /* NOTYET */ ospf_apiserver_flood_opaque_lsa (new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Refresh Opaque LSA", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } out: return new; } /* ----------------------------------------------------------- * Followings are functions to delete LSAs * ----------------------------------------------------------- */ int ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv, struct msg *msg) { struct msg_delete_request *dmsg; struct ospf_lsa *old; struct ospf_area *area = NULL; struct in_addr id; int lsa_type, opaque_type; int rc = 0; struct ospf * ospf; ospf = ospf_lookup(); assert(ospf); /* Extract opaque LSA from message */ dmsg = (struct msg_delete_request *) STREAM_DATA (msg->s); /* Lookup area for link-local and area-local opaque LSAs */ switch (dmsg->lsa_type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: area = ospf_area_lookup_by_area_id (ospf, dmsg->area_id); if (!area) { zlog_warn ("ospf_apiserver_lsa_delete: unknown area %s", inet_ntoa (dmsg->area_id)); rc = OSPF_API_NOSUCHAREA; goto out; } break; case OSPF_OPAQUE_AS_LSA: /* AS-external opaque LSAs have no designated area */ area = NULL; break; default: zlog_warn ("ospf_apiserver_lsa_delete: Cannot delete non-opaque LSA type %d", dmsg->lsa_type); rc = OSPF_API_ILLEGALLSATYPE; goto out; } /* Check if we registered this opaque type */ lsa_type = dmsg->lsa_type; opaque_type = dmsg->opaque_type; if (!apiserver_is_opaque_type_registered (apiserv, lsa_type, opaque_type)) { zlog_warn ("ospf_apiserver_lsa_delete: LSA-type(%d)/Opaque-type(%d): Not registered", lsa_type, opaque_type); rc = OSPF_API_OPAQUETYPENOTREGISTERED; goto out; } /* opaque_id is in network byte order */ id.s_addr = htonl (SET_OPAQUE_LSID (dmsg->opaque_type, ntohl (dmsg->opaque_id))); /* * Even if the target LSA has once scheduled to flush, it remains in * the LSDB until it is finally handled by the maxage remover thread. * Therefore, the lookup function below may return non-NULL result. */ old = ospf_lsa_lookup (area, dmsg->lsa_type, id, ospf->router_id); if (!old) { zlog_warn ("ospf_apiserver_lsa_delete: LSA[Type%d:%s] not in LSDB", dmsg->lsa_type, inet_ntoa (id)); rc = OSPF_API_NOSUCHLSA; goto out; } /* Schedule flushing of LSA from LSDB */ /* NB: Multiple scheduling will produce a warning message, but harmless. */ ospf_opaque_lsa_flush_schedule (old); out: /* Send reply back to client including return code */ rc = ospf_apiserver_send_reply (apiserv, ntohl (msg->hdr.msgseq), rc); return rc; } /* Flush self-originated opaque LSA */ static int apiserver_flush_opaque_type_callback (struct ospf_lsa *lsa, void *p_arg, int int_arg) { struct param_t { struct ospf_apiserver *apiserv; u_char lsa_type; u_char opaque_type; } *param; /* Sanity check */ assert (lsa->data); assert (p_arg); param = (struct param_t *) p_arg; /* If LSA matches type and opaque type then delete it */ if (IS_LSA_SELF (lsa) && lsa->data->type == param->lsa_type && GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)) == param->opaque_type) { ospf_opaque_lsa_flush_schedule (lsa); } return 0; } /* Delete self-originated opaque LSAs of a given opaque type. This function is called when an application unregisters a given opaque type or a connection to an application closes and all those opaque LSAs need to be flushed the LSDB. */ void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type) { struct param_t { struct ospf_apiserver *apiserv; u_char lsa_type; u_char opaque_type; } param; struct listnode *node, *nnode; struct ospf * ospf; struct ospf_area *area; ospf = ospf_lookup(); assert(ospf); /* Set parameter struct. */ param.apiserv = apiserv; param.lsa_type = lsa_type; param.opaque_type = opaque_type; switch (lsa_type) { struct route_node *rn; struct ospf_lsa *lsa; case OSPF_OPAQUE_LINK_LSA: for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; case OSPF_OPAQUE_AREA_LSA: for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; case OSPF_OPAQUE_AS_LSA: LSDB_LOOP (OPAQUE_LINK_LSDB (ospf), rn, lsa) apiserver_flush_opaque_type_callback(lsa, (void *) ¶m, 0); break; default: break; } return; } /* ----------------------------------------------------------- * Followings are callback functions to handle opaque types * ----------------------------------------------------------- */ int ospf_apiserver_new_if (struct interface *ifp) { struct ospf_interface *oi; /* For some strange reason it seems possible that we are invoked with an interface that has no name. This seems to happen during initialization. Return if this happens */ if (ifp->name[0] == '\0') { /* interface has empty name */ zlog_warn ("ospf_apiserver_new_if: interface has no name?"); return 0; } /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_new_if"); zlog_warn ("ifp name=%s status=%d index=%d", ifp->name, ifp->status, ifp->ifindex); if (ifp->name[0] == '\0') { /* interface has empty name */ zlog_warn ("ospf_apiserver_new_if: interface has no name?"); return 0; } oi = ospf_apiserver_if_lookup_by_ifp (ifp); if (!oi) { /* This interface is known to Zebra but not to OSPF daemon yet. */ zlog_warn ("ospf_apiserver_new_if: interface %s not known to OSPFd?", ifp->name); return 0; } assert (oi); /* New interface added to OSPF, tell clients about it */ if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_new_if (oi); } return 0; } int ospf_apiserver_del_if (struct interface *ifp) { struct ospf_interface *oi; /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_del_if"); zlog_warn ("ifp name=%s status=%d index=%d\n", ifp->name, ifp->status, ifp->ifindex); oi = ospf_apiserver_if_lookup_by_ifp (ifp); if (!oi) { /* This interface is known to Zebra but not to OSPF daemon anymore. No need to tell clients about it */ return 0; } /* Interface deleted, tell clients about it */ if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_del_if (oi); } return 0; } void ospf_apiserver_ism_change (struct ospf_interface *oi, int old_state) { /* Tell clients about interface change */ /* zlog_warn for debugging */ zlog_warn ("ospf_apiserver_ism_change"); if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_ism_change (oi); } zlog_warn ("oi->ifp->name=%s", oi->ifp->name); zlog_warn ("old_state=%d", old_state); zlog_warn ("oi->state=%d", oi->state); } void ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status) { /* Neighbor status changed, tell clients about it */ zlog_warn ("ospf_apiserver_nsm_change"); if (listcount (apiserver_list) > 0) { ospf_apiserver_clients_notify_nsm_change (nbr); } } void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa) { struct opaque_lsa { struct lsa_header header; u_char data[1]; /* opaque data have variable length. This is start address */ }; struct opaque_lsa *olsa; int opaquelen; olsa = (struct opaque_lsa *) lsa->data; if (VALID_OPAQUE_INFO_LEN (lsa->data)) opaquelen = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE; else opaquelen = 0; /* Output information about opaque LSAs */ if (vty != NULL) { int i; vty_out (vty, " Added using OSPF API: %u octets of opaque data %s%s", opaquelen, VALID_OPAQUE_INFO_LEN (lsa->data) ? "" : "(Invalid length?)", VTY_NEWLINE); vty_out (vty, " Opaque data: "); for (i = 0; i < opaquelen; i++) { vty_out (vty, "0x%x ", olsa->data[i]); } vty_out (vty, "%s", VTY_NEWLINE); } else { int i; zlog_debug (" Added using OSPF API: %u octets of opaque data %s", opaquelen, VALID_OPAQUE_INFO_LEN (lsa-> data) ? "" : "(Invalid length?)"); zlog_debug (" Opaque data: "); for (i = 0; i < opaquelen; i++) { zlog_debug ("0x%x ", olsa->data[i]); } zlog_debug ("\n"); } return; } /* ----------------------------------------------------------- * Followings are functions to notify clients about events * ----------------------------------------------------------- */ /* Send a message to all clients. This is useful for messages that need to be notified to all clients (such as interface changes) */ void ospf_apiserver_clients_notify_all (struct msg *msg) { struct listnode *node, *nnode; struct ospf_apiserver *apiserv; /* Send message to all clients */ for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) ospf_apiserver_send_msg (apiserv, msg); } /* An interface is now ready to accept opaque LSAs. Notify all clients that registered to use this opaque type */ void ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi) { struct listnode *node, *nnode; struct msg *msg; struct ospf_apiserver *apiserv; assert (oi); if (!oi->address) { zlog_warn ("Interface has no address?"); return; } if (!ospf_apiserver_is_ready_type9 (oi)) { zlog_warn ("Interface not ready for type 9?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_LINK_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_LINK_LSA, r->opaque_type, oi->address->u.prefix4); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type9: new_msg_ready_notify failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area) { struct listnode *node, *nnode; struct msg *msg; struct ospf_apiserver *apiserv; assert (area); if (!ospf_apiserver_is_ready_type10 (area)) { zlog_warn ("Area not ready for type 10?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_AREA_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_AREA_LSA, r->opaque_type, area->area_id); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type10: new_msg_ready_nofity failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_ready_type11 (struct ospf *top) { struct listnode *node, *nnode; struct msg *msg; struct in_addr id_null = { .s_addr = 0L }; struct ospf_apiserver *apiserv; assert (top); if (!ospf_apiserver_is_ready_type11 (top)) { zlog_warn ("AS not ready for type 11?"); return; } for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct listnode *node2, *nnode2; struct registered_opaque_type *r; for (ALL_LIST_ELEMENTS (apiserv->opaque_types, node2, nnode2, r)) { if (r->lsa_type == OSPF_OPAQUE_AS_LSA) { msg = new_msg_ready_notify (0, OSPF_OPAQUE_AS_LSA, r->opaque_type, id_null); if (!msg) { zlog_warn ("ospf_apiserver_clients_notify_ready_type11: new_msg_ready_notify failed"); #ifdef NOTYET /* Cannot allocate new message. What should we do? */ ospf_apiserver_free (apiserv); #endif goto out; } ospf_apiserver_send_msg (apiserv, msg); msg_free (msg); } } } out: return; } void ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi) { struct msg *msg; msg = new_msg_new_if (0, oi->address->u.prefix4, oi->area->area_id); if (msg != NULL) { ospf_apiserver_clients_notify_all (msg); msg_free (msg); } } void ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi) { struct msg *msg; msg = new_msg_del_if (0, oi->address->u.prefix4); if (msg != NULL) { ospf_apiserver_clients_notify_all (msg); msg_free (msg); } } void ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi) { struct msg *msg; struct in_addr ifaddr = { .s_addr = 0L }; struct in_addr area_id = { .s_addr = 0L }; assert (oi); assert (oi->ifp); if (oi->address) { ifaddr = oi->address->u.prefix4; } if (oi->area) { area_id = oi->area->area_id; } msg = new_msg_ism_change (0, ifaddr, area_id, oi->state); if (!msg) { zlog_warn ("apiserver_clients_notify_ism_change: msg_new failed"); return; } ospf_apiserver_clients_notify_all (msg); msg_free (msg); } void ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr) { struct msg *msg; struct in_addr ifaddr = { .s_addr = 0L }; struct in_addr nbraddr = { .s_addr = 0L }; assert (nbr); if (nbr->oi) { ifaddr = nbr->oi->address->u.prefix4; } nbraddr = nbr->address.u.prefix4; msg = new_msg_nsm_change (0, ifaddr, nbraddr, nbr->router_id, nbr->state); if (!msg) { zlog_warn ("apiserver_clients_notify_nsm_change: msg_new failed"); return; } ospf_apiserver_clients_notify_all (msg); msg_free (msg); } static void apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa) { struct msg *msg; struct listnode *node, *nnode; struct ospf_apiserver *apiserv; /* Default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* Default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { assert (lsa->oi); ifaddr = lsa->oi->address->u.prefix4; } /* Prepare message that can be sent to clients that have a matching filter */ msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */ ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("apiserver_clients_lsa_change_notify: msg_new failed"); return; } /* Now send message to all clients with a matching filter */ for (ALL_LIST_ELEMENTS (apiserver_list, node, nnode, apiserv)) { struct lsa_filter_type *filter; u_int16_t mask; u_int32_t *area; int i; /* Check filter for this client. */ filter = apiserv->filter; /* Check area IDs in case of non AS-E LSAs. * If filter has areas (num_areas > 0), * then one of the areas must match the area ID of this LSA. */ i = filter->num_areas; if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA) || (lsa->data->type == OSPF_OPAQUE_AS_LSA)) { i = 0; } if (i > 0) { area = (u_int32_t *) (filter + 1); while (i) { if (*area == area_id.s_addr) { break; } i--; area++; } } else { i = 1; } if (i > 0) { /* Area match. Check LSA type. */ mask = ntohs (filter->typemask); if (mask & Power2[lsa->data->type]) { /* Type also matches. Check origin. */ if ((filter->origin == ANY_ORIGIN) || (filter->origin == IS_LSA_SELF (lsa))) { ospf_apiserver_send_msg (apiserv, msg); } } } } /* Free message since it is not used anymore */ msg_free (msg); } /* ------------------------------------------------------------- * Followings are hooks invoked when LSAs are updated or deleted * ------------------------------------------------------------- */ static int apiserver_notify_clients_lsa (u_char msgtype, struct ospf_lsa *lsa) { struct msg *msg; /* default area for AS-External and Opaque11 LSAs */ struct in_addr area_id = { .s_addr = 0L }; /* default interface for non Opaque9 LSAs */ struct in_addr ifaddr = { .s_addr = 0L }; /* Only notify this update if the LSA's age is smaller than MAXAGE. Otherwise clients would see LSA updates with max age just before they are deleted from the LSDB. LSA delete messages have MAXAGE too but should not be filtered. */ if (IS_LSA_MAXAGE(lsa) && (msgtype == MSG_LSA_UPDATE_NOTIFY)) { return 0; } if (lsa->area) { area_id = lsa->area->area_id; } if (lsa->data->type == OSPF_OPAQUE_LINK_LSA) { ifaddr = lsa->oi->address->u.prefix4; } msg = new_msg_lsa_change_notify (msgtype, 0L, /* no sequence number */ ifaddr, area_id, lsa->flags & OSPF_LSA_SELF, lsa->data); if (!msg) { zlog_warn ("notify_clients_lsa: msg_new failed"); return -1; } /* Notify all clients that new LSA is added/updated */ apiserver_clients_lsa_change_notify (msgtype, lsa); /* Clients made their own copies of msg so we can free msg here */ msg_free (msg); return 0; } int ospf_apiserver_lsa_update (struct ospf_lsa *lsa) { return apiserver_notify_clients_lsa (MSG_LSA_UPDATE_NOTIFY, lsa); } int ospf_apiserver_lsa_delete (struct ospf_lsa *lsa) { return apiserver_notify_clients_lsa (MSG_LSA_DELETE_NOTIFY, lsa); } #endif /* SUPPORT_OSPF_API */ quagga-0.99.24.1/ospfd/ospf_api.c0000644000175000017500000003715712476520570013330 00000000000000/* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #ifdef SUPPORT_OSPF_API #ifndef HAVE_OPAQUE_LSA #error "Core Opaque-LSA module must be configured." #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "buffer.h" #include "network.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_api.h" /* For debugging only, will be removed */ void api_opaque_lsa_print (struct lsa_header *data) { struct opaque_lsa { struct lsa_header header; u_char mydata[]; }; struct opaque_lsa *olsa; int opaquelen; int i; ospf_lsa_header_dump (data); olsa = (struct opaque_lsa *) data; opaquelen = ntohs (data->length) - OSPF_LSA_HEADER_SIZE; zlog_debug ("apiserver_lsa_print: opaquelen=%d\n", opaquelen); for (i = 0; i < opaquelen; i++) { zlog_debug ("0x%x ", olsa->mydata[i]); } zlog_debug ("\n"); } /* ----------------------------------------------------------- * Generic messages * ----------------------------------------------------------- */ struct msg * msg_new (u_char msgtype, void *msgbody, u_int32_t seqnum, u_int16_t msglen) { struct msg *new; new = XCALLOC (MTYPE_OSPF_API_MSG, sizeof (struct msg)); new->hdr.version = OSPF_API_VERSION; new->hdr.msgtype = msgtype; new->hdr.msglen = htons (msglen); new->hdr.msgseq = htonl (seqnum); new->s = stream_new (msglen); assert (new->s); stream_put (new->s, msgbody, msglen); return new; } /* Duplicate a message by copying content. */ struct msg * msg_dup (struct msg *msg) { struct msg *new; assert (msg); new = msg_new (msg->hdr.msgtype, STREAM_DATA (msg->s), ntohl (msg->hdr.msgseq), ntohs (msg->hdr.msglen)); return new; } /* XXX only for testing, will be removed */ struct nametab { int value; const char *name; }; const char * ospf_api_typename (int msgtype) { struct nametab NameTab[] = { { MSG_REGISTER_OPAQUETYPE, "Register opaque-type", }, { MSG_UNREGISTER_OPAQUETYPE, "Unregister opaque-type", }, { MSG_REGISTER_EVENT, "Register event", }, { MSG_SYNC_LSDB, "Sync LSDB", }, { MSG_ORIGINATE_REQUEST, "Originate request", }, { MSG_DELETE_REQUEST, "Delete request", }, { MSG_REPLY, "Reply", }, { MSG_READY_NOTIFY, "Ready notify", }, { MSG_LSA_UPDATE_NOTIFY, "LSA update notify", }, { MSG_LSA_DELETE_NOTIFY, "LSA delete notify", }, { MSG_NEW_IF, "New interface", }, { MSG_DEL_IF, "Del interface", }, { MSG_ISM_CHANGE, "ISM change", }, { MSG_NSM_CHANGE, "NSM change", }, }; int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) { if (NameTab[i].value == msgtype) { name = NameTab[i].name; break; } } return name ? name : "?"; } const char * ospf_api_errname (int errcode) { struct nametab NameTab[] = { { OSPF_API_OK, "OK", }, { OSPF_API_NOSUCHINTERFACE, "No such interface", }, { OSPF_API_NOSUCHAREA, "No such area", }, { OSPF_API_NOSUCHLSA, "No such LSA", }, { OSPF_API_ILLEGALLSATYPE, "Illegal LSA type", }, { OSPF_API_OPAQUETYPEINUSE, "Opaque type in use", }, { OSPF_API_OPAQUETYPENOTREGISTERED, "Opaque type not registered", }, { OSPF_API_NOTREADY, "Not ready", }, { OSPF_API_NOMEMORY, "No memory", }, { OSPF_API_ERROR, "Other error", }, { OSPF_API_UNDEF, "Undefined", }, }; int i, n = array_size(NameTab); const char *name = NULL; for (i = 0; i < n; i++) { if (NameTab[i].value == errcode) { name = NameTab[i].name; break; } } return name ? name : "?"; } void msg_print (struct msg *msg) { if (!msg) { zlog_debug ("msg_print msg=NULL!\n"); return; } #ifdef ORIGINAL_CODING zlog_debug ("msg=%p msgtype=%d msglen=%d msgseq=%d streamdata=%p streamsize=%lu\n", msg, msg->hdr.msgtype, ntohs (msg->hdr.msglen), ntohl (msg->hdr.msgseq), STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); #else /* ORIGINAL_CODING */ /* API message common header part. */ zlog_debug ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)", ospf_api_typename (msg->hdr.msgtype), msg->hdr.msgtype, ntohs (msg->hdr.msglen), (unsigned long) ntohl (msg->hdr.msgseq), STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); /* API message body part. */ #ifdef ndef /* Generic Hex/Ascii dump */ DumpBuf (STREAM_DATA (msg->s), STREAM_SIZE (msg->s)); /* Sorry, deleted! */ #else /* ndef */ /* Message-type dependent dump function. */ #endif /* ndef */ return; #endif /* ORIGINAL_CODING */ } void msg_free (struct msg *msg) { if (msg->s) stream_free (msg->s); XFREE (MTYPE_OSPF_API_MSG, msg); } /* Set sequence number of message */ void msg_set_seq (struct msg *msg, u_int32_t seqnr) { assert (msg); msg->hdr.msgseq = htonl (seqnr); } /* Get sequence number of message */ u_int32_t msg_get_seq (struct msg *msg) { assert (msg); return ntohl (msg->hdr.msgseq); } /* ----------------------------------------------------------- * Message fifo queues * ----------------------------------------------------------- */ struct msg_fifo * msg_fifo_new () { return XCALLOC (MTYPE_OSPF_API_FIFO, sizeof (struct msg_fifo)); } /* Add new message to fifo. */ void msg_fifo_push (struct msg_fifo *fifo, struct msg *msg) { if (fifo->tail) fifo->tail->next = msg; else fifo->head = msg; fifo->tail = msg; fifo->count++; } /* Remove first message from fifo. */ struct msg * msg_fifo_pop (struct msg_fifo *fifo) { struct msg *msg; msg = fifo->head; if (msg) { fifo->head = msg->next; if (fifo->head == NULL) fifo->tail = NULL; fifo->count--; } return msg; } /* Return first fifo entry but do not remove it. */ struct msg * msg_fifo_head (struct msg_fifo *fifo) { return fifo->head; } /* Flush message fifo. */ void msg_fifo_flush (struct msg_fifo *fifo) { struct msg *op; struct msg *next; for (op = fifo->head; op; op = next) { next = op->next; msg_free (op); } fifo->head = fifo->tail = NULL; fifo->count = 0; } /* Free API message fifo. */ void msg_fifo_free (struct msg_fifo *fifo) { msg_fifo_flush (fifo); XFREE (MTYPE_OSPF_API_FIFO, fifo); } struct msg * msg_read (int fd) { struct msg *msg; struct apimsghdr hdr; u_char buf[OSPF_API_MAX_MSG_SIZE]; int bodylen; int rlen; /* Read message header */ rlen = readn (fd, (u_char *) &hdr, sizeof (struct apimsghdr)); if (rlen < 0) { zlog_warn ("msg_read: readn %s", safe_strerror (errno)); return NULL; } else if (rlen == 0) { zlog_warn ("msg_read: Connection closed by peer"); return NULL; } else if (rlen != sizeof (struct apimsghdr)) { zlog_warn ("msg_read: Cannot read message header!"); return NULL; } /* Check version of API protocol */ if (hdr.version != OSPF_API_VERSION) { zlog_warn ("msg_read: OSPF API protocol version mismatch"); return NULL; } /* Determine body length. */ bodylen = ntohs (hdr.msglen); if (bodylen > 0) { /* Read message body */ rlen = readn (fd, buf, bodylen); if (rlen < 0) { zlog_warn ("msg_read: readn %s", safe_strerror (errno)); return NULL; } else if (rlen == 0) { zlog_warn ("msg_read: Connection closed by peer"); return NULL; } else if (rlen != bodylen) { zlog_warn ("msg_read: Cannot read message body!"); return NULL; } } /* Allocate new message */ msg = msg_new (hdr.msgtype, buf, ntohl (hdr.msgseq), ntohs (hdr.msglen)); return msg; } int msg_write (int fd, struct msg *msg) { u_char buf[OSPF_API_MAX_MSG_SIZE]; int l; int wlen; assert (msg); assert (msg->s); /* Length of message including header */ l = sizeof (struct apimsghdr) + ntohs (msg->hdr.msglen); /* Make contiguous memory buffer for message */ memcpy (buf, &msg->hdr, sizeof (struct apimsghdr)); memcpy (buf + sizeof (struct apimsghdr), STREAM_DATA (msg->s), ntohs (msg->hdr.msglen)); wlen = writen (fd, buf, l); if (wlen < 0) { zlog_warn ("msg_write: writen %s", safe_strerror (errno)); return -1; } else if (wlen == 0) { zlog_warn ("msg_write: Connection closed by peer"); return -1; } else if (wlen != l) { zlog_warn ("msg_write: Cannot write API message"); return -1; } return 0; } /* ----------------------------------------------------------- * Specific messages * ----------------------------------------------------------- */ struct msg * new_msg_register_opaque_type (u_int32_t seqnum, u_char ltype, u_char otype) { struct msg_register_opaque_type rmsg; rmsg.lsatype = ltype; rmsg.opaquetype = otype; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); return msg_new (MSG_REGISTER_OPAQUETYPE, &rmsg, seqnum, sizeof (struct msg_register_opaque_type)); } struct msg * new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_register_event *emsg; size_t len; emsg = (struct msg_register_event *) buf; len = sizeof (struct msg_register_event) + filter->num_areas * sizeof (struct in_addr); emsg->filter.typemask = htons (filter->typemask); emsg->filter.origin = filter->origin; emsg->filter.num_areas = filter->num_areas; if (len > sizeof (buf)) len = sizeof(buf); /* API broken - missing memcpy to fill data */ return msg_new (MSG_REGISTER_EVENT, emsg, seqnum, len); } struct msg * new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_sync_lsdb *smsg; size_t len; smsg = (struct msg_sync_lsdb *) buf; len = sizeof (struct msg_sync_lsdb) + filter->num_areas * sizeof (struct in_addr); smsg->filter.typemask = htons (filter->typemask); smsg->filter.origin = filter->origin; smsg->filter.num_areas = filter->num_areas; if (len > sizeof (buf)) len = sizeof(buf); /* API broken - missing memcpy to fill data */ return msg_new (MSG_SYNC_LSDB, smsg, seqnum, len); } struct msg * new_msg_originate_request (u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, struct lsa_header *data) { struct msg_originate_request *omsg; size_t omsglen; char buf[OSPF_API_MAX_MSG_SIZE]; omsg = (struct msg_originate_request *) buf; omsg->ifaddr = ifaddr; omsg->area_id = area_id; omsglen = ntohs (data->length); if (omsglen > sizeof (buf) - offsetof (struct msg_originate_request, data)) omsglen = sizeof (buf) - offsetof (struct msg_originate_request, data); memcpy (&omsg->data, data, omsglen); omsglen += sizeof (struct msg_originate_request) - sizeof (struct lsa_header); return msg_new (MSG_ORIGINATE_REQUEST, omsg, seqnum, omsglen); } struct msg * new_msg_delete_request (u_int32_t seqnum, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id) { struct msg_delete_request dmsg; dmsg.area_id = area_id; dmsg.lsa_type = lsa_type; dmsg.opaque_type = opaque_type; dmsg.opaque_id = htonl (opaque_id); memset (&dmsg.pad, 0, sizeof (dmsg.pad)); return msg_new (MSG_DELETE_REQUEST, &dmsg, seqnum, sizeof (struct msg_delete_request)); } struct msg * new_msg_reply (u_int32_t seqnr, u_char rc) { struct msg *msg; struct msg_reply rmsg; /* Set return code */ rmsg.errcode = rc; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); msg = msg_new (MSG_REPLY, &rmsg, seqnr, sizeof (struct msg_reply)); return msg; } struct msg * new_msg_ready_notify (u_int32_t seqnr, u_char lsa_type, u_char opaque_type, struct in_addr addr) { struct msg_ready_notify rmsg; rmsg.lsa_type = lsa_type; rmsg.opaque_type = opaque_type; memset (&rmsg.pad, 0, sizeof (rmsg.pad)); rmsg.addr = addr; return msg_new (MSG_READY_NOTIFY, &rmsg, seqnr, sizeof (struct msg_ready_notify)); } struct msg * new_msg_new_if (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area_id) { struct msg_new_if nmsg; nmsg.ifaddr = ifaddr; nmsg.area_id = area_id; return msg_new (MSG_NEW_IF, &nmsg, seqnr, sizeof (struct msg_new_if)); } struct msg * new_msg_del_if (u_int32_t seqnr, struct in_addr ifaddr) { struct msg_del_if dmsg; dmsg.ifaddr = ifaddr; return msg_new (MSG_DEL_IF, &dmsg, seqnr, sizeof (struct msg_del_if)); } struct msg * new_msg_ism_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area_id, u_char status) { struct msg_ism_change imsg; imsg.ifaddr = ifaddr; imsg.area_id = area_id; imsg.status = status; memset (&imsg.pad, 0, sizeof (imsg.pad)); return msg_new (MSG_ISM_CHANGE, &imsg, seqnr, sizeof (struct msg_ism_change)); } struct msg * new_msg_nsm_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status) { struct msg_nsm_change nmsg; nmsg.ifaddr = ifaddr; nmsg.nbraddr = nbraddr; nmsg.router_id = router_id; nmsg.status = status; memset (&nmsg.pad, 0, sizeof (nmsg.pad)); return msg_new (MSG_NSM_CHANGE, &nmsg, seqnr, sizeof (struct msg_nsm_change)); } struct msg * new_msg_lsa_change_notify (u_char msgtype, u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *data) { u_char buf[OSPF_API_MAX_MSG_SIZE]; struct msg_lsa_change_notify *nmsg; size_t len; assert (data); nmsg = (struct msg_lsa_change_notify *) buf; nmsg->ifaddr = ifaddr; nmsg->area_id = area_id; nmsg->is_self_originated = is_self_originated; memset (&nmsg->pad, 0, sizeof (nmsg->pad)); len = ntohs (data->length); if (len > sizeof (buf) - offsetof (struct msg_lsa_change_notify, data)) len = sizeof (buf) - offsetof (struct msg_lsa_change_notify, data); memcpy (&nmsg->data, data, len); len += sizeof (struct msg_lsa_change_notify) - sizeof (struct lsa_header); return msg_new (msgtype, nmsg, seqnum, len); } #endif /* SUPPORT_OSPF_API */ quagga-0.99.24.1/ospfd/ospf_vty.c0000644000175000017500000066761412476520570013410 00000000000000/* OSPF VTY interface. * Copyright (C) 2005 6WIND * Copyright (C) 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "thread.h" #include "prefix.h" #include "table.h" #include "vty.h" #include "command.h" #include "plist.h" #include "log.h" #include "zclient.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" /*#include "ospfd/ospf_routemap.h" */ #include "ospfd/ospf_vty.h" #include "ospfd/ospf_dump.h" static const char *ospf_network_type_str[] = { "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT", "VIRTUALLINK", "LOOPBACK" }; /* Utility functions. */ static int ospf_str2area_id (const char *str, struct in_addr *area_id, int *format) { char *endptr = NULL; unsigned long ret; /* match "A.B.C.D". */ if (strchr (str, '.') != NULL) { ret = inet_aton (str, area_id); if (!ret) return -1; *format = OSPF_AREA_ID_FORMAT_ADDRESS; } /* match "<0-4294967295>". */ else { if (*str == '-') return -1; errno = 0; ret = strtoul (str, &endptr, 10); if (*endptr != '\0' || errno || ret > UINT32_MAX) return -1; area_id->s_addr = htonl (ret); *format = OSPF_AREA_ID_FORMAT_DECIMAL; } return 0; } static int str2metric (const char *str, int *metric) { /* Sanity check. */ if (str == NULL) return 0; *metric = strtol (str, NULL, 10); if (*metric < 0 && *metric > 16777214) { /* vty_out (vty, "OSPF metric value is invalid%s", VTY_NEWLINE); */ return 0; } return 1; } static int str2metric_type (const char *str, int *metric_type) { /* Sanity check. */ if (str == NULL) return 0; if (strncmp (str, "1", 1) == 0) *metric_type = EXTERNAL_METRIC_TYPE_1; else if (strncmp (str, "2", 1) == 0) *metric_type = EXTERNAL_METRIC_TYPE_2; else return 0; return 1; } int ospf_oi_count (struct interface *ifp) { struct route_node *rn; int i = 0; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if (rn->info) i++; return i; } DEFUN (router_ospf, router_ospf_cmd, "router ospf", "Enable a routing process\n" "Start OSPF configuration\n") { vty->node = OSPF_NODE; vty->index = ospf_get (); return CMD_SUCCESS; } DEFUN (no_router_ospf, no_router_ospf_cmd, "no router ospf", NO_STR "Enable a routing process\n" "Start OSPF configuration\n") { struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, "There isn't active ospf instance%s", VTY_NEWLINE); return CMD_WARNING; } ospf_finish (ospf); return CMD_SUCCESS; } DEFUN (ospf_router_id, ospf_router_id_cmd, "ospf router-id A.B.C.D", "OSPF specific commands\n" "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") { struct ospf *ospf = vty->index; struct in_addr router_id; int ret; ret = inet_aton (argv[0], &router_id); if (!ret) { vty_out (vty, "Please specify Router ID by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } ospf->router_id_static = router_id; ospf_router_id_update (ospf); return CMD_SUCCESS; } ALIAS (ospf_router_id, router_ospf_id_cmd, "router-id A.B.C.D", "router-id for the OSPF process\n" "OSPF router-id in IP address format\n") DEFUN (no_ospf_router_id, no_ospf_router_id_cmd, "no ospf router-id", NO_STR "OSPF specific commands\n" "router-id for the OSPF process\n") { struct ospf *ospf = vty->index; ospf->router_id_static.s_addr = 0; ospf_router_id_update (ospf); return CMD_SUCCESS; } ALIAS (no_ospf_router_id, no_router_ospf_id_cmd, "no router-id", NO_STR "router-id for the OSPF process\n") static void ospf_passive_interface_default (struct ospf *ospf, u_char newval) { struct listnode *ln; struct interface *ifp; struct ospf_interface *oi; ospf->passive_interface_default = newval; for (ALL_LIST_ELEMENTS_RO (om->iflist, ln, ifp)) { if (ifp && OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface)) UNSET_IF_PARAM (IF_DEF_PARAMS (ifp), passive_interface); } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ln, oi)) { if (OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface)) UNSET_IF_PARAM (oi->params, passive_interface); /* update multicast memberships */ ospf_if_set_multicast(oi); } } static void ospf_passive_interface_update (struct ospf *ospf, struct interface *ifp, struct in_addr addr, struct ospf_if_params *params, u_char value) { u_char dflt; params->passive_interface = value; if (params != IF_DEF_PARAMS (ifp)) { if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface)) dflt = IF_DEF_PARAMS (ifp)->passive_interface; else dflt = ospf->passive_interface_default; if (value != dflt) SET_IF_PARAM (params, passive_interface); else UNSET_IF_PARAM (params, passive_interface); ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } else { if (value != ospf->passive_interface_default) SET_IF_PARAM (params, passive_interface); else UNSET_IF_PARAM (params, passive_interface); } } DEFUN (ospf_passive_interface, ospf_passive_interface_addr_cmd, "passive-interface IFNAME A.B.C.D", "Suppress routing updates on an interface\n" "Interface's name\n") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; struct route_node *rn; struct ospf *ospf = vty->index; if (argc == 0) { ospf_passive_interface_default (ospf, OSPF_IF_PASSIVE); return CMD_SUCCESS; } ifp = if_get_by_name (argv[0]); params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } ospf_passive_interface_update (ospf, ifp, addr, params, OSPF_IF_PASSIVE); /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much * work to determine this set, so we do this for every interface. * This is safe and reasonable because ospf_if_set_multicast uses a * record of joined groups to avoid systems calls if the desired * memberships match the current memership. */ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi && (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_PASSIVE)) ospf_if_set_multicast(oi); } /* * XXX It is not clear what state transitions the interface needs to * undergo when going from active to passive. Fixing this will * require precise identification of interfaces having such a * transition. */ return CMD_SUCCESS; } ALIAS (ospf_passive_interface, ospf_passive_interface_cmd, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface's name\n") ALIAS (ospf_passive_interface, ospf_passive_interface_default_cmd, "passive-interface default", "Suppress routing updates on an interface\n" "Suppress routing updates on interfaces by default\n") DEFUN (no_ospf_passive_interface, no_ospf_passive_interface_addr_cmd, "no passive-interface IFNAME A.B.C.D", NO_STR "Allow routing updates on an interface\n" "Interface's name\n") { struct interface *ifp; struct in_addr addr; struct ospf_if_params *params; int ret; struct route_node *rn; struct ospf *ospf = vty->index; if (argc == 0) { ospf_passive_interface_default (ospf, OSPF_IF_ACTIVE); return CMD_SUCCESS; } ifp = if_get_by_name (argv[0]); params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } ospf_passive_interface_update (ospf, ifp, addr, params, OSPF_IF_ACTIVE); /* XXX We should call ospf_if_set_multicast on exactly those * interfaces for which the passive property changed. It is too much * work to determine this set, so we do this for every interface. * This is safe and reasonable because ospf_if_set_multicast uses a * record of joined groups to avoid systems calls if the desired * memberships match the current memership. */ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi && (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE)) ospf_if_set_multicast(oi); } return CMD_SUCCESS; } ALIAS (no_ospf_passive_interface, no_ospf_passive_interface_cmd, "no passive-interface IFNAME", NO_STR "Allow routing updates on an interface\n" "Interface's name\n") ALIAS (no_ospf_passive_interface, no_ospf_passive_interface_default_cmd, "no passive-interface default", NO_STR "Allow routing updates on an interface\n" "Allow routing updates on interfaces by default\n") DEFUN (ospf_network_area, ospf_network_area_cmd, "network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", "Enable routing on an IP network\n" "OSPF network prefix\n" "Set the OSPF area ID\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") { struct ospf *ospf= vty->index; struct prefix_ipv4 p; struct in_addr area_id; int ret, format; /* Get network prefix and Area ID. */ VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); ret = ospf_network_set (ospf, &p, area_id); if (ret == 0) { vty_out (vty, "There is already same network statement.%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_ospf_network_area, no_ospf_network_area_cmd, "no network A.B.C.D/M area (A.B.C.D|<0-4294967295>)", NO_STR "Enable routing on an IP network\n" "OSPF network prefix\n" "Set the OSPF area ID\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n") { struct ospf *ospf = (struct ospf *) vty->index; struct prefix_ipv4 p; struct in_addr area_id; int ret, format; /* Get network prefix and Area ID. */ VTY_GET_IPV4_PREFIX ("network prefix", p, argv[0]); VTY_GET_OSPF_AREA_ID (area_id, format, argv[1]); ret = ospf_network_unset (ospf, &p, area_id); if (ret == 0) { vty_out (vty, "Can't find specified network area configuration.%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (ospf_area_range, ospf_area_range_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p; struct in_addr area_id; int format; u_int32_t cost; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); ospf_area_range_set (ospf, area_id, &p, OSPF_AREA_RANGE_ADVERTISE); if (argc > 2) { VTY_GET_INTEGER ("range cost", cost, argv[2]); ospf_area_range_cost_set (ospf, area_id, &p, cost); } return CMD_SUCCESS; } ALIAS (ospf_area_range, ospf_area_range_advertise_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "OSPF area range for route advertise (default)\n" "Area range prefix\n" "Advertise this range (default)\n") ALIAS (ospf_area_range, ospf_area_range_cost_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "User specified metric for this range\n" "Advertised metric for this range\n") ALIAS (ospf_area_range, ospf_area_range_advertise_cost_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFUN (ospf_area_range_not_advertise, ospf_area_range_not_advertise_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M not-advertise", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "DoNotAdvertise this range\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); ospf_area_range_set (ospf, area_id, &p, 0); return CMD_SUCCESS; } DEFUN (no_ospf_area_range, no_ospf_area_range_cmd, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); ospf_area_range_unset (ospf, area_id, &p); return CMD_SUCCESS; } ALIAS (no_ospf_area_range, no_ospf_area_range_advertise_cmd, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M (advertise|not-advertise)", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "DoNotAdvertise this range\n") ALIAS (no_ospf_area_range, no_ospf_area_range_cost_cmd, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M cost <0-16777215>", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "User specified metric for this range\n" "Advertised metric for this range\n") ALIAS (no_ospf_area_range, no_ospf_area_range_advertise_cost_cmd, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M advertise cost <0-16777215>", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Advertise this range (default)\n" "User specified metric for this range\n" "Advertised metric for this range\n") DEFUN (ospf_area_range_substitute, ospf_area_range_substitute_cmd, "area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p, s; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); ospf_area_range_substitute_set (ospf, area_id, &p, &s); return CMD_SUCCESS; } DEFUN (no_ospf_area_range_substitute, no_ospf_area_range_substitute_cmd, "no area (A.B.C.D|<0-4294967295>) range A.B.C.D/M substitute A.B.C.D/M", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Summarize routes matching address/mask (border routers only)\n" "Area range prefix\n" "Announce area range as another prefix\n" "Network prefix to be announced instead of range\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p, s; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); VTY_GET_IPV4_PREFIX ("area range", p, argv[1]); VTY_GET_IPV4_PREFIX ("substituted network prefix", s, argv[2]); ospf_area_range_substitute_unset (ospf, area_id, &p); return CMD_SUCCESS; } /* Command Handler Logic in VLink stuff is delicate!! ALTER AT YOUR OWN RISK!!!! Various dummy values are used to represent 'NoChange' state for VLink configuration NOT being changed by a VLink command, and special syntax is used within the command strings so that the typed in command verbs can be seen in the configuration command bacckend handler. This is to drastically reduce the verbeage required to coe up with a reasonably compatible Cisco VLink command - Matthew Grant Wed, 21 Feb 2001 15:13:52 +1300 */ /* Configuration data for virtual links */ struct ospf_vl_config_data { struct vty *vty; /* vty stuff */ struct in_addr area_id; /* area ID from command line */ int format; /* command line area ID format */ struct in_addr vl_peer; /* command line vl_peer */ int auth_type; /* Authehntication type, if given */ char *auth_key; /* simple password if present */ int crypto_key_id; /* Cryptographic key ID */ char *md5_key; /* MD5 authentication key */ int hello_interval; /* Obvious what these are... */ int retransmit_interval; int transmit_delay; int dead_interval; }; static void ospf_vl_config_data_init (struct ospf_vl_config_data *vl_config, struct vty *vty) { memset (vl_config, 0, sizeof (struct ospf_vl_config_data)); vl_config->auth_type = OSPF_AUTH_CMD_NOTSEEN; vl_config->vty = vty; } static struct ospf_vl_data * ospf_find_vl_data (struct ospf *ospf, struct ospf_vl_config_data *vl_config) { struct ospf_area *area; struct ospf_vl_data *vl_data; struct vty *vty; struct in_addr area_id; vty = vl_config->vty; area_id = vl_config->area_id; if (area_id.s_addr == OSPF_AREA_BACKBONE) { vty_out (vty, "Configuring VLs over the backbone is not allowed%s", VTY_NEWLINE); return NULL; } area = ospf_area_get (ospf, area_id, vl_config->format); if (area->external_routing != OSPF_AREA_DEFAULT) { if (vl_config->format == OSPF_AREA_ID_FORMAT_ADDRESS) vty_out (vty, "Area %s is %s%s", inet_ntoa (area_id), area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", VTY_NEWLINE); else vty_out (vty, "Area %ld is %s%s", (u_long)ntohl (area_id.s_addr), area->external_routing == OSPF_AREA_NSSA?"nssa":"stub", VTY_NEWLINE); return NULL; } if ((vl_data = ospf_vl_lookup (ospf, area, vl_config->vl_peer)) == NULL) { vl_data = ospf_vl_data_new (area, vl_config->vl_peer); if (vl_data->vl_oi == NULL) { vl_data->vl_oi = ospf_vl_new (ospf, vl_data); ospf_vl_add (ospf, vl_data); ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } } return vl_data; } static int ospf_vl_set_security (struct ospf_vl_data *vl_data, struct ospf_vl_config_data *vl_config) { struct crypt_key *ck; struct vty *vty; struct interface *ifp = vl_data->vl_oi->ifp; vty = vl_config->vty; if (vl_config->auth_type != OSPF_AUTH_CMD_NOTSEEN) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); IF_DEF_PARAMS (ifp)->auth_type = vl_config->auth_type; } if (vl_config->auth_key) { memset(IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE+1); strncpy ((char *) IF_DEF_PARAMS (ifp)->auth_simple, vl_config->auth_key, OSPF_AUTH_SIMPLE_SIZE); } else if (vl_config->md5_key) { if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id) != NULL) { vty_out (vty, "OSPF: Key %d already exists%s", vl_config->crypto_key_id, VTY_NEWLINE); return CMD_WARNING; } ck = ospf_crypt_key_new (); ck->key_id = vl_config->crypto_key_id; memset(ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); strncpy ((char *) ck->auth_key, vl_config->md5_key, OSPF_AUTH_MD5_SIZE); ospf_crypt_key_add (IF_DEF_PARAMS (ifp)->auth_crypt, ck); } else if (vl_config->crypto_key_id != 0) { /* Delete a key */ if (ospf_crypt_key_lookup (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id) == NULL) { vty_out (vty, "OSPF: Key %d does not exist%s", vl_config->crypto_key_id, VTY_NEWLINE); return CMD_WARNING; } ospf_crypt_key_delete (IF_DEF_PARAMS (ifp)->auth_crypt, vl_config->crypto_key_id); } return CMD_SUCCESS; } static int ospf_vl_set_timers (struct ospf_vl_data *vl_data, struct ospf_vl_config_data *vl_config) { struct interface *ifp = ifp = vl_data->vl_oi->ifp; /* Virtual Link data initialised to defaults, so only set if a value given */ if (vl_config->hello_interval) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); IF_DEF_PARAMS (ifp)->v_hello = vl_config->hello_interval; } if (vl_config->dead_interval) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); IF_DEF_PARAMS (ifp)->v_wait = vl_config->dead_interval; } if (vl_config->retransmit_interval) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); IF_DEF_PARAMS (ifp)->retransmit_interval = vl_config->retransmit_interval; } if (vl_config->transmit_delay) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); IF_DEF_PARAMS (ifp)->transmit_delay = vl_config->transmit_delay; } return CMD_SUCCESS; } /* The business end of all of the above */ static int ospf_vl_set (struct ospf *ospf, struct ospf_vl_config_data *vl_config) { struct ospf_vl_data *vl_data; int ret; vl_data = ospf_find_vl_data (ospf, vl_config); if (!vl_data) return CMD_WARNING; /* Process this one first as it can have a fatal result, which can only logically occur if the virtual link exists already Thus a command error does not result in a change to the running configuration such as unexpectedly altered timer values etc.*/ ret = ospf_vl_set_security (vl_data, vl_config); if (ret != CMD_SUCCESS) return ret; /* Set any time based parameters, these area already range checked */ ret = ospf_vl_set_timers (vl_data, vl_config); if (ret != CMD_SUCCESS) return ret; return CMD_SUCCESS; } /* This stuff exists to make specifying all the alias commands A LOT simpler */ #define VLINK_HELPSTR_IPADDR \ "OSPF area parameters\n" \ "OSPF area ID in IP address format\n" \ "OSPF area ID as a decimal value\n" \ "Configure a virtual link\n" \ "Router ID of the remote ABR\n" #define VLINK_HELPSTR_AUTHTYPE_SIMPLE \ "Enable authentication on this virtual link\n" \ "dummy string \n" #define VLINK_HELPSTR_AUTHTYPE_ALL \ VLINK_HELPSTR_AUTHTYPE_SIMPLE \ "Use null authentication\n" \ "Use message-digest authentication\n" #define VLINK_HELPSTR_TIME_PARAM_NOSECS \ "Time between HELLO packets\n" \ "Time between retransmitting lost link state advertisements\n" \ "Link state transmit delay\n" \ "Interval after which a neighbor is declared dead\n" #define VLINK_HELPSTR_TIME_PARAM \ VLINK_HELPSTR_TIME_PARAM_NOSECS \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ "Authentication password (key)\n" \ "The OSPF password (key)" #define VLINK_HELPSTR_AUTH_MD5 \ "Message digest authentication password (key)\n" \ "dummy string \n" \ "Key ID\n" \ "Use MD5 algorithm\n" \ "The OSPF password (key)" DEFUN (ospf_area_vlink, ospf_area_vlink_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", VLINK_HELPSTR_IPADDR) { struct ospf *ospf = vty->index; struct ospf_vl_config_data vl_config; char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; char md5_key[OSPF_AUTH_MD5_SIZE+1]; int i; int ret; ospf_vl_config_data_init(&vl_config, vty); /* Read off first 2 parameters and check them */ ret = ospf_str2area_id (argv[0], &vl_config.area_id, &vl_config.format); if (ret < 0) { vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); return CMD_WARNING; } ret = inet_aton (argv[1], &vl_config.vl_peer); if (! ret) { vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", VTY_NEWLINE); return CMD_WARNING; } if (argc <=2) { /* Thats all folks! - BUGS B. strikes again!!!*/ return ospf_vl_set (ospf, &vl_config); } /* Deal with other parameters */ for (i=2; i < argc; i++) { /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ switch (argv[i][0]) { case 'a': if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) { /* authentication-key - this option can occur anywhere on command line. At start of command line must check for authentication option. */ memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); strncpy (auth_key, argv[i+1], OSPF_AUTH_SIMPLE_SIZE); vl_config.auth_key = auth_key; i++; } else if (strncmp (argv[i], "authentication", 14) == 0) { /* authentication - this option can only occur at start of command line */ vl_config.auth_type = OSPF_AUTH_SIMPLE; if ((i+1) < argc) { if (strncmp (argv[i+1], "n", 1) == 0) { /* "authentication null" */ vl_config.auth_type = OSPF_AUTH_NULL; i++; } else if (strncmp (argv[i+1], "m", 1) == 0 && strcmp (argv[i+1], "message-digest-") != 0) { /* "authentication message-digest" */ vl_config.auth_type = OSPF_AUTH_CRYPTOGRAPHIC; i++; } } } break; case 'm': /* message-digest-key */ i++; vl_config.crypto_key_id = strtol (argv[i], NULL, 10); if (vl_config.crypto_key_id < 0) return CMD_WARNING; i++; memset(md5_key, 0, OSPF_AUTH_MD5_SIZE+1); strncpy (md5_key, argv[i], OSPF_AUTH_MD5_SIZE); vl_config.md5_key = md5_key; break; case 'h': /* Hello interval */ i++; vl_config.hello_interval = strtol (argv[i], NULL, 10); if (vl_config.hello_interval < 0) return CMD_WARNING; break; case 'r': /* Retransmit Interval */ i++; vl_config.retransmit_interval = strtol (argv[i], NULL, 10); if (vl_config.retransmit_interval < 0) return CMD_WARNING; break; case 't': /* Transmit Delay */ i++; vl_config.transmit_delay = strtol (argv[i], NULL, 10); if (vl_config.transmit_delay < 0) return CMD_WARNING; break; case 'd': /* Dead Interval */ i++; vl_config.dead_interval = strtol (argv[i], NULL, 10); if (vl_config.dead_interval < 0) return CMD_WARNING; break; } } /* Action configuration */ return ospf_vl_set (ospf, &vl_config); } DEFUN (no_ospf_area_vlink, no_ospf_area_vlink_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D", NO_STR VLINK_HELPSTR_IPADDR) { struct ospf *ospf = vty->index; struct ospf_area *area; struct ospf_vl_config_data vl_config; struct ospf_vl_data *vl_data = NULL; char auth_key[OSPF_AUTH_SIMPLE_SIZE+1]; int i; int ret, format; ospf_vl_config_data_init(&vl_config, vty); ret = ospf_str2area_id (argv[0], &vl_config.area_id, &format); if (ret < 0) { vty_out (vty, "OSPF area ID is invalid%s", VTY_NEWLINE); return CMD_WARNING; } area = ospf_area_lookup_by_area_id (ospf, vl_config.area_id); if (!area) { vty_out (vty, "Area does not exist%s", VTY_NEWLINE); return CMD_WARNING; } ret = inet_aton (argv[1], &vl_config.vl_peer); if (! ret) { vty_out (vty, "Please specify valid Router ID as a.b.c.d%s", VTY_NEWLINE); return CMD_WARNING; } if (argc <=2) { /* Basic VLink no command */ /* Thats all folks! - BUGS B. strikes again!!!*/ if ((vl_data = ospf_vl_lookup (ospf, area, vl_config.vl_peer))) ospf_vl_delete (ospf, vl_data); ospf_area_check_free (ospf, vl_config.area_id); return CMD_SUCCESS; } /* If we are down here, we are reseting parameters */ /* Deal with other parameters */ for (i=2; i < argc; i++) { /* vty_out (vty, "argv[%d] - %s%s", i, argv[i], VTY_NEWLINE); */ switch (argv[i][0]) { case 'a': if (i > 2 || strncmp (argv[i], "authentication-", 15) == 0) { /* authentication-key - this option can occur anywhere on command line. At start of command line must check for authentication option. */ memset (auth_key, 0, OSPF_AUTH_SIMPLE_SIZE + 1); vl_config.auth_key = auth_key; } else if (strncmp (argv[i], "authentication", 14) == 0) { /* authentication - this option can only occur at start of command line */ vl_config.auth_type = OSPF_AUTH_NOTSET; } break; case 'm': /* message-digest-key */ /* Delete one key */ i++; vl_config.crypto_key_id = strtol (argv[i], NULL, 10); if (vl_config.crypto_key_id < 0) return CMD_WARNING; vl_config.md5_key = NULL; break; case 'h': /* Hello interval */ vl_config.hello_interval = OSPF_HELLO_INTERVAL_DEFAULT; break; case 'r': /* Retransmit Interval */ vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; break; case 't': /* Transmit Delay */ vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; break; case 'd': /* Dead Interval */ i++; vl_config.dead_interval = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; break; } } /* Action configuration */ return ospf_vl_set (ospf, &vl_config); } ALIAS (ospf_area_vlink, ospf_area_vlink_param1_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_param1_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) ALIAS (ospf_area_vlink, ospf_area_vlink_param2_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_param2_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (ospf_area_vlink, ospf_area_vlink_param3_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_param3_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (ospf_area_vlink, ospf_area_vlink_param4_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535> " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) <1-65535>", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_param4_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval) " "(hello-interval|retransmit-interval|transmit-delay|dead-interval)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM VLINK_HELPSTR_TIME_PARAM) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_args_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null)", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_ALL) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|)", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_authtype_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE) ALIAS (ospf_area_vlink, ospf_area_vlink_md5_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(message-digest-key|) <1-255> md5 KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTH_MD5) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_md5_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(message-digest-key|) <1-255>", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTH_MD5) ALIAS (ospf_area_vlink, ospf_area_vlink_authkey_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication-key|) AUTH_KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTH_SIMPLE) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_authkey_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication-key|)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTH_SIMPLE) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_args_authkey_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null) " "(authentication-key|) AUTH_KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_ALL VLINK_HELPSTR_AUTH_SIMPLE) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_authkey_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(authentication-key|) AUTH_KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE VLINK_HELPSTR_AUTH_SIMPLE) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_authtype_authkey_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(authentication-key|)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE VLINK_HELPSTR_AUTH_SIMPLE) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_args_md5_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) (message-digest|null) " "(message-digest-key|) <1-255> md5 KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_ALL VLINK_HELPSTR_AUTH_MD5) ALIAS (ospf_area_vlink, ospf_area_vlink_authtype_md5_cmd, "area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(message-digest-key|) <1-255> md5 KEY", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE VLINK_HELPSTR_AUTH_MD5) ALIAS (no_ospf_area_vlink, no_ospf_area_vlink_authtype_md5_cmd, "no area (A.B.C.D|<0-4294967295>) virtual-link A.B.C.D " "(authentication|) " "(message-digest-key|)", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_AUTHTYPE_SIMPLE VLINK_HELPSTR_AUTH_MD5) DEFUN (ospf_area_shortcut, ospf_area_shortcut_cmd, "area (A.B.C.D|<0-4294967295>) shortcut (default|enable|disable)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure the area's shortcutting mode\n" "Set default shortcutting behavior\n" "Enable shortcutting through the area\n" "Disable shortcutting through the area\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int mode; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); if (strncmp (argv[1], "de", 2) == 0) mode = OSPF_SHORTCUT_DEFAULT; else if (strncmp (argv[1], "di", 2) == 0) mode = OSPF_SHORTCUT_DISABLE; else if (strncmp (argv[1], "e", 1) == 0) mode = OSPF_SHORTCUT_ENABLE; else return CMD_WARNING; ospf_area_shortcut_set (ospf, area, mode); if (ospf->abr_type != OSPF_ABR_SHORTCUT) vty_out (vty, "Shortcut area setting will take effect " "only when the router is configured as Shortcut ABR%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (no_ospf_area_shortcut, no_ospf_area_shortcut_cmd, "no area (A.B.C.D|<0-4294967295>) shortcut (enable|disable)", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Deconfigure the area's shortcutting mode\n" "Deconfigure enabled shortcutting through the area\n" "Deconfigure disabled shortcutting through the area\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("shortcut", area_id, format, argv[0]); area = ospf_area_lookup_by_area_id (ospf, area_id); if (!area) return CMD_SUCCESS; ospf_area_shortcut_unset (ospf, area); return CMD_SUCCESS; } DEFUN (ospf_area_stub, ospf_area_stub_cmd, "area (A.B.C.D|<0-4294967295>) stub", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int ret, format; VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); ret = ospf_area_stub_set (ospf, area_id); if (ret == 0) { vty_out (vty, "First deconfigure all virtual link through this area%s", VTY_NEWLINE); return CMD_WARNING; } ospf_area_no_summary_unset (ospf, area_id); return CMD_SUCCESS; } DEFUN (ospf_area_stub_no_summary, ospf_area_stub_no_summary_cmd, "area (A.B.C.D|<0-4294967295>) stub no-summary", "OSPF stub parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n" "Do not inject inter-area routes into stub\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int ret, format; VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); ret = ospf_area_stub_set (ospf, area_id); if (ret == 0) { vty_out (vty, "%% Area cannot be stub as it contains a virtual link%s", VTY_NEWLINE); return CMD_WARNING; } ospf_area_no_summary_set (ospf, area_id); return CMD_SUCCESS; } DEFUN (no_ospf_area_stub, no_ospf_area_stub_cmd, "no area (A.B.C.D|<0-4294967295>) stub", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); ospf_area_stub_unset (ospf, area_id); ospf_area_no_summary_unset (ospf, area_id); return CMD_SUCCESS; } DEFUN (no_ospf_area_stub_no_summary, no_ospf_area_stub_no_summary_cmd, "no area (A.B.C.D|<0-4294967295>) stub no-summary", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as stub\n" "Do not inject inter-area routes into area\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("stub", area_id, format, argv[0]); ospf_area_no_summary_unset (ospf, area_id); return CMD_SUCCESS; } static int ospf_area_nssa_cmd_handler (struct vty *vty, int argc, const char *argv[], int nosum) { struct ospf *ospf = vty->index; struct in_addr area_id; int ret, format; VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); ret = ospf_area_nssa_set (ospf, area_id); if (ret == 0) { vty_out (vty, "%% Area cannot be nssa as it contains a virtual link%s", VTY_NEWLINE); return CMD_WARNING; } if (argc > 1) { if (strncmp (argv[1], "translate-c", 11) == 0) ospf_area_nssa_translator_role_set (ospf, area_id, OSPF_NSSA_ROLE_CANDIDATE); else if (strncmp (argv[1], "translate-n", 11) == 0) ospf_area_nssa_translator_role_set (ospf, area_id, OSPF_NSSA_ROLE_NEVER); else if (strncmp (argv[1], "translate-a", 11) == 0) ospf_area_nssa_translator_role_set (ospf, area_id, OSPF_NSSA_ROLE_ALWAYS); } else { ospf_area_nssa_translator_role_set (ospf, area_id, OSPF_NSSA_ROLE_CANDIDATE); } if (nosum) ospf_area_no_summary_set (ospf, area_id); else ospf_area_no_summary_unset (ospf, area_id); ospf_schedule_abr_task (ospf); return CMD_SUCCESS; } DEFUN (ospf_area_nssa_translate_no_summary, ospf_area_nssa_translate_no_summary_cmd, "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always) no-summary", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Configure NSSA-ABR for translate election (default)\n" "Configure NSSA-ABR to never translate\n" "Configure NSSA-ABR to always translate\n" "Do not inject inter-area routes into nssa\n") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 1); } DEFUN (ospf_area_nssa_translate, ospf_area_nssa_translate_cmd, "area (A.B.C.D|<0-4294967295>) nssa (translate-candidate|translate-never|translate-always)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Configure NSSA-ABR for translate election (default)\n" "Configure NSSA-ABR to never translate\n" "Configure NSSA-ABR to always translate\n") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 0); } DEFUN (ospf_area_nssa, ospf_area_nssa_cmd, "area (A.B.C.D|<0-4294967295>) nssa", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 0); } DEFUN (ospf_area_nssa_no_summary, ospf_area_nssa_no_summary_cmd, "area (A.B.C.D|<0-4294967295>) nssa no-summary", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Do not inject inter-area routes into nssa\n") { return ospf_area_nssa_cmd_handler (vty, argc, argv, 1); } DEFUN (no_ospf_area_nssa, no_ospf_area_nssa_cmd, "no area (A.B.C.D|<0-4294967295>) nssa", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); ospf_area_nssa_unset (ospf, area_id); ospf_area_no_summary_unset (ospf, area_id); ospf_schedule_abr_task (ospf); return CMD_SUCCESS; } DEFUN (no_ospf_area_nssa_no_summary, no_ospf_area_nssa_no_summary_cmd, "no area (A.B.C.D|<0-4294967295>) nssa no-summary", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Configure OSPF area as nssa\n" "Do not inject inter-area routes into nssa\n") { struct ospf *ospf = vty->index; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID_NO_BB ("NSSA", area_id, format, argv[0]); ospf_area_no_summary_unset (ospf, area_id); return CMD_SUCCESS; } DEFUN (ospf_area_default_cost, ospf_area_default_cost_cmd, "area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; u_int32_t cost; int format; struct prefix_ipv4 p; VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); VTY_GET_INTEGER_RANGE ("stub default cost", cost, argv[1], 0, 16777215); area = ospf_area_get (ospf, area_id, format); if (area->external_routing == OSPF_AREA_DEFAULT) { vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); return CMD_WARNING; } area->default_cost = cost; p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); return CMD_SUCCESS; } DEFUN (no_ospf_area_default_cost, no_ospf_area_default_cost_cmd, "no area (A.B.C.D|<0-4294967295>) default-cost <0-16777215>", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the summary-default cost of a NSSA or stub area\n" "Stub's advertised default summary cost\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; struct prefix_ipv4 p; VTY_GET_OSPF_AREA_ID_NO_BB ("default-cost", area_id, format, argv[0]); VTY_CHECK_INTEGER_RANGE ("stub default cost", argv[1], 0, OSPF_LS_INFINITY); area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return CMD_SUCCESS; if (area->external_routing == OSPF_AREA_DEFAULT) { vty_out (vty, "The area is neither stub, nor NSSA%s", VTY_NEWLINE); return CMD_WARNING; } area->default_cost = 1; p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); ospf_area_check_free (ospf, area_id); return CMD_SUCCESS; } DEFUN (ospf_area_export_list, ospf_area_export_list_cmd, "area (A.B.C.D|<0-4294967295>) export-list NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the filter for networks announced to other areas\n" "Name of the access-list\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); ospf_area_export_list_set (ospf, area, argv[1]); return CMD_SUCCESS; } DEFUN (no_ospf_area_export_list, no_ospf_area_export_list_cmd, "no area (A.B.C.D|<0-4294967295>) export-list NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return CMD_SUCCESS; ospf_area_export_list_unset (ospf, area); return CMD_SUCCESS; } DEFUN (ospf_area_import_list, ospf_area_import_list_cmd, "area (A.B.C.D|<0-4294967295>) import-list NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Set the filter for networks from other areas announced to the specified one\n" "Name of the access-list\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); ospf_area_import_list_set (ospf, area, argv[1]); return CMD_SUCCESS; } DEFUN (no_ospf_area_import_list, no_ospf_area_import_list_cmd, "no area (A.B.C.D|<0-4294967295>) import-list NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Unset the filter for networks announced to other areas\n" "Name of the access-list\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return CMD_SUCCESS; ospf_area_import_list_unset (ospf, area); return CMD_SUCCESS; } DEFUN (ospf_area_filter_list, ospf_area_filter_list_cmd, "area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Filter networks between OSPF areas\n" "Filter prefixes between OSPF areas\n" "Name of an IP prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; struct prefix_list *plist; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); plist = prefix_list_lookup (AFI_IP, argv[1]); if (strncmp (argv[2], "in", 2) == 0) { PREFIX_LIST_IN (area) = plist; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); PREFIX_NAME_IN (area) = strdup (argv[1]); ospf_schedule_abr_task (ospf); } else { PREFIX_LIST_OUT (area) = plist; if (PREFIX_NAME_OUT (area)) free (PREFIX_NAME_OUT (area)); PREFIX_NAME_OUT (area) = strdup (argv[1]); ospf_schedule_abr_task (ospf); } return CMD_SUCCESS; } DEFUN (no_ospf_area_filter_list, no_ospf_area_filter_list_cmd, "no area (A.B.C.D|<0-4294967295>) filter-list prefix WORD (in|out)", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Filter networks between OSPF areas\n" "Filter prefixes between OSPF areas\n" "Name of an IP prefix-list\n" "Filter networks sent to this area\n" "Filter networks sent from this area\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); if ((area = ospf_area_lookup_by_area_id (ospf, area_id)) == NULL) return CMD_SUCCESS; if (strncmp (argv[2], "in", 2) == 0) { if (PREFIX_NAME_IN (area)) if (strcmp (PREFIX_NAME_IN (area), argv[1]) != 0) return CMD_SUCCESS; PREFIX_LIST_IN (area) = NULL; if (PREFIX_NAME_IN (area)) free (PREFIX_NAME_IN (area)); PREFIX_NAME_IN (area) = NULL; ospf_schedule_abr_task (ospf); } else { if (PREFIX_NAME_OUT (area)) if (strcmp (PREFIX_NAME_OUT (area), argv[1]) != 0) return CMD_SUCCESS; PREFIX_LIST_OUT (area) = NULL; if (PREFIX_NAME_OUT (area)) free (PREFIX_NAME_OUT (area)); PREFIX_NAME_OUT (area) = NULL; ospf_schedule_abr_task (ospf); } return CMD_SUCCESS; } DEFUN (ospf_area_authentication_message_digest, ospf_area_authentication_message_digest_cmd, "area (A.B.C.D|<0-4294967295>) authentication message-digest", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n" "Use message-digest authentication\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); area->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; return CMD_SUCCESS; } DEFUN (ospf_area_authentication, ospf_area_authentication_cmd, "area (A.B.C.D|<0-4294967295>) authentication", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_get (ospf, area_id, format); area->auth_type = OSPF_AUTH_SIMPLE; return CMD_SUCCESS; } DEFUN (no_ospf_area_authentication, no_ospf_area_authentication_cmd, "no area (A.B.C.D|<0-4294967295>) authentication", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" "Enable authentication\n") { struct ospf *ospf = vty->index; struct ospf_area *area; struct in_addr area_id; int format; VTY_GET_OSPF_AREA_ID (area_id, format, argv[0]); area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return CMD_SUCCESS; area->auth_type = OSPF_AUTH_NULL; ospf_area_check_free (ospf, area_id); return CMD_SUCCESS; } DEFUN (ospf_abr_type, ospf_abr_type_cmd, "ospf abr-type (cisco|ibm|shortcut|standard)", "OSPF specific commands\n" "Set OSPF ABR type\n" "Alternative ABR, cisco implementation\n" "Alternative ABR, IBM implementation\n" "Shortcut ABR\n" "Standard behavior (RFC2328)\n") { struct ospf *ospf = vty->index; u_char abr_type = OSPF_ABR_UNKNOWN; if (strncmp (argv[0], "c", 1) == 0) abr_type = OSPF_ABR_CISCO; else if (strncmp (argv[0], "i", 1) == 0) abr_type = OSPF_ABR_IBM; else if (strncmp (argv[0], "sh", 2) == 0) abr_type = OSPF_ABR_SHORTCUT; else if (strncmp (argv[0], "st", 2) == 0) abr_type = OSPF_ABR_STAND; else return CMD_WARNING; /* If ABR type value is changed, schedule ABR task. */ if (ospf->abr_type != abr_type) { ospf->abr_type = abr_type; ospf_schedule_abr_task (ospf); } return CMD_SUCCESS; } DEFUN (no_ospf_abr_type, no_ospf_abr_type_cmd, "no ospf abr-type (cisco|ibm|shortcut|standard)", NO_STR "OSPF specific commands\n" "Set OSPF ABR type\n" "Alternative ABR, cisco implementation\n" "Alternative ABR, IBM implementation\n" "Shortcut ABR\n") { struct ospf *ospf = vty->index; u_char abr_type = OSPF_ABR_UNKNOWN; if (strncmp (argv[0], "c", 1) == 0) abr_type = OSPF_ABR_CISCO; else if (strncmp (argv[0], "i", 1) == 0) abr_type = OSPF_ABR_IBM; else if (strncmp (argv[0], "sh", 2) == 0) abr_type = OSPF_ABR_SHORTCUT; else if (strncmp (argv[0], "st", 2) == 0) abr_type = OSPF_ABR_STAND; else return CMD_WARNING; /* If ABR type value is changed, schedule ABR task. */ if (ospf->abr_type == abr_type) { ospf->abr_type = OSPF_ABR_DEFAULT; ospf_schedule_abr_task (ospf); } return CMD_SUCCESS; } DEFUN (ospf_log_adjacency_changes, ospf_log_adjacency_changes_cmd, "log-adjacency-changes", "Log changes in adjacency state\n") { struct ospf *ospf = vty->index; SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (ospf_log_adjacency_changes_detail, ospf_log_adjacency_changes_detail_cmd, "log-adjacency-changes detail", "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf *ospf = vty->index; SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (no_ospf_log_adjacency_changes, no_ospf_log_adjacency_changes_cmd, "no log-adjacency-changes", NO_STR "Log changes in adjacency state\n") { struct ospf *ospf = vty->index; UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); return CMD_SUCCESS; } DEFUN (no_ospf_log_adjacency_changes_detail, no_ospf_log_adjacency_changes_detail_cmd, "no log-adjacency-changes detail", NO_STR "Log changes in adjacency state\n" "Log all state changes\n") { struct ospf *ospf = vty->index; UNSET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL); return CMD_SUCCESS; } DEFUN (ospf_compatible_rfc1583, ospf_compatible_rfc1583_cmd, "compatible rfc1583", "OSPF compatibility list\n" "compatible with RFC 1583\n") { struct ospf *ospf = vty->index; if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { SET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } return CMD_SUCCESS; } DEFUN (no_ospf_compatible_rfc1583, no_ospf_compatible_rfc1583_cmd, "no compatible rfc1583", NO_STR "OSPF compatibility list\n" "compatible with RFC 1583\n") { struct ospf *ospf = vty->index; if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { UNSET_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE); ospf_spf_calculate_schedule (ospf, SPF_FLAG_CONFIG_CHANGE); } return CMD_SUCCESS; } ALIAS (ospf_compatible_rfc1583, ospf_rfc1583_flag_cmd, "ospf rfc1583compatibility", "OSPF specific commands\n" "Enable the RFC1583Compatibility flag\n") ALIAS (no_ospf_compatible_rfc1583, no_ospf_rfc1583_flag_cmd, "no ospf rfc1583compatibility", NO_STR "OSPF specific commands\n" "Disable the RFC1583Compatibility flag\n") static int ospf_timers_spf_set (struct vty *vty, unsigned int delay, unsigned int hold, unsigned int max) { struct ospf *ospf = vty->index; ospf->spf_delay = delay; ospf->spf_holdtime = hold; ospf->spf_max_holdtime = max; return CMD_SUCCESS; } DEFUN (ospf_timers_throttle_spf, ospf_timers_throttle_spf_cmd, "timers throttle spf <0-600000> <0-600000> <0-600000>", "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n" "Delay (msec) from first change received till SPF calculation\n" "Initial hold time (msec) between consecutive SPF calculations\n" "Maximum hold time (msec)\n") { unsigned int delay, hold, max; if (argc != 3) { vty_out (vty, "Insufficient arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER_RANGE ("SPF delay timer", delay, argv[0], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF hold timer", hold, argv[1], 0, 600000); VTY_GET_INTEGER_RANGE ("SPF max-hold timer", max, argv[2], 0, 600000); return ospf_timers_spf_set (vty, delay, hold, max); } DEFUN_DEPRECATED (ospf_timers_spf, ospf_timers_spf_cmd, "timers spf <0-4294967295> <0-4294967295>", "Adjust routing timers\n" "OSPF SPF timers\n" "Delay (s) between receiving a change to SPF calculation\n" "Hold time (s) between consecutive SPF calculations\n") { unsigned int delay, hold; if (argc != 2) { vty_out (vty, "Insufficient number of arguments%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("SPF delay timer", delay, argv[0]); VTY_GET_INTEGER ("SPF hold timer", hold, argv[1]); /* truncate down the second values if they're greater than 600000ms */ if (delay > (600000 / 1000)) delay = 600000; else if (delay == 0) /* 0s delay was probably specified because of lack of ms resolution */ delay = OSPF_SPF_DELAY_DEFAULT; if (hold > (600000 / 1000)) hold = 600000; return ospf_timers_spf_set (vty, delay * 1000, hold * 1000, hold * 1000); } DEFUN (no_ospf_timers_throttle_spf, no_ospf_timers_throttle_spf_cmd, "no timers throttle spf", NO_STR "Adjust routing timers\n" "Throttling adaptive timer\n" "OSPF SPF timers\n") { return ospf_timers_spf_set (vty, OSPF_SPF_DELAY_DEFAULT, OSPF_SPF_HOLDTIME_DEFAULT, OSPF_SPF_MAX_HOLDTIME_DEFAULT); } ALIAS_DEPRECATED (no_ospf_timers_throttle_spf, no_ospf_timers_spf_cmd, "no timers spf", NO_STR "Adjust routing timers\n" "OSPF SPF timers\n") DEFUN (ospf_neighbor, ospf_neighbor_cmd, "neighbor A.B.C.D", NEIGHBOR_STR "Neighbor IP address\n") { struct ospf *ospf = vty->index; struct in_addr nbr_addr; unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); if (argc > 1) VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[1], 0, 255); if (argc > 2) VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[2], 1, 65535); ospf_nbr_nbma_set (ospf, nbr_addr); if (argc > 1) ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); if (argc > 2) ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval); return CMD_SUCCESS; } ALIAS (ospf_neighbor, ospf_neighbor_priority_poll_interval_cmd, "neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", NEIGHBOR_STR "Neighbor IP address\n" "Neighbor Priority\n" "Priority\n" "Dead Neighbor Polling interval\n" "Seconds\n") ALIAS (ospf_neighbor, ospf_neighbor_priority_cmd, "neighbor A.B.C.D priority <0-255>", NEIGHBOR_STR "Neighbor IP address\n" "Neighbor Priority\n" "Seconds\n") DEFUN (ospf_neighbor_poll_interval, ospf_neighbor_poll_interval_cmd, "neighbor A.B.C.D poll-interval <1-65535>", NEIGHBOR_STR "Neighbor IP address\n" "Dead Neighbor Polling interval\n" "Seconds\n") { struct ospf *ospf = vty->index; struct in_addr nbr_addr; unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); if (argc > 1) VTY_GET_INTEGER_RANGE ("poll interval", interval, argv[1], 1, 65535); if (argc > 2) VTY_GET_INTEGER_RANGE ("neighbor priority", priority, argv[2], 0, 255); ospf_nbr_nbma_set (ospf, nbr_addr); if (argc > 1) ospf_nbr_nbma_poll_interval_set (ospf, nbr_addr, interval); if (argc > 2) ospf_nbr_nbma_priority_set (ospf, nbr_addr, priority); return CMD_SUCCESS; } ALIAS (ospf_neighbor_poll_interval, ospf_neighbor_poll_interval_priority_cmd, "neighbor A.B.C.D poll-interval <1-65535> priority <0-255>", NEIGHBOR_STR "Neighbor address\n" "OSPF dead-router polling interval\n" "Seconds\n" "OSPF priority of non-broadcast neighbor\n" "Priority\n") DEFUN (no_ospf_neighbor, no_ospf_neighbor_cmd, "no neighbor A.B.C.D", NO_STR NEIGHBOR_STR "Neighbor IP address\n") { struct ospf *ospf = vty->index; struct in_addr nbr_addr; VTY_GET_IPV4_ADDRESS ("neighbor address", nbr_addr, argv[0]); (void)ospf_nbr_nbma_unset (ospf, nbr_addr); return CMD_SUCCESS; } ALIAS (no_ospf_neighbor, no_ospf_neighbor_priority_cmd, "no neighbor A.B.C.D priority <0-255>", NO_STR NEIGHBOR_STR "Neighbor IP address\n" "Neighbor Priority\n" "Priority\n") ALIAS (no_ospf_neighbor, no_ospf_neighbor_poll_interval_cmd, "no neighbor A.B.C.D poll-interval <1-65535>", NO_STR NEIGHBOR_STR "Neighbor IP address\n" "Dead Neighbor Polling interval\n" "Seconds\n") ALIAS (no_ospf_neighbor, no_ospf_neighbor_priority_pollinterval_cmd, "no neighbor A.B.C.D priority <0-255> poll-interval <1-65535>", NO_STR NEIGHBOR_STR "Neighbor IP address\n" "Neighbor Priority\n" "Priority\n" "Dead Neighbor Polling interval\n" "Seconds\n") DEFUN (ospf_refresh_timer, ospf_refresh_timer_cmd, "refresh timer <10-1800>", "Adjust refresh parameters\n" "Set refresh timer\n" "Timer value in seconds\n") { struct ospf *ospf = vty->index; unsigned int interval; VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); interval = (interval / 10) * 10; ospf_timers_refresh_set (ospf, interval); return CMD_SUCCESS; } DEFUN (no_ospf_refresh_timer, no_ospf_refresh_timer_val_cmd, "no refresh timer <10-1800>", "Adjust refresh parameters\n" "Unset refresh timer\n" "Timer value in seconds\n") { struct ospf *ospf = vty->index; unsigned int interval; if (argc == 1) { VTY_GET_INTEGER_RANGE ("refresh timer", interval, argv[0], 10, 1800); if (ospf->lsa_refresh_interval != interval || interval == OSPF_LSA_REFRESH_INTERVAL_DEFAULT) return CMD_SUCCESS; } ospf_timers_refresh_unset (ospf); return CMD_SUCCESS; } ALIAS (no_ospf_refresh_timer, no_ospf_refresh_timer_cmd, "no refresh timer", "Adjust refresh parameters\n" "Unset refresh timer\n") DEFUN (ospf_auto_cost_reference_bandwidth, ospf_auto_cost_reference_bandwidth_cmd, "auto-cost reference-bandwidth <1-4294967>", "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n" "The reference bandwidth in terms of Mbits per second\n") { struct ospf *ospf = vty->index; u_int32_t refbw; struct listnode *node; struct interface *ifp; refbw = strtol (argv[0], NULL, 10); if (refbw < 1 || refbw > 4294967) { vty_out (vty, "reference-bandwidth value is invalid%s", VTY_NEWLINE); return CMD_WARNING; } /* If reference bandwidth is changed. */ if ((refbw * 1000) == ospf->ref_bandwidth) return CMD_SUCCESS; ospf->ref_bandwidth = refbw * 1000; for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } DEFUN (no_ospf_auto_cost_reference_bandwidth, no_ospf_auto_cost_reference_bandwidth_cmd, "no auto-cost reference-bandwidth", NO_STR "Calculate OSPF interface cost according to bandwidth\n" "Use reference bandwidth method to assign OSPF cost\n") { struct ospf *ospf = vty->index; struct listnode *node, *nnode; struct interface *ifp; if (ospf->ref_bandwidth == OSPF_DEFAULT_REF_BANDWIDTH) return CMD_SUCCESS; ospf->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; vty_out (vty, "%% OSPF: Reference bandwidth is changed.%s", VTY_NEWLINE); vty_out (vty, " Please ensure reference bandwidth is consistent across all routers%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS (om->iflist, node, nnode, ifp)) ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } const char *ospf_abr_type_descr_str[] = { "Unknown", "Standard (RFC2328)", "Alternative IBM", "Alternative Cisco", "Alternative Shortcut" }; const char *ospf_shortcut_mode_descr_str[] = { "Default", "Enabled", "Disabled" }; static void show_ip_ospf_area (struct vty *vty, struct ospf_area *area) { /* Show Area ID. */ vty_out (vty, " Area ID: %s", inet_ntoa (area->area_id)); /* Show Area type/mode. */ if (OSPF_IS_AREA_BACKBONE (area)) vty_out (vty, " (Backbone)%s", VTY_NEWLINE); else { if (area->external_routing == OSPF_AREA_STUB) vty_out (vty, " (Stub%s%s)", area->no_summary ? ", no summary" : "", area->shortcut_configured ? "; " : ""); else if (area->external_routing == OSPF_AREA_NSSA) vty_out (vty, " (NSSA%s%s)", area->no_summary ? ", no summary" : "", area->shortcut_configured ? "; " : ""); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Shortcutting mode: %s", ospf_shortcut_mode_descr_str[area->shortcut_configured]); vty_out (vty, ", S-bit consensus: %s%s", area->shortcut_capability ? "ok" : "no", VTY_NEWLINE); } /* Show number of interfaces. */ vty_out (vty, " Number of interfaces in this area: Total: %d, " "Active: %d%s", listcount (area->oiflist), area->act_ints, VTY_NEWLINE); if (area->external_routing == OSPF_AREA_NSSA) { vty_out (vty, " It is an NSSA configuration. %s Elected NSSA/ABR performs type-7/type-5 LSA translation. %s", VTY_NEWLINE, VTY_NEWLINE); if (! IS_OSPF_ABR (area->ospf)) vty_out (vty, " It is not ABR, therefore not Translator. %s", VTY_NEWLINE); else if (area->NSSATranslatorState) { vty_out (vty, " We are an ABR and "); if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_CANDIDATE) vty_out (vty, "the NSSA Elected Translator. %s", VTY_NEWLINE); else if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS) vty_out (vty, "always an NSSA Translator. %s", VTY_NEWLINE); } else { vty_out (vty, " We are an ABR, but "); if (area->NSSATranslatorRole == OSPF_NSSA_ROLE_CANDIDATE) vty_out (vty, "not the NSSA Elected Translator. %s", VTY_NEWLINE); else vty_out (vty, "never an NSSA Translator. %s", VTY_NEWLINE); } } /* Stub-router state for this area */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) { char timebuf[OSPF_TIME_DUMP_SIZE]; vty_out (vty, " Originating stub / maximum-distance Router-LSA%s", VTY_NEWLINE); if (CHECK_FLAG(area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) vty_out (vty, " Administratively activated (indefinitely)%s", VTY_NEWLINE); if (area->t_stub_router) vty_out (vty, " Active from startup, %s remaining%s", ospf_timer_dump (area->t_stub_router, timebuf, sizeof(timebuf)), VTY_NEWLINE); } /* Show number of fully adjacent neighbors. */ vty_out (vty, " Number of fully adjacent neighbors in this area:" " %d%s", area->full_nbrs, VTY_NEWLINE); /* Show authentication type. */ vty_out (vty, " Area has "); if (area->auth_type == OSPF_AUTH_NULL) vty_out (vty, "no authentication%s", VTY_NEWLINE); else if (area->auth_type == OSPF_AUTH_SIMPLE) vty_out (vty, "simple password authentication%s", VTY_NEWLINE); else if (area->auth_type == OSPF_AUTH_CRYPTOGRAPHIC) vty_out (vty, "message digest authentication%s", VTY_NEWLINE); if (!OSPF_IS_AREA_BACKBONE (area)) vty_out (vty, " Number of full virtual adjacencies going through" " this area: %d%s", area->full_vls, VTY_NEWLINE); /* Show SPF calculation times. */ vty_out (vty, " SPF algorithm executed %d times%s", area->spf_calculation, VTY_NEWLINE); /* Show number of LSA. */ vty_out (vty, " Number of LSA %ld%s", area->lsdb->total, VTY_NEWLINE); vty_out (vty, " Number of router LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_ROUTER_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_ROUTER_LSA), VTY_NEWLINE); vty_out (vty, " Number of network LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_NETWORK_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_NETWORK_LSA), VTY_NEWLINE); vty_out (vty, " Number of summary LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_SUMMARY_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_SUMMARY_LSA), VTY_NEWLINE); vty_out (vty, " Number of ASBR summary LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_ASBR_SUMMARY_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_ASBR_SUMMARY_LSA), VTY_NEWLINE); vty_out (vty, " Number of NSSA LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_AS_NSSA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_AS_NSSA_LSA), VTY_NEWLINE); #ifdef HAVE_OPAQUE_LSA vty_out (vty, " Number of opaque link LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_LINK_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_LINK_LSA), VTY_NEWLINE); vty_out (vty, " Number of opaque area LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (area->lsdb, OSPF_OPAQUE_AREA_LSA), ospf_lsdb_checksum (area->lsdb, OSPF_OPAQUE_AREA_LSA), VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, "%s", VTY_NEWLINE); } DEFUN (show_ip_ospf, show_ip_ospf_cmd, "show ip ospf", SHOW_STR IP_STR "OSPF information\n") { struct listnode *node, *nnode; struct ospf_area * area; struct ospf *ospf; struct timeval result; char timebuf[OSPF_TIME_DUMP_SIZE]; /* Check OSPF is enable. */ ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Show Router ID. */ vty_out (vty, " OSPF Routing Process, Router ID: %s%s", inet_ntoa (ospf->router_id), VTY_NEWLINE); /* Graceful shutdown */ if (ospf->t_deferred_shutdown) vty_out (vty, " Deferred shutdown in progress, %s remaining%s", ospf_timer_dump (ospf->t_deferred_shutdown, timebuf, sizeof (timebuf)), VTY_NEWLINE); /* Show capability. */ vty_out (vty, " Supports only single TOS (TOS0) routes%s", VTY_NEWLINE); vty_out (vty, " This implementation conforms to RFC2328%s", VTY_NEWLINE); vty_out (vty, " RFC1583Compatibility flag is %s%s", CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE) ? "enabled" : "disabled", VTY_NEWLINE); #ifdef HAVE_OPAQUE_LSA vty_out (vty, " OpaqueCapability flag is %s%s%s", CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE) ? "enabled" : "disabled", IS_OPAQUE_LSA_ORIGINATION_BLOCKED (ospf->opaque) ? " (origination blocked)" : "", VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ /* Show stub-router configuration */ if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED || ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) { vty_out (vty, " Stub router advertisement is configured%s", VTY_NEWLINE); if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " Enabled for %us after start-up%s", ospf->stub_router_startup_time, VTY_NEWLINE); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " Enabled for %us prior to full shutdown%s", ospf->stub_router_shutdown_time, VTY_NEWLINE); } /* Show SPF timers. */ vty_out (vty, " Initial SPF scheduling delay %d millisec(s)%s" " Minimum hold time between consecutive SPFs %d millisec(s)%s" " Maximum hold time between consecutive SPFs %d millisec(s)%s" " Hold time multiplier is currently %d%s", ospf->spf_delay, VTY_NEWLINE, ospf->spf_holdtime, VTY_NEWLINE, ospf->spf_max_holdtime, VTY_NEWLINE, ospf->spf_hold_multiplier, VTY_NEWLINE); vty_out (vty, " SPF algorithm "); if (ospf->ts_spf.tv_sec || ospf->ts_spf.tv_usec) { result = tv_sub (recent_relative_time (), ospf->ts_spf); vty_out (vty, "last executed %s ago%s", ospf_timeval_dump (&result, timebuf, sizeof (timebuf)), VTY_NEWLINE); vty_out (vty, " Last SPF duration %s%s", ospf_timeval_dump (&ospf->ts_spf_duration, timebuf, sizeof (timebuf)), VTY_NEWLINE); } else vty_out (vty, "has not been run%s", VTY_NEWLINE); vty_out (vty, " SPF timer %s%s%s", (ospf->t_spf_calc ? "due in " : "is "), ospf_timer_dump (ospf->t_spf_calc, timebuf, sizeof (timebuf)), VTY_NEWLINE); /* Show refresh parameters. */ vty_out (vty, " Refresh timer %d secs%s", ospf->lsa_refresh_interval, VTY_NEWLINE); /* Show ABR/ASBR flags. */ if (CHECK_FLAG (ospf->flags, OSPF_FLAG_ABR)) vty_out (vty, " This router is an ABR, ABR type is: %s%s", ospf_abr_type_descr_str[ospf->abr_type], VTY_NEWLINE); if (CHECK_FLAG (ospf->flags, OSPF_FLAG_ASBR)) vty_out (vty, " This router is an ASBR " "(injecting external routing information)%s", VTY_NEWLINE); /* Show Number of AS-external-LSAs. */ vty_out (vty, " Number of external LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_AS_EXTERNAL_LSA), VTY_NEWLINE); #ifdef HAVE_OPAQUE_LSA vty_out (vty, " Number of opaque AS LSA %ld. Checksum Sum 0x%08x%s", ospf_lsdb_count (ospf->lsdb, OSPF_OPAQUE_AS_LSA), ospf_lsdb_checksum (ospf->lsdb, OSPF_OPAQUE_AS_LSA), VTY_NEWLINE); #endif /* HAVE_OPAQUE_LSA */ /* Show number of areas attached. */ vty_out (vty, " Number of areas attached to this router: %d%s", listcount (ospf->areas), VTY_NEWLINE); if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES)) { if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) vty_out(vty, " All adjacency changes are logged%s",VTY_NEWLINE); else vty_out(vty, " Adjacency changes are logged%s",VTY_NEWLINE); } vty_out (vty, "%s",VTY_NEWLINE); /* Show each area status. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) show_ip_ospf_area (vty, area); return CMD_SUCCESS; } static void show_ip_ospf_interface_sub (struct vty *vty, struct ospf *ospf, struct interface *ifp) { int is_up; struct ospf_neighbor *nbr; struct route_node *rn; /* Is interface up? */ vty_out (vty, "%s is %s%s", ifp->name, ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); vty_out (vty, " ifindex %u, MTU %u bytes, BW %u Kbit %s%s", ifp->ifindex, ifp->mtu, ifp->bandwidth, if_flag_dump(ifp->flags), VTY_NEWLINE); /* Is interface OSPF enabled? */ if (ospf_oi_count(ifp) == 0) { vty_out (vty, " OSPF not enabled on this interface%s", VTY_NEWLINE); return; } else if (!is_up) { vty_out (vty, " OSPF is enabled, but not running on this interface%s", VTY_NEWLINE); return; } for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; /* Show OSPF interface information. */ vty_out (vty, " Internet Address %s/%d,", inet_ntoa (oi->address->u.prefix4), oi->address->prefixlen); if (oi->connected->destination || oi->type == OSPF_IFTYPE_VIRTUALLINK) { struct in_addr *dest; const char *dstr; if (CONNECTED_PEER(oi->connected) || oi->type == OSPF_IFTYPE_VIRTUALLINK) dstr = "Peer"; else dstr = "Broadcast"; /* For Vlinks, showing the peer address is probably more * informative than the local interface that is being used */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) dest = &oi->vl_data->peer_addr; else dest = &oi->connected->destination->u.prefix4; vty_out (vty, " %s %s,", dstr, inet_ntoa (*dest)); } vty_out (vty, " Area %s%s", ospf_area_desc_string (oi->area), VTY_NEWLINE); vty_out (vty, " MTU mismatch detection:%s%s", OSPF_IF_PARAM(oi, mtu_ignore) ? "disabled" : "enabled", VTY_NEWLINE); vty_out (vty, " Router ID %s, Network Type %s, Cost: %d%s", inet_ntoa (ospf->router_id), ospf_network_type_str[oi->type], oi->output_cost, VTY_NEWLINE); vty_out (vty, " Transmit Delay is %d sec, State %s, Priority %d%s", OSPF_IF_PARAM (oi,transmit_delay), LOOKUP (ospf_ism_state_msg, oi->state), PRIORITY (oi), VTY_NEWLINE); /* Show DR information. */ if (DR (oi).s_addr == 0) vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); else { nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); if (nbr == NULL) vty_out (vty, " No designated router on this network%s", VTY_NEWLINE); else { vty_out (vty, " Designated Router (ID) %s,", inet_ntoa (nbr->router_id)); vty_out (vty, " Interface Address %s%s", inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); } } /* Show BDR information. */ if (BDR (oi).s_addr == 0) vty_out (vty, " No backup designated router on this network%s", VTY_NEWLINE); else { nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &BDR (oi)); if (nbr == NULL) vty_out (vty, " No backup designated router on this network%s", VTY_NEWLINE); else { vty_out (vty, " Backup Designated Router (ID) %s,", inet_ntoa (nbr->router_id)); vty_out (vty, " Interface Address %s%s", inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); } } /* Next network-LSA sequence number we'll use, if we're elected DR */ if (oi->params && ntohl (oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) vty_out (vty, " Saved Network-LSA sequence number 0x%x%s", ntohl (oi->params->network_lsa_seqnum), VTY_NEWLINE); vty_out (vty, " Multicast group memberships:"); if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) vty_out (vty, " OSPFAllRouters"); if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) vty_out (vty, " OSPFDesignatedRouters"); } else vty_out (vty, " "); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Timer intervals configured,"); vty_out (vty, " Hello "); if (OSPF_IF_PARAM (oi, fast_hello) == 0) vty_out (vty, "%ds,", OSPF_IF_PARAM (oi, v_hello)); else vty_out (vty, "%dms,", 1000 / OSPF_IF_PARAM (oi, fast_hello)); vty_out (vty, " Dead %ds, Wait %ds, Retransmit %d%s", OSPF_IF_PARAM (oi, v_wait), OSPF_IF_PARAM (oi, v_wait), OSPF_IF_PARAM (oi, retransmit_interval), VTY_NEWLINE); if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_ACTIVE) { char timebuf[OSPF_TIME_DUMP_SIZE]; vty_out (vty, " Hello due in %s%s", ospf_timer_dump (oi->t_hello, timebuf, sizeof(timebuf)), VTY_NEWLINE); } else /* passive-interface is set */ vty_out (vty, " No Hellos (Passive interface)%s", VTY_NEWLINE); vty_out (vty, " Neighbor Count is %d, Adjacent neighbor count is %d%s", ospf_nbr_count (oi, 0), ospf_nbr_count (oi, NSM_Full), VTY_NEWLINE); } } DEFUN (show_ip_ospf_interface, show_ip_ospf_interface_cmd, "show ip ospf interface [INTERFACE]", SHOW_STR IP_STR "OSPF information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct ospf *ospf; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, "OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Show All Interfaces. */ if (argc == 0) for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) show_ip_ospf_interface_sub (vty, ospf, ifp); /* Interface name is specified. */ else { if ((ifp = if_lookup_by_name (argv[0])) == NULL) vty_out (vty, "No such interface name%s", VTY_NEWLINE); else show_ip_ospf_interface_sub (vty, ospf, ifp); } return CMD_SUCCESS; } static void show_ip_ospf_neighbour_header (struct vty *vty) { vty_out (vty, "%s%15s %3s %-15s %9s %-15s %-20s %5s %5s %5s%s", VTY_NEWLINE, "Neighbor ID", "Pri", "State", "Dead Time", "Address", "Interface", "RXmtL", "RqstL", "DBsmL", VTY_NEWLINE); } static void show_ip_ospf_neighbor_sub (struct vty *vty, struct ospf_interface *oi) { struct route_node *rn; struct ospf_neighbor *nbr; char msgbuf[16]; char timebuf[OSPF_TIME_DUMP_SIZE]; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) /* Do not show myself. */ if (nbr != oi->nbr_self) /* Down state is not shown. */ if (nbr->state != NSM_Down) { ospf_nbr_state_message (nbr, msgbuf, 16); if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) vty_out (vty, "%-15s %3d %-15s ", "-", nbr->priority, msgbuf); else vty_out (vty, "%-15s %3d %-15s ", inet_ntoa (nbr->router_id), nbr->priority, msgbuf); vty_out (vty, "%9s ", ospf_timer_dump (nbr->t_inactivity, timebuf, sizeof(timebuf))); vty_out (vty, "%-15s ", inet_ntoa (nbr->src)); vty_out (vty, "%-20s %5ld %5ld %5d%s", IF_NAME (oi), ospf_ls_retransmit_count (nbr), ospf_ls_request_count (nbr), ospf_db_summary_count (nbr), VTY_NEWLINE); } } DEFUN (show_ip_ospf_neighbor, show_ip_ospf_neighbor_cmd, "show ip ospf neighbor", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n") { struct ospf *ospf; struct ospf_interface *oi; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } show_ip_ospf_neighbour_header (vty); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) show_ip_ospf_neighbor_sub (vty, oi); return CMD_SUCCESS; } DEFUN (show_ip_ospf_neighbor_all, show_ip_ospf_neighbor_all_cmd, "show ip ospf neighbor all", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "include down status neighbor\n") { struct ospf *ospf = ospf_lookup (); struct listnode *node; struct ospf_interface *oi; if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } show_ip_ospf_neighbour_header (vty); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { struct listnode *nbr_node; struct ospf_nbr_nbma *nbr_nbma; show_ip_ospf_neighbor_sub (vty, oi); /* print Down neighbor status */ for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, nbr_node, nbr_nbma)) { if (nbr_nbma->nbr == NULL || nbr_nbma->nbr->state == NSM_Down) { vty_out (vty, "%-15s %3d %-15s %9s ", "-", nbr_nbma->priority, "Down", "-"); vty_out (vty, "%-15s %-20s %5d %5d %5d%s", inet_ntoa (nbr_nbma->addr), IF_NAME (oi), 0, 0, 0, VTY_NEWLINE); } } } return CMD_SUCCESS; } DEFUN (show_ip_ospf_neighbor_int, show_ip_ospf_neighbor_int_cmd, "show ip ospf neighbor IFNAME", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "Interface name\n") { struct ospf *ospf; struct interface *ifp; struct route_node *rn; ifp = if_lookup_by_name (argv[0]); if (!ifp) { vty_out (vty, "No such interface.%s", VTY_NEWLINE); return CMD_WARNING; } ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } show_ip_ospf_neighbour_header (vty); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; show_ip_ospf_neighbor_sub (vty, oi); } return CMD_SUCCESS; } static void show_ip_ospf_nbr_nbma_detail_sub (struct vty *vty, struct ospf_interface *oi, struct ospf_nbr_nbma *nbr_nbma) { char timebuf[OSPF_TIME_DUMP_SIZE]; /* Show neighbor ID. */ vty_out (vty, " Neighbor %s,", "-"); /* Show interface address. */ vty_out (vty, " interface address %s%s", inet_ntoa (nbr_nbma->addr), VTY_NEWLINE); /* Show Area ID. */ vty_out (vty, " In the area %s via interface %s%s", ospf_area_desc_string (oi->area), IF_NAME (oi), VTY_NEWLINE); /* Show neighbor priority and state. */ vty_out (vty, " Neighbor priority is %d, State is %s,", nbr_nbma->priority, "Down"); /* Show state changes. */ vty_out (vty, " %d state changes%s", nbr_nbma->state_change, VTY_NEWLINE); /* Show PollInterval */ vty_out (vty, " Poll interval %d%s", nbr_nbma->v_poll, VTY_NEWLINE); /* Show poll-interval timer. */ vty_out (vty, " Poll timer due in %s%s", ospf_timer_dump (nbr_nbma->t_poll, timebuf, sizeof(timebuf)), VTY_NEWLINE); /* Show poll-interval timer thread. */ vty_out (vty, " Thread Poll Timer %s%s", nbr_nbma->t_poll != NULL ? "on" : "off", VTY_NEWLINE); } static void show_ip_ospf_neighbor_detail_sub (struct vty *vty, struct ospf_interface *oi, struct ospf_neighbor *nbr) { char timebuf[OSPF_TIME_DUMP_SIZE]; /* Show neighbor ID. */ if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == 0) vty_out (vty, " Neighbor %s,", "-"); else vty_out (vty, " Neighbor %s,", inet_ntoa (nbr->router_id)); /* Show interface address. */ vty_out (vty, " interface address %s%s", inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE); /* Show Area ID. */ vty_out (vty, " In the area %s via interface %s%s", ospf_area_desc_string (oi->area), oi->ifp->name, VTY_NEWLINE); /* Show neighbor priority and state. */ vty_out (vty, " Neighbor priority is %d, State is %s,", nbr->priority, LOOKUP (ospf_nsm_state_msg, nbr->state)); /* Show state changes. */ vty_out (vty, " %d state changes%s", nbr->state_change, VTY_NEWLINE); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_progress); vty_out (vty, " Most recent state change statistics:%s", VTY_NEWLINE); vty_out (vty, " Progressive change %s ago%s", ospf_timeval_dump (&res, timebuf, sizeof(timebuf)), VTY_NEWLINE); } if (nbr->ts_last_regress.tv_sec || nbr->ts_last_regress.tv_usec) { struct timeval res = tv_sub (recent_relative_time (), nbr->ts_last_regress); vty_out (vty, " Regressive change %s ago, due to %s%s", ospf_timeval_dump (&res, timebuf, sizeof(timebuf)), (nbr->last_regress_str ? nbr->last_regress_str : "??"), VTY_NEWLINE); } /* Show Designated Rotuer ID. */ vty_out (vty, " DR is %s,", inet_ntoa (nbr->d_router)); /* Show Backup Designated Rotuer ID. */ vty_out (vty, " BDR is %s%s", inet_ntoa (nbr->bd_router), VTY_NEWLINE); /* Show options. */ vty_out (vty, " Options %d %s%s", nbr->options, ospf_options_dump (nbr->options), VTY_NEWLINE); /* Show Router Dead interval timer. */ vty_out (vty, " Dead timer due in %s%s", ospf_timer_dump (nbr->t_inactivity, timebuf, sizeof (timebuf)), VTY_NEWLINE); /* Show Database Summary list. */ vty_out (vty, " Database Summary List %d%s", ospf_db_summary_count (nbr), VTY_NEWLINE); /* Show Link State Request list. */ vty_out (vty, " Link State Request List %ld%s", ospf_ls_request_count (nbr), VTY_NEWLINE); /* Show Link State Retransmission list. */ vty_out (vty, " Link State Retransmission List %ld%s", ospf_ls_retransmit_count (nbr), VTY_NEWLINE); /* Show inactivity timer thread. */ vty_out (vty, " Thread Inactivity Timer %s%s", nbr->t_inactivity != NULL ? "on" : "off", VTY_NEWLINE); /* Show Database Description retransmission thread. */ vty_out (vty, " Thread Database Description Retransmision %s%s", nbr->t_db_desc != NULL ? "on" : "off", VTY_NEWLINE); /* Show Link State Request Retransmission thread. */ vty_out (vty, " Thread Link State Request Retransmission %s%s", nbr->t_ls_req != NULL ? "on" : "off", VTY_NEWLINE); /* Show Link State Update Retransmission thread. */ vty_out (vty, " Thread Link State Update Retransmission %s%s%s", nbr->t_ls_upd != NULL ? "on" : "off", VTY_NEWLINE, VTY_NEWLINE); } DEFUN (show_ip_ospf_neighbor_id, show_ip_ospf_neighbor_id_cmd, "show ip ospf neighbor A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "Neighbor ID\n") { struct ospf *ospf; struct listnode *node; struct ospf_neighbor *nbr; struct ospf_interface *oi; struct in_addr router_id; int ret; ret = inet_aton (argv[0], &router_id); if (!ret) { vty_out (vty, "Please specify Neighbor ID by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if ((nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &router_id))) show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); return CMD_SUCCESS; } DEFUN (show_ip_ospf_neighbor_detail, show_ip_ospf_neighbor_detail_cmd, "show ip ospf neighbor detail", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "detail of all neighbors\n") { struct ospf *ospf; struct ospf_interface *oi; struct listnode *node; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (nbr != oi->nbr_self) if (nbr->state != NSM_Down) show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); } return CMD_SUCCESS; } DEFUN (show_ip_ospf_neighbor_detail_all, show_ip_ospf_neighbor_detail_all_cmd, "show ip ospf neighbor detail all", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "detail of all neighbors\n" "include down status neighbor\n") { struct ospf *ospf; struct listnode *node; struct ospf_interface *oi; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (nbr != oi->nbr_self) if (oi->type == OSPF_IFTYPE_NBMA && nbr->state != NSM_Down) show_ip_ospf_neighbor_detail_sub (vty, oi, rn->info); if (oi->type == OSPF_IFTYPE_NBMA) { struct listnode *nd; for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, nd, nbr_nbma)) if (nbr_nbma->nbr == NULL || nbr_nbma->nbr->state == NSM_Down) show_ip_ospf_nbr_nbma_detail_sub (vty, oi, nbr_nbma); } } return CMD_SUCCESS; } DEFUN (show_ip_ospf_neighbor_int_detail, show_ip_ospf_neighbor_int_detail_cmd, "show ip ospf neighbor IFNAME detail", SHOW_STR IP_STR "OSPF information\n" "Neighbor list\n" "Interface name\n" "detail of all neighbors") { struct ospf *ospf; struct ospf_interface *oi; struct interface *ifp; struct route_node *rn, *nrn; struct ospf_neighbor *nbr; ifp = if_lookup_by_name (argv[0]); if (!ifp) { vty_out (vty, "No such interface.%s", VTY_NEWLINE); return CMD_WARNING; } ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if ((oi = rn->info)) for (nrn = route_top (oi->nbrs); nrn; nrn = route_next (nrn)) if ((nbr = nrn->info)) if (nbr != oi->nbr_self) if (nbr->state != NSM_Down) show_ip_ospf_neighbor_detail_sub (vty, oi, nbr); return CMD_SUCCESS; } /* Show functions */ static int show_lsa_summary (struct vty *vty, struct ospf_lsa *lsa, int self) { struct router_lsa *rl; struct summary_lsa *sl; struct as_external_lsa *asel; struct prefix_ipv4 p; if (lsa != NULL) /* If self option is set, check LSA self flag. */ if (self == 0 || IS_LSA_SELF (lsa)) { /* LSA common part show. */ vty_out (vty, "%-15s ", inet_ntoa (lsa->data->id)); vty_out (vty, "%-15s %4d 0x%08lx 0x%04x", inet_ntoa (lsa->data->adv_router), LS_AGE (lsa), (u_long)ntohl (lsa->data->ls_seqnum), ntohs (lsa->data->checksum)); /* LSA specific part show. */ switch (lsa->data->type) { case OSPF_ROUTER_LSA: rl = (struct router_lsa *) lsa->data; vty_out (vty, " %-d", ntohs (rl->links)); break; case OSPF_SUMMARY_LSA: sl = (struct summary_lsa *) lsa->data; p.family = AF_INET; p.prefix = sl->header.id; p.prefixlen = ip_masklen (sl->mask); apply_mask_ipv4 (&p); vty_out (vty, " %s/%d", inet_ntoa (p.prefix), p.prefixlen); break; case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: asel = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = asel->header.id; p.prefixlen = ip_masklen (asel->mask); apply_mask_ipv4 (&p); vty_out (vty, " %s %s/%d [0x%lx]", IS_EXTERNAL_METRIC (asel->e[0].tos) ? "E2" : "E1", inet_ntoa (p.prefix), p.prefixlen, (u_long)ntohl (asel->e[0].route_tag)); break; case OSPF_NETWORK_LSA: case OSPF_ASBR_SUMMARY_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ default: break; } vty_out (vty, VTY_NEWLINE); } return 0; } static const char *show_database_desc[] = { "unknown", "Router Link States", "Net Link States", "Summary Link States", "ASBR-Summary Link States", "AS External Link States", "Group Membership LSA", "NSSA-external Link States", #ifdef HAVE_OPAQUE_LSA "Type-8 LSA", "Link-Local Opaque-LSA", "Area-Local Opaque-LSA", "AS-external Opaque-LSA", #endif /* HAVE_OPAQUE_LSA */ }; static const char *show_database_header[] = { "", "Link ID ADV Router Age Seq# CkSum Link count", "Link ID ADV Router Age Seq# CkSum", "Link ID ADV Router Age Seq# CkSum Route", "Link ID ADV Router Age Seq# CkSum", "Link ID ADV Router Age Seq# CkSum Route", " --- header for Group Member ----", "Link ID ADV Router Age Seq# CkSum Route", #ifdef HAVE_OPAQUE_LSA " --- type-8 ---", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", "Opaque-Type/Id ADV Router Age Seq# CkSum", #endif /* HAVE_OPAQUE_LSA */ }; static void show_ip_ospf_database_header (struct vty *vty, struct ospf_lsa *lsa) { struct router_lsa *rlsa = (struct router_lsa*) lsa->data; vty_out (vty, " LS age: %d%s", LS_AGE (lsa), VTY_NEWLINE); vty_out (vty, " Options: 0x%-2x : %s%s", lsa->data->options, ospf_options_dump(lsa->data->options), VTY_NEWLINE); vty_out (vty, " LS Flags: 0x%-2x %s%s", lsa->flags, ((lsa->flags & OSPF_LSA_LOCAL_XLT) ? "(Translated from Type-7)" : ""), VTY_NEWLINE); if (lsa->data->type == OSPF_ROUTER_LSA) { vty_out (vty, " Flags: 0x%x" , rlsa->flags); if (rlsa->flags) vty_out (vty, " :%s%s%s%s", IS_ROUTER_LSA_BORDER (rlsa) ? " ABR" : "", IS_ROUTER_LSA_EXTERNAL (rlsa) ? " ASBR" : "", IS_ROUTER_LSA_VIRTUAL (rlsa) ? " VL-endpoint" : "", IS_ROUTER_LSA_SHORTCUT (rlsa) ? " Shortcut" : ""); vty_out (vty, "%s", VTY_NEWLINE); } vty_out (vty, " LS Type: %s%s", LOOKUP (ospf_lsa_type_msg, lsa->data->type), VTY_NEWLINE); vty_out (vty, " Link State ID: %s %s%s", inet_ntoa (lsa->data->id), LOOKUP (ospf_link_state_id_type_msg, lsa->data->type), VTY_NEWLINE); vty_out (vty, " Advertising Router: %s%s", inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); vty_out (vty, " LS Seq Number: %08lx%s", (u_long)ntohl (lsa->data->ls_seqnum), VTY_NEWLINE); vty_out (vty, " Checksum: 0x%04x%s", ntohs (lsa->data->checksum), VTY_NEWLINE); vty_out (vty, " Length: %d%s", ntohs (lsa->data->length), VTY_NEWLINE); } const char *link_type_desc[] = { "(null)", "another Router (point-to-point)", "a Transit Network", "Stub Network", "a Virtual Link", }; const char *link_id_desc[] = { "(null)", "Neighboring Router ID", "Designated Router address", "Net", "Neighboring Router ID", }; const char *link_data_desc[] = { "(null)", "Router Interface address", "Router Interface address", "Network Mask", "Router Interface address", }; /* Show router-LSA each Link information. */ static void show_ip_ospf_database_router_links (struct vty *vty, struct router_lsa *rl) { int len, i, type; len = ntohs (rl->header.length) - 4; for (i = 0; i < ntohs (rl->links) && len > 0; len -= 12, i++) { type = rl->link[i].type; vty_out (vty, " Link connected to: %s%s", link_type_desc[type], VTY_NEWLINE); vty_out (vty, " (Link ID) %s: %s%s", link_id_desc[type], inet_ntoa (rl->link[i].link_id), VTY_NEWLINE); vty_out (vty, " (Link Data) %s: %s%s", link_data_desc[type], inet_ntoa (rl->link[i].link_data), VTY_NEWLINE); vty_out (vty, " Number of TOS metrics: 0%s", VTY_NEWLINE); vty_out (vty, " TOS 0 Metric: %d%s", ntohs (rl->link[i].metric), VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } } /* Show router-LSA detail information. */ static int show_router_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { struct router_lsa *rl = (struct router_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Number of Links: %d%s%s", ntohs (rl->links), VTY_NEWLINE, VTY_NEWLINE); show_ip_ospf_database_router_links (vty, rl); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show network-LSA detail information. */ static int show_network_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { int length, i; if (lsa != NULL) { struct network_lsa *nl = (struct network_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Network Mask: /%d%s", ip_masklen (nl->mask), VTY_NEWLINE); length = ntohs (lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4; for (i = 0; length > 0; i++, length -= 4) vty_out (vty, " Attached Router: %s%s", inet_ntoa (nl->routers[i]), VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show summary-LSA detail information. */ static int show_summary_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { struct summary_lsa *sl = (struct summary_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Network Mask: /%d%s", ip_masklen (sl->mask), VTY_NEWLINE); vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show summary-ASBR-LSA detail information. */ static int show_summary_asbr_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { struct summary_lsa *sl = (struct summary_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Network Mask: /%d%s", ip_masklen (sl->mask), VTY_NEWLINE); vty_out (vty, " TOS: 0 Metric: %d%s", GET_METRIC (sl->metric), VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Show AS-external-LSA detail information. */ static int show_as_external_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Network Mask: /%d%s", ip_masklen (al->mask), VTY_NEWLINE); vty_out (vty, " Metric Type: %s%s", IS_EXTERNAL_METRIC (al->e[0].tos) ? "2 (Larger than any link state path)" : "1", VTY_NEWLINE); vty_out (vty, " TOS: 0%s", VTY_NEWLINE); vty_out (vty, " Metric: %d%s", GET_METRIC (al->e[0].metric), VTY_NEWLINE); vty_out (vty, " Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); vty_out (vty, " External Route Tag: %lu%s%s", (u_long)ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); } return 0; } #if 0 static int show_as_external_lsa_stdvty (struct ospf_lsa *lsa) { struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; /* show_ip_ospf_database_header (vty, lsa); */ zlog_debug( " Network Mask: /%d%s", ip_masklen (al->mask), "\n"); zlog_debug( " Metric Type: %s%s", IS_EXTERNAL_METRIC (al->e[0].tos) ? "2 (Larger than any link state path)" : "1", "\n"); zlog_debug( " TOS: 0%s", "\n"); zlog_debug( " Metric: %d%s", GET_METRIC (al->e[0].metric), "\n"); zlog_debug( " Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), "\n"); zlog_debug( " External Route Tag: %u%s%s", ntohl (al->e[0].route_tag), "\n", "\n"); return 0; } #endif /* Show AS-NSSA-LSA detail information. */ static int show_as_nssa_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; show_ip_ospf_database_header (vty, lsa); vty_out (vty, " Network Mask: /%d%s", ip_masklen (al->mask), VTY_NEWLINE); vty_out (vty, " Metric Type: %s%s", IS_EXTERNAL_METRIC (al->e[0].tos) ? "2 (Larger than any link state path)" : "1", VTY_NEWLINE); vty_out (vty, " TOS: 0%s", VTY_NEWLINE); vty_out (vty, " Metric: %d%s", GET_METRIC (al->e[0].metric), VTY_NEWLINE); vty_out (vty, " NSSA: Forward Address: %s%s", inet_ntoa (al->e[0].fwd_addr), VTY_NEWLINE); vty_out (vty, " External Route Tag: %u%s%s", ntohl (al->e[0].route_tag), VTY_NEWLINE, VTY_NEWLINE); } return 0; } static int show_func_dummy (struct vty *vty, struct ospf_lsa *lsa) { return 0; } #ifdef HAVE_OPAQUE_LSA static int show_opaque_lsa_detail (struct vty *vty, struct ospf_lsa *lsa) { if (lsa != NULL) { show_ip_ospf_database_header (vty, lsa); show_opaque_info_detail (vty, lsa); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } #endif /* HAVE_OPAQUE_LSA */ int (*show_function[])(struct vty *, struct ospf_lsa *) = { NULL, show_router_lsa_detail, show_network_lsa_detail, show_summary_lsa_detail, show_summary_asbr_lsa_detail, show_as_external_lsa_detail, show_func_dummy, show_as_nssa_lsa_detail, /* almost same as external */ #ifdef HAVE_OPAQUE_LSA NULL, /* type-8 */ show_opaque_lsa_detail, show_opaque_lsa_detail, show_opaque_lsa_detail, #endif /* HAVE_OPAQUE_LSA */ }; static void show_lsa_prefix_set (struct vty *vty, struct prefix_ls *lp, struct in_addr *id, struct in_addr *adv_router) { memset (lp, 0, sizeof (struct prefix_ls)); lp->family = 0; if (id == NULL) lp->prefixlen = 0; else if (adv_router == NULL) { lp->prefixlen = 32; lp->id = *id; } else { lp->prefixlen = 64; lp->id = *id; lp->adv_router = *adv_router; } } static void show_lsa_detail_proc (struct vty *vty, struct route_table *rt, struct in_addr *id, struct in_addr *adv_router) { struct prefix_ls lp; struct route_node *rn, *start; struct ospf_lsa *lsa; show_lsa_prefix_set (vty, &lp, id, adv_router); start = route_node_get (rt, (struct prefix *) &lp); if (start) { route_lock_node (start); for (rn = start; rn; rn = route_next_until (rn, start)) if ((lsa = rn->info)) { if (show_function[lsa->data->type] != NULL) show_function[lsa->data->type] (vty, lsa); } route_unlock_node (start); } } /* Show detail LSA information -- if id is NULL then show all LSAs. */ static void show_lsa_detail (struct vty *vty, struct ospf *ospf, int type, struct in_addr *id, struct in_addr *adv_router) { struct listnode *node; struct ospf_area *area; switch (type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_proc (vty, AS_LSDB (ospf, type), id, adv_router); break; default: for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { vty_out (vty, "%s %s (Area %s)%s%s", VTY_NEWLINE, show_database_desc[type], ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_proc (vty, AREA_LSDB (area, type), id, adv_router); } break; } } static void show_lsa_detail_adv_router_proc (struct vty *vty, struct route_table *rt, struct in_addr *adv_router) { struct route_node *rn; struct ospf_lsa *lsa; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((lsa = rn->info)) if (IPV4_ADDR_SAME (adv_router, &lsa->data->adv_router)) { if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) continue; if (show_function[lsa->data->type] != NULL) show_function[lsa->data->type] (vty, lsa); } } /* Show detail LSA information. */ static void show_lsa_detail_adv_router (struct vty *vty, struct ospf *ospf, int type, struct in_addr *adv_router) { struct listnode *node; struct ospf_area *area; switch (type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ vty_out (vty, " %s %s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_adv_router_proc (vty, AS_LSDB (ospf, type), adv_router); break; default: for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { vty_out (vty, "%s %s (Area %s)%s%s", VTY_NEWLINE, show_database_desc[type], ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); show_lsa_detail_adv_router_proc (vty, AREA_LSDB (area, type), adv_router); } break; } } static void show_ip_ospf_database_summary (struct vty *vty, struct ospf *ospf, int self) { struct ospf_lsa *lsa; struct route_node *rn; struct ospf_area *area; struct listnode *node; int type; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { switch (type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ continue; default: break; } if (ospf_lsdb_count_self (area->lsdb, type) > 0 || (!self && ospf_lsdb_count (area->lsdb, type) > 0)) { vty_out (vty, " %s (Area %s)%s%s", show_database_desc[type], ospf_area_desc_string (area), VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); LSDB_LOOP (AREA_LSDB (area, type), rn, lsa) show_lsa_summary (vty, lsa, self); vty_out (vty, "%s", VTY_NEWLINE); } } } for (type = OSPF_MIN_LSA; type < OSPF_MAX_LSA; type++) { switch (type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ break; default: continue; } if (ospf_lsdb_count_self (ospf->lsdb, type) || (!self && ospf_lsdb_count (ospf->lsdb, type))) { vty_out (vty, " %s%s%s", show_database_desc[type], VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, "%s%s", show_database_header[type], VTY_NEWLINE); LSDB_LOOP (AS_LSDB (ospf, type), rn, lsa) show_lsa_summary (vty, lsa, self); vty_out (vty, "%s", VTY_NEWLINE); } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_database_maxage (struct vty *vty, struct ospf *ospf) { struct route_node *rn; vty_out (vty, "%s MaxAge Link States:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) { struct ospf_lsa *lsa; if ((lsa = rn->info) != NULL) { vty_out (vty, "Link type: %d%s", lsa->data->type, VTY_NEWLINE); vty_out (vty, "Link State ID: %s%s", inet_ntoa (lsa->data->id), VTY_NEWLINE); vty_out (vty, "Advertising Router: %s%s", inet_ntoa (lsa->data->adv_router), VTY_NEWLINE); vty_out (vty, "LSA lock count: %d%s", lsa->lock, VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); } } } #define OSPF_LSA_TYPE_NSSA_DESC "NSSA external link state\n" #define OSPF_LSA_TYPE_NSSA_CMD_STR "|nssa-external" #ifdef HAVE_OPAQUE_LSA #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "Link local Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "Link area Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "Link AS Opaque-LSA\n" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "|opaque-link|opaque-area|opaque-as" #else /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPE_OPAQUE_LINK_DESC "" #define OSPF_LSA_TYPE_OPAQUE_AREA_DESC "" #define OSPF_LSA_TYPE_OPAQUE_AS_DESC "" #define OSPF_LSA_TYPE_OPAQUE_CMD_STR "" #endif /* HAVE_OPAQUE_LSA */ #define OSPF_LSA_TYPES_CMD_STR \ "asbr-summary|external|network|router|summary" \ OSPF_LSA_TYPE_NSSA_CMD_STR \ OSPF_LSA_TYPE_OPAQUE_CMD_STR #define OSPF_LSA_TYPES_DESC \ "ASBR summary link states\n" \ "External link states\n" \ "Network link states\n" \ "Router link states\n" \ "Network summary link states\n" \ OSPF_LSA_TYPE_NSSA_DESC \ OSPF_LSA_TYPE_OPAQUE_LINK_DESC \ OSPF_LSA_TYPE_OPAQUE_AREA_DESC \ OSPF_LSA_TYPE_OPAQUE_AS_DESC DEFUN (show_ip_ospf_database, show_ip_ospf_database_cmd, "show ip ospf database", SHOW_STR IP_STR "OSPF information\n" "Database summary\n") { struct ospf *ospf; int type, ret; struct in_addr id, adv_router; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, inet_ntoa (ospf->router_id), VTY_NEWLINE, VTY_NEWLINE); /* Show all LSA. */ if (argc == 0) { show_ip_ospf_database_summary (vty, ospf, 0); return CMD_SUCCESS; } /* Set database type to show. */ if (strncmp (argv[0], "r", 1) == 0) type = OSPF_ROUTER_LSA; else if (strncmp (argv[0], "ne", 2) == 0) type = OSPF_NETWORK_LSA; else if (strncmp (argv[0], "ns", 2) == 0) type = OSPF_AS_NSSA_LSA; else if (strncmp (argv[0], "su", 2) == 0) type = OSPF_SUMMARY_LSA; else if (strncmp (argv[0], "a", 1) == 0) type = OSPF_ASBR_SUMMARY_LSA; else if (strncmp (argv[0], "e", 1) == 0) type = OSPF_AS_EXTERNAL_LSA; else if (strncmp (argv[0], "se", 2) == 0) { show_ip_ospf_database_summary (vty, ospf, 1); return CMD_SUCCESS; } else if (strncmp (argv[0], "m", 1) == 0) { show_ip_ospf_database_maxage (vty, ospf); return CMD_SUCCESS; } #ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; #endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; /* `show ip ospf database LSA'. */ if (argc == 1) show_lsa_detail (vty, ospf, type, NULL, NULL); else if (argc >= 2) { ret = inet_aton (argv[1], &id); if (!ret) return CMD_WARNING; /* `show ip ospf database LSA ID'. */ if (argc == 2) show_lsa_detail (vty, ospf, type, &id, NULL); /* `show ip ospf database LSA ID adv-router ADV_ROUTER'. */ else if (argc == 3) { if (strncmp (argv[2], "s", 1) == 0) adv_router = ospf->router_id; else { ret = inet_aton (argv[2], &adv_router); if (!ret) return CMD_WARNING; } show_lsa_detail (vty, ospf, type, &id, &adv_router); } } return CMD_SUCCESS; } ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR "|max-age|self-originate)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "LSAs in MaxAge list\n" "Self-originated link states\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_adv_router_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D adv-router A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" "Advertising Router link states\n" "Advertising Router (as an IP address)\n") ALIAS (show_ip_ospf_database, show_ip_ospf_database_type_id_self_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") A.B.C.D (self-originate|)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Link State ID (as an IP address)\n" "Self-originated link states\n" "\n") DEFUN (show_ip_ospf_database_type_adv_router, show_ip_ospf_database_type_adv_router_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") adv-router A.B.C.D", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Advertising Router link states\n" "Advertising Router (as an IP address)\n") { struct ospf *ospf; int type, ret; struct in_addr adv_router; ospf = ospf_lookup (); if (ospf == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } vty_out (vty, "%s OSPF Router with ID (%s)%s%s", VTY_NEWLINE, inet_ntoa (ospf->router_id), VTY_NEWLINE, VTY_NEWLINE); if (argc != 2) return CMD_WARNING; /* Set database type to show. */ if (strncmp (argv[0], "r", 1) == 0) type = OSPF_ROUTER_LSA; else if (strncmp (argv[0], "ne", 2) == 0) type = OSPF_NETWORK_LSA; else if (strncmp (argv[0], "ns", 2) == 0) type = OSPF_AS_NSSA_LSA; else if (strncmp (argv[0], "s", 1) == 0) type = OSPF_SUMMARY_LSA; else if (strncmp (argv[0], "a", 1) == 0) type = OSPF_ASBR_SUMMARY_LSA; else if (strncmp (argv[0], "e", 1) == 0) type = OSPF_AS_EXTERNAL_LSA; #ifdef HAVE_OPAQUE_LSA else if (strncmp (argv[0], "opaque-l", 8) == 0) type = OSPF_OPAQUE_LINK_LSA; else if (strncmp (argv[0], "opaque-ar", 9) == 0) type = OSPF_OPAQUE_AREA_LSA; else if (strncmp (argv[0], "opaque-as", 9) == 0) type = OSPF_OPAQUE_AS_LSA; #endif /* HAVE_OPAQUE_LSA */ else return CMD_WARNING; /* `show ip ospf database LSA adv-router ADV_ROUTER'. */ if (strncmp (argv[1], "s", 1) == 0) adv_router = ospf->router_id; else { ret = inet_aton (argv[1], &adv_router); if (!ret) return CMD_WARNING; } show_lsa_detail_adv_router (vty, ospf, type, &adv_router); return CMD_SUCCESS; } ALIAS (show_ip_ospf_database_type_adv_router, show_ip_ospf_database_type_self_cmd, "show ip ospf database (" OSPF_LSA_TYPES_CMD_STR ") (self-originate|)", SHOW_STR IP_STR "OSPF information\n" "Database summary\n" OSPF_LSA_TYPES_DESC "Self-originated link states\n") DEFUN (ip_ospf_authentication_args, ip_ospf_authentication_args_addr_cmd, "ip ospf authentication (null|message-digest) A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } /* Handle null authentication */ if ( argv[0][0] == 'n' ) { SET_IF_PARAM (params, auth_type); params->auth_type = OSPF_AUTH_NULL; return CMD_SUCCESS; } /* Handle message-digest authentication */ if ( argv[0][0] == 'm' ) { SET_IF_PARAM (params, auth_type); params->auth_type = OSPF_AUTH_CRYPTOGRAPHIC; return CMD_SUCCESS; } vty_out (vty, "You shouldn't get here!%s", VTY_NEWLINE); return CMD_WARNING; } ALIAS (ip_ospf_authentication_args, ip_ospf_authentication_args_cmd, "ip ospf authentication (null|message-digest)", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Use null authentication\n" "Use message-digest authentication\n") DEFUN (ip_ospf_authentication, ip_ospf_authentication_addr_cmd, "ip ospf authentication A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, auth_type); params->auth_type = OSPF_AUTH_SIMPLE; return CMD_SUCCESS; } ALIAS (ip_ospf_authentication, ip_ospf_authentication_cmd, "ip ospf authentication", "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n") DEFUN (no_ip_ospf_authentication, no_ip_ospf_authentication_addr_cmd, "no ip ospf authentication A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } params->auth_type = OSPF_AUTH_NOTSET; UNSET_IF_PARAM (params, auth_type); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_authentication, no_ip_ospf_authentication_cmd, "no ip ospf authentication", NO_STR "IP Information\n" "OSPF interface commands\n" "Enable authentication on this interface\n") DEFUN (ip_ospf_authentication_key, ip_ospf_authentication_key_addr_cmd, "ip ospf authentication-key AUTH_KEY A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE + 1); strncpy ((char *) params->auth_simple, argv[0], OSPF_AUTH_SIMPLE_SIZE); SET_IF_PARAM (params, auth_simple); return CMD_SUCCESS; } ALIAS (ip_ospf_authentication_key, ip_ospf_authentication_key_cmd, "ip ospf authentication-key AUTH_KEY", "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)") ALIAS (ip_ospf_authentication_key, ospf_authentication_key_cmd, "ospf authentication-key AUTH_KEY", "OSPF interface commands\n" "Authentication password (key)\n" "The OSPF password (key)") DEFUN (no_ip_ospf_authentication_key, no_ip_ospf_authentication_key_addr_cmd, "no ip ospf authentication-key A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n" "Address of interface") { struct interface *ifp; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } memset (params->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); UNSET_IF_PARAM (params, auth_simple); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_authentication_key, no_ip_ospf_authentication_key_cmd, "no ip ospf authentication-key", NO_STR "IP Information\n" "OSPF interface commands\n" "Authentication password (key)\n") ALIAS (no_ip_ospf_authentication_key, no_ospf_authentication_key_cmd, "no ospf authentication-key", NO_STR "OSPF interface commands\n" "Authentication password (key)\n") DEFUN (ip_ospf_message_digest_key, ip_ospf_message_digest_key_addr_cmd, "ip ospf message-digest-key <1-255> md5 KEY A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)" "Address of interface") { struct interface *ifp; struct crypt_key *ck; u_char key_id; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 3) { ret = inet_aton(argv[2], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } key_id = strtol (argv[0], NULL, 10); if (ospf_crypt_key_lookup (params->auth_crypt, key_id) != NULL) { vty_out (vty, "OSPF: Key %d already exists%s", key_id, VTY_NEWLINE); return CMD_WARNING; } ck = ospf_crypt_key_new (); ck->key_id = (u_char) key_id; memset (ck->auth_key, 0, OSPF_AUTH_MD5_SIZE+1); strncpy ((char *) ck->auth_key, argv[1], OSPF_AUTH_MD5_SIZE); ospf_crypt_key_add (params->auth_crypt, ck); SET_IF_PARAM (params, auth_crypt); return CMD_SUCCESS; } ALIAS (ip_ospf_message_digest_key, ip_ospf_message_digest_key_cmd, "ip ospf message-digest-key <1-255> md5 KEY", "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") ALIAS (ip_ospf_message_digest_key, ospf_message_digest_key_cmd, "ospf message-digest-key <1-255> md5 KEY", "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Use MD5 algorithm\n" "The OSPF password (key)") DEFUN (no_ip_ospf_message_digest_key, no_ip_ospf_message_digest_key_addr_cmd, "no ip ospf message-digest-key <1-255> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n" "Address of interface") { struct interface *ifp; struct crypt_key *ck; int key_id; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } key_id = strtol (argv[0], NULL, 10); ck = ospf_crypt_key_lookup (params->auth_crypt, key_id); if (ck == NULL) { vty_out (vty, "OSPF: Key %d does not exist%s", key_id, VTY_NEWLINE); return CMD_WARNING; } ospf_crypt_key_delete (params->auth_crypt, key_id); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_message_digest_key, no_ip_ospf_message_digest_key_cmd, "no ip ospf message-digest-key <1-255>", NO_STR "IP Information\n" "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n") ALIAS (no_ip_ospf_message_digest_key, no_ospf_message_digest_key_cmd, "no ospf message-digest-key <1-255>", NO_STR "OSPF interface commands\n" "Message digest authentication password (key)\n" "Key ID\n") DEFUN (ip_ospf_cost, ip_ospf_cost_u32_inet4_cmd, "ip ospf cost <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") { struct interface *ifp = vty->index; u_int32_t cost; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); cost = strtol (argv[0], NULL, 10); /* cost range is <1-65535>. */ if (cost < 1 || cost > 65535) { vty_out (vty, "Interface output cost is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, output_cost_cmd); params->output_cost_cmd = cost; ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } ALIAS (ip_ospf_cost, ip_ospf_cost_u32_cmd, "ip ospf cost <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (ip_ospf_cost, ospf_cost_u32_cmd, "ospf cost <1-65535>", "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (ip_ospf_cost, ospf_cost_u32_inet4_cmd, "ospf cost <1-65535> A.B.C.D", "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") DEFUN (no_ip_ospf_cost, no_ip_ospf_cost_inet4_cmd, "no ip ospf cost A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, output_cost_cmd); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } ALIAS (no_ip_ospf_cost, no_ip_ospf_cost_cmd, "no ip ospf cost", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n") ALIAS (no_ip_ospf_cost, no_ospf_cost_cmd, "no ospf cost", NO_STR "OSPF interface commands\n" "Interface cost\n") ALIAS (no_ip_ospf_cost, no_ospf_cost_inet4_cmd, "no ospf cost A.B.C.D", NO_STR "OSPF interface commands\n" "Interface cost\n" "Address of interface") DEFUN (no_ip_ospf_cost2, no_ip_ospf_cost_u32_cmd, "no ip ospf cost <1-65535>", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost") { struct interface *ifp = vty->index; struct in_addr addr; u_int32_t cost; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); /* According to the semantics we are mimicking "no ip ospf cost N" is * always treated as "no ip ospf cost" regardless of the actual value * of N already configured for the interface. Thus the first argument * is always checked to be a number, but is ignored after that. */ cost = strtol (argv[0], NULL, 10); if (cost < 1 || cost > 65535) { vty_out (vty, "Interface output cost is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, output_cost_cmd); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } ospf_if_recalculate_output_cost (ifp); return CMD_SUCCESS; } ALIAS (no_ip_ospf_cost2, no_ospf_cost_u32_cmd, "no ospf cost <1-65535>", NO_STR "OSPF interface commands\n" "Interface cost\n" "Cost") ALIAS (no_ip_ospf_cost2, no_ip_ospf_cost_u32_inet4_cmd, "no ip ospf cost <1-65535> A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") ALIAS (no_ip_ospf_cost2, no_ospf_cost_u32_inet4_cmd, "no ospf cost <1-65535> A.B.C.D", NO_STR "OSPF interface commands\n" "Interface cost\n" "Cost\n" "Address of interface") static void ospf_nbr_timer_update (struct ospf_interface *oi) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) { nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval); nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval); } } static int ospf_vty_dead_interval_set (struct vty *vty, const char *interval_str, const char *nbr_str, const char *fast_hello_str) { struct interface *ifp = vty->index; u_int32_t seconds; u_char hellomult; struct in_addr addr; int ret; struct ospf_if_params *params; struct ospf_interface *oi; struct route_node *rn; params = IF_DEF_PARAMS (ifp); if (nbr_str) { ret = inet_aton(nbr_str, &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } if (interval_str) { VTY_GET_INTEGER_RANGE ("Router Dead Interval", seconds, interval_str, 1, 65535); /* reset fast_hello too, just to be sure */ UNSET_IF_PARAM (params, fast_hello); params->fast_hello = OSPF_FAST_HELLO_DEFAULT; } else if (fast_hello_str) { VTY_GET_INTEGER_RANGE ("Hello Multiplier", hellomult, fast_hello_str, 1, 10); /* 1s dead-interval with sub-second hellos desired */ seconds = OSPF_ROUTER_DEAD_INTERVAL_MINIMAL; SET_IF_PARAM (params, fast_hello); params->fast_hello = hellomult; } else { vty_out (vty, "Please specify dead-interval or hello-multiplier%s", VTY_NEWLINE); return CMD_WARNING; } SET_IF_PARAM (params, v_wait); params->v_wait = seconds; /* Update timer values in neighbor structure. */ if (nbr_str) { struct ospf *ospf; if ((ospf = ospf_lookup())) { oi = ospf_if_lookup_by_local_addr (ospf, ifp, addr); if (oi) ospf_nbr_timer_update (oi); } } else { for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if ((oi = rn->info)) ospf_nbr_timer_update (oi); } return CMD_SUCCESS; } DEFUN (ip_ospf_dead_interval, ip_ospf_dead_interval_addr_cmd, "ip ospf dead-interval <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n" "Address of interface\n") { if (argc == 2) return ospf_vty_dead_interval_set (vty, argv[0], argv[1], NULL); else return ospf_vty_dead_interval_set (vty, argv[0], NULL, NULL); } ALIAS (ip_ospf_dead_interval, ip_ospf_dead_interval_cmd, "ip ospf dead-interval <1-65535>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") ALIAS (ip_ospf_dead_interval, ospf_dead_interval_cmd, "ospf dead-interval <1-65535>", "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Seconds\n") DEFUN (ip_ospf_dead_interval_minimal, ip_ospf_dead_interval_minimal_addr_cmd, "ip ospf dead-interval minimal hello-multiplier <1-10> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n" "Address of interface\n") { if (argc == 2) return ospf_vty_dead_interval_set (vty, NULL, argv[1], argv[0]); else return ospf_vty_dead_interval_set (vty, NULL, NULL, argv[0]); } ALIAS (ip_ospf_dead_interval_minimal, ip_ospf_dead_interval_minimal_cmd, "ip ospf dead-interval minimal hello-multiplier <1-10>", "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Minimal 1s dead-interval with fast sub-second hellos\n" "Hello multiplier factor\n" "Number of Hellos to send each second\n") DEFUN (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_addr_cmd, "no ip ospf dead-interval A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; struct ospf_interface *oi; struct route_node *rn; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, v_wait); params->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; UNSET_IF_PARAM (params, fast_hello); params->fast_hello = OSPF_FAST_HELLO_DEFAULT; if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } /* Update timer values in neighbor structure. */ if (argc == 1) { struct ospf *ospf; if ((ospf = ospf_lookup())) { oi = ospf_if_lookup_by_local_addr (ospf, ifp, addr); if (oi) ospf_nbr_timer_update (oi); } } else { for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if ((oi = rn->info)) ospf_nbr_timer_update (oi); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_dead_interval, no_ip_ospf_dead_interval_cmd, "no ip ospf dead-interval", NO_STR "IP Information\n" "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") ALIAS (no_ip_ospf_dead_interval, no_ospf_dead_interval_cmd, "no ospf dead-interval", NO_STR "OSPF interface commands\n" "Interval after which a neighbor is declared dead\n") DEFUN (ip_ospf_hello_interval, ip_ospf_hello_interval_addr_cmd, "ip ospf hello-interval <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; u_int32_t seconds; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); seconds = strtol (argv[0], NULL, 10); /* HelloInterval range is <1-65535>. */ if (seconds < 1 || seconds > 65535) { vty_out (vty, "Hello Interval is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, v_hello); params->v_hello = seconds; return CMD_SUCCESS; } ALIAS (ip_ospf_hello_interval, ip_ospf_hello_interval_cmd, "ip ospf hello-interval <1-65535>", "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") ALIAS (ip_ospf_hello_interval, ospf_hello_interval_cmd, "ospf hello-interval <1-65535>", "OSPF interface commands\n" "Time between HELLO packets\n" "Seconds\n") DEFUN (no_ip_ospf_hello_interval, no_ip_ospf_hello_interval_addr_cmd, "no ip ospf hello-interval A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, v_hello); params->v_hello = OSPF_HELLO_INTERVAL_DEFAULT; if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_hello_interval, no_ip_ospf_hello_interval_cmd, "no ip ospf hello-interval", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between HELLO packets\n") ALIAS (no_ip_ospf_hello_interval, no_ospf_hello_interval_cmd, "no ospf hello-interval", NO_STR "OSPF interface commands\n" "Time between HELLO packets\n") DEFUN (ip_ospf_network, ip_ospf_network_cmd, "ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "IP Information\n" "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; struct route_node *rn; if (old_type == OSPF_IFTYPE_LOOPBACK) { vty_out (vty, "This is a loopback interface. Can't set network type.%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp (argv[0], "b", 1) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_BROADCAST; else if (strncmp (argv[0], "n", 1) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_NBMA; else if (strncmp (argv[0], "point-to-m", 10) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; else if (strncmp (argv[0], "point-to-p", 10) == 0) IF_DEF_PARAMS (ifp)->type = OSPF_IFTYPE_POINTOPOINT; if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; oi->type = IF_DEF_PARAMS (ifp)->type; if (oi->state > ISM_Down) { OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); } } return CMD_SUCCESS; } ALIAS (ip_ospf_network, ospf_network_cmd, "ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)", "OSPF interface commands\n" "Network type\n" "Specify OSPF broadcast multi-access network\n" "Specify OSPF NBMA network\n" "Specify OSPF point-to-multipoint network\n" "Specify OSPF point-to-point network\n") DEFUN (no_ip_ospf_network, no_ip_ospf_network_cmd, "no ip ospf network", NO_STR "IP Information\n" "OSPF interface commands\n" "Network type\n") { struct interface *ifp = vty->index; int old_type = IF_DEF_PARAMS (ifp)->type; struct route_node *rn; IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); if (IF_DEF_PARAMS (ifp)->type == old_type) return CMD_SUCCESS; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; oi->type = IF_DEF_PARAMS (ifp)->type; if (oi->state > ISM_Down) { OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceUp); } } return CMD_SUCCESS; } ALIAS (no_ip_ospf_network, no_ospf_network_cmd, "no ospf network", NO_STR "OSPF interface commands\n" "Network type\n") DEFUN (ip_ospf_priority, ip_ospf_priority_addr_cmd, "ip ospf priority <0-255> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n" "Address of interface") { struct interface *ifp = vty->index; long priority; struct route_node *rn; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); priority = strtol (argv[0], NULL, 10); /* Router Priority range is <0-255>. */ if (priority < 0 || priority > 255) { vty_out (vty, "Router Priority is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, priority); params->priority = priority; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) { PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); } } return CMD_SUCCESS; } ALIAS (ip_ospf_priority, ip_ospf_priority_cmd, "ip ospf priority <0-255>", "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Priority\n") ALIAS (ip_ospf_priority, ospf_priority_cmd, "ospf priority <0-255>", "OSPF interface commands\n" "Router priority\n" "Priority\n") DEFUN (no_ip_ospf_priority, no_ip_ospf_priority_addr_cmd, "no ip ospf priority A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Router priority\n" "Address of interface") { struct interface *ifp = vty->index; struct route_node *rn; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, priority); params->priority = OSPF_ROUTER_PRIORITY_DEFAULT; if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi = rn->info; if (!oi) continue; if (PRIORITY (oi) != OSPF_IF_PARAM (oi, priority)) { PRIORITY (oi) = OSPF_IF_PARAM (oi, priority); OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); } } return CMD_SUCCESS; } ALIAS (no_ip_ospf_priority, no_ip_ospf_priority_cmd, "no ip ospf priority", NO_STR "IP Information\n" "OSPF interface commands\n" "Router priority\n") ALIAS (no_ip_ospf_priority, no_ospf_priority_cmd, "no ospf priority", NO_STR "OSPF interface commands\n" "Router priority\n") DEFUN (ip_ospf_retransmit_interval, ip_ospf_retransmit_interval_addr_cmd, "ip ospf retransmit-interval <3-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; u_int32_t seconds; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); seconds = strtol (argv[0], NULL, 10); /* Retransmit Interval range is <3-65535>. */ if (seconds < 3 || seconds > 65535) { vty_out (vty, "Retransmit Interval is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, retransmit_interval); params->retransmit_interval = seconds; return CMD_SUCCESS; } ALIAS (ip_ospf_retransmit_interval, ip_ospf_retransmit_interval_cmd, "ip ospf retransmit-interval <3-65535>", "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n") ALIAS (ip_ospf_retransmit_interval, ospf_retransmit_interval_cmd, "ospf retransmit-interval <3-65535>", "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Seconds\n") DEFUN (no_ip_ospf_retransmit_interval, no_ip_ospf_retransmit_interval_addr_cmd, "no ip ospf retransmit-interval A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, retransmit_interval); params->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_retransmit_interval, no_ip_ospf_retransmit_interval_cmd, "no ip ospf retransmit-interval", NO_STR "IP Information\n" "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n") ALIAS (no_ip_ospf_retransmit_interval, no_ospf_retransmit_interval_cmd, "no ospf retransmit-interval", NO_STR "OSPF interface commands\n" "Time between retransmitting lost link state advertisements\n") DEFUN (ip_ospf_transmit_delay, ip_ospf_transmit_delay_addr_cmd, "ip ospf transmit-delay <1-65535> A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n" "Address of interface") { struct interface *ifp = vty->index; u_int32_t seconds; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); seconds = strtol (argv[0], NULL, 10); /* Transmit Delay range is <1-65535>. */ if (seconds < 1 || seconds > 65535) { vty_out (vty, "Transmit Delay is invalid%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 2) { ret = inet_aton(argv[1], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } SET_IF_PARAM (params, transmit_delay); params->transmit_delay = seconds; return CMD_SUCCESS; } ALIAS (ip_ospf_transmit_delay, ip_ospf_transmit_delay_cmd, "ip ospf transmit-delay <1-65535>", "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n") ALIAS (ip_ospf_transmit_delay, ospf_transmit_delay_cmd, "ospf transmit-delay <1-65535>", "OSPF interface commands\n" "Link state transmit delay\n" "Seconds\n") DEFUN (no_ip_ospf_transmit_delay, no_ip_ospf_transmit_delay_addr_cmd, "no ip ospf transmit-delay A.B.C.D", NO_STR "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; ifp = vty->index; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_lookup_if_params (ifp, addr); if (params == NULL) return CMD_SUCCESS; } UNSET_IF_PARAM (params, transmit_delay); params->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } return CMD_SUCCESS; } ALIAS (no_ip_ospf_transmit_delay, no_ip_ospf_transmit_delay_cmd, "no ip ospf transmit-delay", NO_STR "IP Information\n" "OSPF interface commands\n" "Link state transmit delay\n") ALIAS (no_ip_ospf_transmit_delay, no_ospf_transmit_delay_cmd, "no ospf transmit-delay", NO_STR "OSPF interface commands\n" "Link state transmit delay\n") DEFUN (ospf_redistribute_source, ospf_redistribute_source_cmd, "redistribute " QUAGGA_REDIST_STR_OSPFD " {metric <0-16777214>|metric-type (1|2)|route-map WORD}", REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD "Metric for redistributed routes\n" "OSPF default metric\n" "OSPF exterior metric type for redistributed routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int source; int type = -1; int metric = -1; if (argc < 4) return CMD_WARNING; /* should not happen */ /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; /* Get metric value. */ if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ if (argv[2] != NULL) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; if (argv[3] != NULL) ospf_routemap_set (ospf, source, argv[3]); else ospf_routemap_unset (ospf, source); return ospf_redistribute_set (ospf, source, type, metric); } DEFUN (no_ospf_redistribute_source, no_ospf_redistribute_source_cmd, "no redistribute " QUAGGA_REDIST_STR_OSPFD, NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; source = proto_redistnum(AFI_IP, argv[0]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; ospf_routemap_unset (ospf, source); return ospf_redistribute_unset (ospf, source); } DEFUN (ospf_distribute_list_out, ospf_distribute_list_out_cmd, "distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, "Filter networks in routing updates\n" "Access-list name\n" OUT_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; /* Get distribute source. */ source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; return ospf_distribute_list_out_set (ospf, source, argv[0]); } DEFUN (no_ospf_distribute_list_out, no_ospf_distribute_list_out_cmd, "no distribute-list WORD out " QUAGGA_REDIST_STR_OSPFD, NO_STR "Filter networks in routing updates\n" "Access-list name\n" OUT_STR QUAGGA_REDIST_HELP_STR_OSPFD) { struct ospf *ospf = vty->index; int source; source = proto_redistnum(AFI_IP, argv[1]); if (source < 0 || source == ZEBRA_ROUTE_OSPF) return CMD_WARNING; return ospf_distribute_list_out_unset (ospf, source, argv[0]); } /* Default information originate. */ DEFUN (ospf_default_information_originate, ospf_default_information_originate_cmd, "default-information originate " "{always|metric <0-16777214>|metric-type (1|2)|route-map WORD}", "Control distribution of default information\n" "Distribute a default route\n" "Always advertise default route\n" "OSPF default metric\n" "OSPF metric\n" "OSPF metric type for default routes\n" "Set OSPF External Type 1 metrics\n" "Set OSPF External Type 2 metrics\n" "Route map reference\n" "Pointer to route-map entries\n") { struct ospf *ospf = vty->index; int default_originate = DEFAULT_ORIGINATE_ZEBRA; int type = -1; int metric = -1; if (argc < 4) return CMD_WARNING; /* this should not happen */ /* Check whether "always" was specified */ if (argv[0] != NULL) default_originate = DEFAULT_ORIGINATE_ALWAYS; /* Get metric value. */ if (argv[1] != NULL) if (!str2metric (argv[1], &metric)) return CMD_WARNING; /* Get metric type. */ if (argv[2] != NULL) if (!str2metric_type (argv[2], &type)) return CMD_WARNING; if (argv[3] != NULL) ospf_routemap_set (ospf, DEFAULT_ROUTE, argv[3]); else ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_set (ospf, default_originate, type, metric); } DEFUN (no_ospf_default_information_originate, no_ospf_default_information_originate_cmd, "no default-information originate", NO_STR "Control distribution of default information\n" "Distribute a default route\n") { struct ospf *ospf = vty->index; struct prefix_ipv4 p; p.family = AF_INET; p.prefix.s_addr = 0; p.prefixlen = 0; ospf_external_lsa_flush (ospf, DEFAULT_ROUTE, &p, 0); if (EXTERNAL_INFO (DEFAULT_ROUTE)) { ospf_external_info_delete (DEFAULT_ROUTE, p); route_table_finish (EXTERNAL_INFO (DEFAULT_ROUTE)); EXTERNAL_INFO (DEFAULT_ROUTE) = NULL; } ospf_routemap_unset (ospf, DEFAULT_ROUTE); return ospf_redistribute_default_unset (ospf); } DEFUN (ospf_default_metric, ospf_default_metric_cmd, "default-metric <0-16777214>", "Set metric of redistributed routes\n" "Default metric\n") { struct ospf *ospf = vty->index; int metric = -1; if (!str2metric (argv[0], &metric)) return CMD_WARNING; ospf->default_metric = metric; return CMD_SUCCESS; } DEFUN (no_ospf_default_metric, no_ospf_default_metric_cmd, "no default-metric", NO_STR "Set metric of redistributed routes\n") { struct ospf *ospf = vty->index; ospf->default_metric = -1; return CMD_SUCCESS; } ALIAS (no_ospf_default_metric, no_ospf_default_metric_val_cmd, "no default-metric <0-16777214>", NO_STR "Set metric of redistributed routes\n" "Default metric\n") DEFUN (ospf_distance, ospf_distance_cmd, "distance <1-255>", "Define an administrative distance\n" "OSPF Administrative distance\n") { struct ospf *ospf = vty->index; ospf->distance_all = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (no_ospf_distance, no_ospf_distance_cmd, "no distance <1-255>", NO_STR "Define an administrative distance\n" "OSPF Administrative distance\n") { struct ospf *ospf = vty->index; ospf->distance_all = 0; return CMD_SUCCESS; } DEFUN (no_ospf_distance_ospf, no_ospf_distance_ospf_cmd, "no distance ospf {intra-area|inter-area|external}", NO_STR "Define an administrative distance\n" "OSPF Administrative distance\n" "OSPF Distance\n" "Intra-area routes\n" "Inter-area routes\n" "External routes\n") { struct ospf *ospf = vty->index; if (argc < 3) return CMD_WARNING; if (argv[0] != NULL) ospf->distance_intra = 0; if (argv[1] != NULL) ospf->distance_inter = 0; if (argv[2] != NULL) ospf->distance_external = 0; if (argv[0] || argv[1] || argv[2]) return CMD_SUCCESS; /* If no arguments are given, clear all distance information */ ospf->distance_intra = 0; ospf->distance_inter = 0; ospf->distance_external = 0; return CMD_SUCCESS; } DEFUN (ospf_distance_ospf, ospf_distance_ospf_cmd, "distance ospf " "{intra-area <1-255>|inter-area <1-255>|external <1-255>}", "Define an administrative distance\n" "OSPF Administrative distance\n" "Intra-area routes\n" "Distance for intra-area routes\n" "Inter-area routes\n" "Distance for inter-area routes\n" "External routes\n" "Distance for external routes\n") { struct ospf *ospf = vty->index; if (argc < 3) /* should not happen */ return CMD_WARNING; if (!argv[0] && !argv[1] && !argv[2]) { vty_out(vty, "%% Command incomplete. (Arguments required)%s", VTY_NEWLINE); return CMD_WARNING; } if (argv[0] != NULL) ospf->distance_intra = atoi(argv[0]); if (argv[1] != NULL) ospf->distance_inter = atoi(argv[1]); if (argv[2] != NULL) ospf->distance_external = atoi(argv[2]); return CMD_SUCCESS; } DEFUN (ospf_distance_source, ospf_distance_source_cmd, "distance <1-255> A.B.C.D/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf *ospf = vty->index; ospf_distance_set (vty, ospf, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_ospf_distance_source, no_ospf_distance_source_cmd, "no distance <1-255> A.B.C.D/M", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n") { struct ospf *ospf = vty->index; ospf_distance_unset (vty, ospf, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (ospf_distance_source_access_list, ospf_distance_source_access_list_cmd, "distance <1-255> A.B.C.D/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf *ospf = vty->index; ospf_distance_set (vty, ospf, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_ospf_distance_source_access_list, no_ospf_distance_source_access_list_cmd, "no distance <1-255> A.B.C.D/M WORD", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { struct ospf *ospf = vty->index; ospf_distance_unset (vty, ospf, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (ip_ospf_mtu_ignore, ip_ospf_mtu_ignore_addr_cmd, "ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } params->mtu_ignore = 1; if (params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) SET_IF_PARAM (params, mtu_ignore); else { UNSET_IF_PARAM (params, mtu_ignore); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } } return CMD_SUCCESS; } ALIAS (ip_ospf_mtu_ignore, ip_ospf_mtu_ignore_cmd, "ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFUN (no_ip_ospf_mtu_ignore, no_ip_ospf_mtu_ignore_addr_cmd, "no ip ospf mtu-ignore A.B.C.D", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n" "Address of interface") { struct interface *ifp = vty->index; struct in_addr addr; int ret; struct ospf_if_params *params; params = IF_DEF_PARAMS (ifp); if (argc == 1) { ret = inet_aton(argv[0], &addr); if (!ret) { vty_out (vty, "Please specify interface address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } params = ospf_get_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } params->mtu_ignore = 0; if (params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) SET_IF_PARAM (params, mtu_ignore); else { UNSET_IF_PARAM (params, mtu_ignore); if (params != IF_DEF_PARAMS (ifp)) { ospf_free_if_params (ifp, addr); ospf_if_update_params (ifp, addr); } } return CMD_SUCCESS; } ALIAS (no_ip_ospf_mtu_ignore, no_ip_ospf_mtu_ignore_cmd, "no ip ospf mtu-ignore", "IP Information\n" "OSPF interface commands\n" "Disable mtu mismatch detection\n") DEFUN (ospf_max_metric_router_lsa_admin, ospf_max_metric_router_lsa_admin_cmd, "max-metric router-lsa administrative", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) ospf_router_lsa_update_area (area); } /* Allows for areas configured later to get the property */ ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_SET; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_admin, no_ospf_max_metric_router_lsa_admin_cmd, "no max-metric router-lsa administrative", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Administratively applied, for an indefinite period\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); /* Don't trample on the start-up stub timer */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) && !area->t_stub_router) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); } } ospf->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; return CMD_SUCCESS; } DEFUN (ospf_max_metric_router_lsa_startup, ospf_max_metric_router_lsa_startup_cmd, "max-metric router-lsa on-startup <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n" "Time (seconds) to advertise self as stub-router\n") { unsigned int seconds; struct ospf *ospf = vty->index; if (argc != 1) { vty_out (vty, "%% Must supply stub-router period"); return CMD_WARNING; } VTY_GET_INTEGER ("stub-router startup period", seconds, argv[0]); ospf->stub_router_startup_time = seconds; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_startup, no_ospf_max_metric_router_lsa_startup_cmd, "no max-metric router-lsa on-startup", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Automatically advertise stub Router-LSA on startup of OSPF\n") { struct listnode *ln; struct ospf_area *area; struct ospf *ospf = vty->index; ospf->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); OSPF_TIMER_OFF (area->t_stub_router); /* Don't trample on admin stub routed */ if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); } } return CMD_SUCCESS; } DEFUN (ospf_max_metric_router_lsa_shutdown, ospf_max_metric_router_lsa_shutdown_cmd, "max-metric router-lsa on-shutdown <5-86400>", "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n" "Time (seconds) to wait till full shutdown\n") { unsigned int seconds; struct ospf *ospf = vty->index; if (argc != 1) { vty_out (vty, "%% Must supply stub-router shutdown period"); return CMD_WARNING; } VTY_GET_INTEGER ("stub-router shutdown wait period", seconds, argv[0]); ospf->stub_router_shutdown_time = seconds; return CMD_SUCCESS; } DEFUN (no_ospf_max_metric_router_lsa_shutdown, no_ospf_max_metric_router_lsa_shutdown_cmd, "no max-metric router-lsa on-shutdown", NO_STR "OSPF maximum / infinite-distance metric\n" "Advertise own Router-LSA with infinite distance (stub router)\n" "Advertise stub-router prior to full shutdown of OSPF\n") { struct ospf *ospf = vty->index; ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; return CMD_SUCCESS; } static void config_write_stub_router (struct vty *vty, struct ospf *ospf) { struct listnode *ln; struct ospf_area *area; if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " max-metric router-lsa on-startup %u%s", ospf->stub_router_startup_time, VTY_NEWLINE); if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) vty_out (vty, " max-metric router-lsa on-shutdown %u%s", ospf->stub_router_shutdown_time, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { vty_out (vty, " max-metric router-lsa administrative%s", VTY_NEWLINE); break; } } return; } static void show_ip_ospf_route_network (struct vty *vty, struct route_table *rt) { struct route_node *rn; struct ospf_route *or; struct listnode *pnode, *pnnode; struct ospf_path *path; vty_out (vty, "============ OSPF network routing table ============%s", VTY_NEWLINE); for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) { char buf1[19]; snprintf (buf1, 19, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (or->path_type) { case OSPF_PATH_INTER_AREA: if (or->type == OSPF_DESTINATION_NETWORK) vty_out (vty, "N IA %-18s [%d] area: %s%s", buf1, or->cost, inet_ntoa (or->u.std.area_id), VTY_NEWLINE); else if (or->type == OSPF_DESTINATION_DISCARD) vty_out (vty, "D IA %-18s Discard entry%s", buf1, VTY_NEWLINE); break; case OSPF_PATH_INTRA_AREA: vty_out (vty, "N %-18s [%d] area: %s%s", buf1, or->cost, inet_ntoa (or->u.std.area_id), VTY_NEWLINE); break; default: break; } if (or->type == OSPF_DESTINATION_NETWORK) for (ALL_LIST_ELEMENTS (or->paths, pnode, pnnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_route_router (struct vty *vty, struct route_table *rtrs) { struct route_node *rn; struct ospf_route *or; struct listnode *pnode; struct listnode *node; struct ospf_path *path; vty_out (vty, "============ OSPF router routing table =============%s", VTY_NEWLINE); for (rn = route_top (rtrs); rn; rn = route_next (rn)) if (rn->info) { int flag = 0; vty_out (vty, "R %-15s ", inet_ntoa (rn->p.u.prefix4)); for (ALL_LIST_ELEMENTS_RO ((struct list *)rn->info, node, or)) { if (flag++) vty_out (vty, "%24s", ""); /* Show path. */ vty_out (vty, "%s [%d] area: %s", (or->path_type == OSPF_PATH_INTER_AREA ? "IA" : " "), or->cost, inet_ntoa (or->u.std.area_id)); /* Show flags. */ vty_out (vty, "%s%s%s", (or->u.std.flags & ROUTER_LSA_BORDER ? ", ABR" : ""), (or->u.std.flags & ROUTER_LSA_EXTERNAL ? ", ASBR" : ""), VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } } vty_out (vty, "%s", VTY_NEWLINE); } static void show_ip_ospf_route_external (struct vty *vty, struct route_table *rt) { struct route_node *rn; struct ospf_route *er; struct listnode *pnode, *pnnode; struct ospf_path *path; vty_out (vty, "============ OSPF external routing table ===========%s", VTY_NEWLINE); for (rn = route_top (rt); rn; rn = route_next (rn)) if ((er = rn->info) != NULL) { char buf1[19]; snprintf (buf1, 19, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); switch (er->path_type) { case OSPF_PATH_TYPE1_EXTERNAL: vty_out (vty, "N E1 %-18s [%d] tag: %u%s", buf1, er->cost, er->u.ext.tag, VTY_NEWLINE); break; case OSPF_PATH_TYPE2_EXTERNAL: vty_out (vty, "N E2 %-18s [%d/%d] tag: %u%s", buf1, er->cost, er->u.ext.type2_cost, er->u.ext.tag, VTY_NEWLINE); break; } for (ALL_LIST_ELEMENTS (er->paths, pnode, pnnode, path)) { if (if_lookup_by_index(path->ifindex)) { if (path->nexthop.s_addr == 0) vty_out (vty, "%24s directly attached to %s%s", "", ifindex2ifname (path->ifindex), VTY_NEWLINE); else vty_out (vty, "%24s via %s, %s%s", "", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex), VTY_NEWLINE); } } } vty_out (vty, "%s", VTY_NEWLINE); } DEFUN (show_ip_ospf_border_routers, show_ip_ospf_border_routers_cmd, "show ip ospf border-routers", SHOW_STR IP_STR "show all the ABR's and ASBR's\n" "for this area\n") { struct ospf *ospf; if ((ospf = ospf_lookup ()) == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } if (ospf->new_table == NULL) { vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Show Network routes. show_ip_ospf_route_network (vty, ospf->new_table); */ /* Show Router routes. */ show_ip_ospf_route_router (vty, ospf->new_rtrs); return CMD_SUCCESS; } DEFUN (show_ip_ospf_route, show_ip_ospf_route_cmd, "show ip ospf route", SHOW_STR IP_STR "OSPF information\n" "OSPF routing table\n") { struct ospf *ospf; if ((ospf = ospf_lookup ()) == NULL) { vty_out (vty, " OSPF Routing Process not enabled%s", VTY_NEWLINE); return CMD_SUCCESS; } if (ospf->new_table == NULL) { vty_out (vty, "No OSPF routing information exist%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Show Network routes. */ show_ip_ospf_route_network (vty, ospf->new_table); /* Show Router routes. */ show_ip_ospf_route_router (vty, ospf->new_rtrs); /* Show AS External routes. */ show_ip_ospf_route_external (vty, ospf->old_external_route); return CMD_SUCCESS; } const char *ospf_abr_type_str[] = { "unknown", "standard", "ibm", "cisco", "shortcut" }; const char *ospf_shortcut_mode_str[] = { "default", "enable", "disable" }; static void area_id2str (char *buf, int length, struct ospf_area *area) { memset (buf, 0, length); if (area->format == OSPF_AREA_ID_FORMAT_ADDRESS) strncpy (buf, inet_ntoa (area->area_id), length); else sprintf (buf, "%lu", (unsigned long) ntohl (area->area_id.s_addr)); } const char *ospf_int_type_str[] = { "unknown", /* should never be used. */ "point-to-point", "broadcast", "non-broadcast", "point-to-multipoint", "virtual-link", /* should never be used. */ "loopback" }; /* Configuration write function for ospfd. */ static int config_write_interface (struct vty *vty) { struct listnode *n1, *n2; struct interface *ifp; struct crypt_key *ck; int write = 0; struct route_node *rn = NULL; struct ospf_if_params *params; for (ALL_LIST_ELEMENTS_RO (iflist, n1, ifp)) { if (memcmp (ifp->name, "VLINK", 5) == 0) continue; vty_out (vty, "!%s", VTY_NEWLINE); vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); write++; params = IF_DEF_PARAMS (ifp); do { /* Interface Network print. */ if (OSPF_IF_PARAM_CONFIGURED (params, type) && params->type != OSPF_IFTYPE_LOOPBACK) { if (params->type != ospf_default_iftype(ifp)) { vty_out (vty, " ip ospf network %s", ospf_int_type_str[params->type]); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } } /* OSPF interface authentication print */ if (OSPF_IF_PARAM_CONFIGURED (params, auth_type) && params->auth_type != OSPF_AUTH_NOTSET) { const char *auth_str; /* Translation tables are not that much help here due to syntax of the simple option */ switch (params->auth_type) { case OSPF_AUTH_NULL: auth_str = " null"; break; case OSPF_AUTH_SIMPLE: auth_str = ""; break; case OSPF_AUTH_CRYPTOGRAPHIC: auth_str = " message-digest"; break; default: auth_str = ""; break; } vty_out (vty, " ip ospf authentication%s", auth_str); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Simple Authentication Password print. */ if (OSPF_IF_PARAM_CONFIGURED (params, auth_simple) && params->auth_simple[0] != '\0') { vty_out (vty, " ip ospf authentication-key %s", params->auth_simple); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Cryptographic Authentication Key print. */ for (ALL_LIST_ELEMENTS_RO (params->auth_crypt, n2, ck)) { vty_out (vty, " ip ospf message-digest-key %d md5 %s", ck->key_id, ck->auth_key); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Interface Output Cost print. */ if (OSPF_IF_PARAM_CONFIGURED (params, output_cost_cmd)) { vty_out (vty, " ip ospf cost %u", params->output_cost_cmd); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Hello Interval print. */ if (OSPF_IF_PARAM_CONFIGURED (params, v_hello) && params->v_hello != OSPF_HELLO_INTERVAL_DEFAULT) { vty_out (vty, " ip ospf hello-interval %u", params->v_hello); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Router Dead Interval print. */ if (OSPF_IF_PARAM_CONFIGURED (params, v_wait) && params->v_wait != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT) { vty_out (vty, " ip ospf dead-interval "); /* fast hello ? */ if (OSPF_IF_PARAM_CONFIGURED (params, fast_hello)) vty_out (vty, "minimal hello-multiplier %d", params->fast_hello); else vty_out (vty, "%u", params->v_wait); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Router Priority print. */ if (OSPF_IF_PARAM_CONFIGURED (params, priority) && params->priority != OSPF_ROUTER_PRIORITY_DEFAULT) { vty_out (vty, " ip ospf priority %u", params->priority); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Retransmit Interval print. */ if (OSPF_IF_PARAM_CONFIGURED (params, retransmit_interval) && params->retransmit_interval != OSPF_RETRANSMIT_INTERVAL_DEFAULT) { vty_out (vty, " ip ospf retransmit-interval %u", params->retransmit_interval); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED (params, transmit_delay) && params->transmit_delay != OSPF_TRANSMIT_DELAY_DEFAULT) { vty_out (vty, " ip ospf transmit-delay %u", params->transmit_delay); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } /* MTU ignore print. */ if (OSPF_IF_PARAM_CONFIGURED (params, mtu_ignore) && params->mtu_ignore != OSPF_MTU_IGNORE_DEFAULT) { if (params->mtu_ignore == 0) vty_out (vty, " no ip ospf mtu-ignore"); else vty_out (vty, " ip ospf mtu-ignore"); if (params != IF_DEF_PARAMS (ifp)) vty_out (vty, " %s", inet_ntoa (rn->p.u.prefix4)); vty_out (vty, "%s", VTY_NEWLINE); } while (1) { if (rn == NULL) rn = route_top (IF_OIFS_PARAMS (ifp)); else rn = route_next (rn); if (rn == NULL) break; params = rn->info; if (params != NULL) break; } } while (rn); #ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_if (vty, ifp); #endif /* HAVE_OPAQUE_LSA */ } return write; } static int config_write_network_area (struct vty *vty, struct ospf *ospf) { struct route_node *rn; u_char buf[INET_ADDRSTRLEN]; /* `network area' print. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) if (rn->info) { struct ospf_network *n = rn->info; memset (buf, 0, INET_ADDRSTRLEN); /* Create Area ID string by specified Area ID format. */ if (n->format == OSPF_AREA_ID_FORMAT_ADDRESS) strncpy ((char *) buf, inet_ntoa (n->area_id), INET_ADDRSTRLEN); else sprintf ((char *) buf, "%lu", (unsigned long int) ntohl (n->area_id.s_addr)); /* Network print. */ vty_out (vty, " network %s/%d area %s%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, buf, VTY_NEWLINE); } return 0; } static int config_write_ospf_area (struct vty *vty, struct ospf *ospf) { struct listnode *node; struct ospf_area *area; u_char buf[INET_ADDRSTRLEN]; /* Area configuration print. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { struct route_node *rn1; area_id2str ((char *) buf, INET_ADDRSTRLEN, area); if (area->auth_type != OSPF_AUTH_NULL) { if (area->auth_type == OSPF_AUTH_SIMPLE) vty_out (vty, " area %s authentication%s", buf, VTY_NEWLINE); else vty_out (vty, " area %s authentication message-digest%s", buf, VTY_NEWLINE); } if (area->shortcut_configured != OSPF_SHORTCUT_DEFAULT) vty_out (vty, " area %s shortcut %s%s", buf, ospf_shortcut_mode_str[area->shortcut_configured], VTY_NEWLINE); if ((area->external_routing == OSPF_AREA_STUB) || (area->external_routing == OSPF_AREA_NSSA) ) { if (area->external_routing == OSPF_AREA_STUB) vty_out (vty, " area %s stub", buf); else if (area->external_routing == OSPF_AREA_NSSA) { vty_out (vty, " area %s nssa", buf); switch (area->NSSATranslatorRole) { case OSPF_NSSA_ROLE_NEVER: vty_out (vty, " translate-never"); break; case OSPF_NSSA_ROLE_ALWAYS: vty_out (vty, " translate-always"); break; case OSPF_NSSA_ROLE_CANDIDATE: default: vty_out (vty, " translate-candidate"); } } if (area->no_summary) vty_out (vty, " no-summary"); vty_out (vty, "%s", VTY_NEWLINE); if (area->default_cost != 1) vty_out (vty, " area %s default-cost %d%s", buf, area->default_cost, VTY_NEWLINE); } for (rn1 = route_top (area->ranges); rn1; rn1 = route_next (rn1)) if (rn1->info) { struct ospf_area_range *range = rn1->info; vty_out (vty, " area %s range %s/%d", buf, inet_ntoa (rn1->p.u.prefix4), rn1->p.prefixlen); if (range->cost_config != OSPF_AREA_RANGE_COST_UNSPEC) vty_out (vty, " cost %d", range->cost_config); if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) vty_out (vty, " not-advertise"); if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) vty_out (vty, " substitute %s/%d", inet_ntoa (range->subst_addr), range->subst_masklen); vty_out (vty, "%s", VTY_NEWLINE); } if (EXPORT_NAME (area)) vty_out (vty, " area %s export-list %s%s", buf, EXPORT_NAME (area), VTY_NEWLINE); if (IMPORT_NAME (area)) vty_out (vty, " area %s import-list %s%s", buf, IMPORT_NAME (area), VTY_NEWLINE); if (PREFIX_NAME_IN (area)) vty_out (vty, " area %s filter-list prefix %s in%s", buf, PREFIX_NAME_IN (area), VTY_NEWLINE); if (PREFIX_NAME_OUT (area)) vty_out (vty, " area %s filter-list prefix %s out%s", buf, PREFIX_NAME_OUT (area), VTY_NEWLINE); } return 0; } static int config_write_ospf_nbr_nbma (struct vty *vty, struct ospf *ospf) { struct ospf_nbr_nbma *nbr_nbma; struct route_node *rn; /* Static Neighbor configuration print. */ for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) if ((nbr_nbma = rn->info)) { vty_out (vty, " neighbor %s", inet_ntoa (nbr_nbma->addr)); if (nbr_nbma->priority != OSPF_NEIGHBOR_PRIORITY_DEFAULT) vty_out (vty, " priority %d", nbr_nbma->priority); if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) vty_out (vty, " poll-interval %d", nbr_nbma->v_poll); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } static int config_write_virtual_link (struct vty *vty, struct ospf *ospf) { struct listnode *node; struct ospf_vl_data *vl_data; u_char buf[INET_ADDRSTRLEN]; /* Virtual-Link print */ for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { struct listnode *n2; struct crypt_key *ck; struct ospf_interface *oi; if (vl_data != NULL) { memset (buf, 0, INET_ADDRSTRLEN); if (vl_data->format == OSPF_AREA_ID_FORMAT_ADDRESS) strncpy ((char *) buf, inet_ntoa (vl_data->vl_area_id), INET_ADDRSTRLEN); else sprintf ((char *) buf, "%lu", (unsigned long int) ntohl (vl_data->vl_area_id.s_addr)); oi = vl_data->vl_oi; /* timers */ if (OSPF_IF_PARAM (oi, v_hello) != OSPF_HELLO_INTERVAL_DEFAULT || OSPF_IF_PARAM (oi, v_wait) != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || OSPF_IF_PARAM (oi, retransmit_interval) != OSPF_RETRANSMIT_INTERVAL_DEFAULT || OSPF_IF_PARAM (oi, transmit_delay) != OSPF_TRANSMIT_DELAY_DEFAULT) vty_out (vty, " area %s virtual-link %s hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d%s", buf, inet_ntoa (vl_data->vl_peer), OSPF_IF_PARAM (oi, v_hello), OSPF_IF_PARAM (oi, retransmit_interval), OSPF_IF_PARAM (oi, transmit_delay), OSPF_IF_PARAM (oi, v_wait), VTY_NEWLINE); else vty_out (vty, " area %s virtual-link %s%s", buf, inet_ntoa (vl_data->vl_peer), VTY_NEWLINE); /* Auth key */ if (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple[0] != '\0') vty_out (vty, " area %s virtual-link %s authentication-key %s%s", buf, inet_ntoa (vl_data->vl_peer), IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_simple, VTY_NEWLINE); /* md5 keys */ for (ALL_LIST_ELEMENTS_RO (IF_DEF_PARAMS (vl_data->vl_oi->ifp)->auth_crypt, n2, ck)) vty_out (vty, " area %s virtual-link %s" " message-digest-key %d md5 %s%s", buf, inet_ntoa (vl_data->vl_peer), ck->key_id, ck->auth_key, VTY_NEWLINE); } } return 0; } static int config_write_ospf_redistribute (struct vty *vty, struct ospf *ospf) { int type; /* redistribute print. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) if (type != zclient->redist_default && zclient->redist[type]) { vty_out (vty, " redistribute %s", zebra_route_string(type)); if (ospf->dmetric[type].value >= 0) vty_out (vty, " metric %d", ospf->dmetric[type].value); if (ospf->dmetric[type].type == EXTERNAL_METRIC_TYPE_1) vty_out (vty, " metric-type 1"); if (ROUTEMAP_NAME (ospf, type)) vty_out (vty, " route-map %s", ROUTEMAP_NAME (ospf, type)); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } static int config_write_ospf_default_metric (struct vty *vty, struct ospf *ospf) { if (ospf->default_metric != -1) vty_out (vty, " default-metric %d%s", ospf->default_metric, VTY_NEWLINE); return 0; } static int config_write_ospf_distribute (struct vty *vty, struct ospf *ospf) { int type; if (ospf) { /* distribute-list print. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) if (DISTRIBUTE_NAME (ospf, type)) vty_out (vty, " distribute-list %s out %s%s", DISTRIBUTE_NAME (ospf, type), zebra_route_string(type), VTY_NEWLINE); /* default-information print. */ if (ospf->default_originate != DEFAULT_ORIGINATE_NONE) { vty_out (vty, " default-information originate"); if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) vty_out (vty, " always"); if (ospf->dmetric[DEFAULT_ROUTE].value >= 0) vty_out (vty, " metric %d", ospf->dmetric[DEFAULT_ROUTE].value); if (ospf->dmetric[DEFAULT_ROUTE].type == EXTERNAL_METRIC_TYPE_1) vty_out (vty, " metric-type 1"); if (ROUTEMAP_NAME (ospf, DEFAULT_ROUTE)) vty_out (vty, " route-map %s", ROUTEMAP_NAME (ospf, DEFAULT_ROUTE)); vty_out (vty, "%s", VTY_NEWLINE); } } return 0; } static int config_write_ospf_distance (struct vty *vty, struct ospf *ospf) { struct route_node *rn; struct ospf_distance *odistance; if (ospf->distance_all) vty_out (vty, " distance %d%s", ospf->distance_all, VTY_NEWLINE); if (ospf->distance_intra || ospf->distance_inter || ospf->distance_external) { vty_out (vty, " distance ospf"); if (ospf->distance_intra) vty_out (vty, " intra-area %d", ospf->distance_intra); if (ospf->distance_inter) vty_out (vty, " inter-area %d", ospf->distance_inter); if (ospf->distance_external) vty_out (vty, " external %d", ospf->distance_external); vty_out (vty, "%s", VTY_NEWLINE); } for (rn = route_top (ospf->distance_table); rn; rn = route_next (rn)) if ((odistance = rn->info) != NULL) { vty_out (vty, " distance %d %s/%d %s%s", odistance->distance, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, odistance->access_list ? odistance->access_list : "", VTY_NEWLINE); } return 0; } /* OSPF configuration write function. */ static int ospf_config_write (struct vty *vty) { struct ospf *ospf; struct interface *ifp; struct ospf_interface *oi; struct listnode *node; int write = 0; ospf = ospf_lookup (); if (ospf != NULL) { /* `router ospf' print. */ vty_out (vty, "router ospf%s", VTY_NEWLINE); write++; if (!ospf->networks) return write; /* Router ID print. */ if (ospf->router_id_static.s_addr != 0) vty_out (vty, " ospf router-id %s%s", inet_ntoa (ospf->router_id_static), VTY_NEWLINE); /* ABR type print. */ if (ospf->abr_type != OSPF_ABR_DEFAULT) vty_out (vty, " ospf abr-type %s%s", ospf_abr_type_str[ospf->abr_type], VTY_NEWLINE); /* log-adjacency-changes flag print. */ if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES)) { vty_out(vty, " log-adjacency-changes"); if (CHECK_FLAG(ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) vty_out(vty, " detail"); vty_out(vty, "%s", VTY_NEWLINE); } /* RFC1583 compatibility flag print -- Compatible with CISCO 12.1. */ if (CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) vty_out (vty, " compatible rfc1583%s", VTY_NEWLINE); /* auto-cost reference-bandwidth configuration. */ if (ospf->ref_bandwidth != OSPF_DEFAULT_REF_BANDWIDTH) { vty_out (vty, "! Important: ensure reference bandwidth " "is consistent across all routers%s", VTY_NEWLINE); vty_out (vty, " auto-cost reference-bandwidth %d%s", ospf->ref_bandwidth / 1000, VTY_NEWLINE); } /* SPF timers print. */ if (ospf->spf_delay != OSPF_SPF_DELAY_DEFAULT || ospf->spf_holdtime != OSPF_SPF_HOLDTIME_DEFAULT || ospf->spf_max_holdtime != OSPF_SPF_MAX_HOLDTIME_DEFAULT) vty_out (vty, " timers throttle spf %d %d %d%s", ospf->spf_delay, ospf->spf_holdtime, ospf->spf_max_holdtime, VTY_NEWLINE); /* Max-metric router-lsa print */ config_write_stub_router (vty, ospf); /* SPF refresh parameters print. */ if (ospf->lsa_refresh_interval != OSPF_LSA_REFRESH_INTERVAL_DEFAULT) vty_out (vty, " refresh timer %d%s", ospf->lsa_refresh_interval, VTY_NEWLINE); /* Redistribute information print. */ config_write_ospf_redistribute (vty, ospf); /* passive-interface print. */ if (ospf->passive_interface_default == OSPF_IF_PASSIVE) vty_out (vty, " passive-interface default%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), passive_interface) && IF_DEF_PARAMS (ifp)->passive_interface != ospf->passive_interface_default) { vty_out (vty, " %spassive-interface %s%s", IF_DEF_PARAMS (ifp)->passive_interface ? "" : "no ", ifp->name, VTY_NEWLINE); } for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { if (!OSPF_IF_PARAM_CONFIGURED (oi->params, passive_interface)) continue; if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), passive_interface)) { if (oi->params->passive_interface == IF_DEF_PARAMS (oi->ifp)->passive_interface) continue; } else if (oi->params->passive_interface == ospf->passive_interface_default) continue; vty_out (vty, " %spassive-interface %s %s%s", oi->params->passive_interface ? "" : "no ", oi->ifp->name, inet_ntoa (oi->address->u.prefix4), VTY_NEWLINE); } /* Network area print. */ config_write_network_area (vty, ospf); /* Area config print. */ config_write_ospf_area (vty, ospf); /* static neighbor print. */ config_write_ospf_nbr_nbma (vty, ospf); /* Virtual-Link print. */ config_write_virtual_link (vty, ospf); /* Default metric configuration. */ config_write_ospf_default_metric (vty, ospf); /* Distribute-list and default-information print. */ config_write_ospf_distribute (vty, ospf); /* Distance configuration. */ config_write_ospf_distance (vty, ospf); #ifdef HAVE_OPAQUE_LSA ospf_opaque_config_write_router (vty, ospf); #endif /* HAVE_OPAQUE_LSA */ } return write; } void ospf_vty_show_init (void) { /* "show ip ospf" commands. */ install_element (VIEW_NODE, &show_ip_ospf_cmd); install_element (ENABLE_NODE, &show_ip_ospf_cmd); /* "show ip ospf database" commands. */ install_element (VIEW_NODE, &show_ip_ospf_database_type_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_adv_router_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_id_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_type_self_cmd); install_element (VIEW_NODE, &show_ip_ospf_database_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_adv_router_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_adv_router_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_id_self_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_type_self_cmd); install_element (ENABLE_NODE, &show_ip_ospf_database_cmd); /* "show ip ospf interface" commands. */ install_element (VIEW_NODE, &show_ip_ospf_interface_cmd); install_element (ENABLE_NODE, &show_ip_ospf_interface_cmd); /* "show ip ospf neighbor" commands. */ install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_detail_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_int_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_id_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_all_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_detail_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_cmd); install_element (VIEW_NODE, &show_ip_ospf_neighbor_all_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_detail_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_int_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_id_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_all_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_detail_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_cmd); install_element (ENABLE_NODE, &show_ip_ospf_neighbor_all_cmd); /* "show ip ospf route" commands. */ install_element (VIEW_NODE, &show_ip_ospf_route_cmd); install_element (ENABLE_NODE, &show_ip_ospf_route_cmd); install_element (VIEW_NODE, &show_ip_ospf_border_routers_cmd); install_element (ENABLE_NODE, &show_ip_ospf_border_routers_cmd); } /* ospfd's interface node. */ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 }; /* Initialization of OSPF interface. */ static void ospf_vty_if_init (void) { /* Install interface node. */ install_node (&interface_node, config_write_interface); install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); /* "description" commands. */ install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); /* "ip ospf authentication" commands. */ install_element (INTERFACE_NODE, &ip_ospf_authentication_args_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_authentication_args_cmd); install_element (INTERFACE_NODE, &ip_ospf_authentication_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_authentication_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_cmd); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_authentication_key_cmd); /* "ip ospf message-digest-key" commands. */ install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_message_digest_key_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_message_digest_key_cmd); /* "ip ospf cost" commands. */ install_element (INTERFACE_NODE, &ip_ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &ip_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_inet4_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_cost_cmd); /* "ip ospf mtu-ignore" commands. */ install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_mtu_ignore_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_mtu_ignore_cmd); /* "ip ospf dead-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_dead_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_cmd); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_dead_interval_minimal_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_dead_interval_cmd); /* "ip ospf hello-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_hello_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_hello_interval_cmd); /* "ip ospf network" commands. */ install_element (INTERFACE_NODE, &ip_ospf_network_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_network_cmd); /* "ip ospf priority" commands. */ install_element (INTERFACE_NODE, &ip_ospf_priority_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_priority_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_priority_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_priority_cmd); /* "ip ospf retransmit-interval" commands. */ install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_retransmit_interval_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_retransmit_interval_cmd); /* "ip ospf transmit-delay" commands. */ install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &ip_ospf_transmit_delay_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); install_element (INTERFACE_NODE, &no_ip_ospf_transmit_delay_cmd); /* These commands are compatibitliy for previous version. */ install_element (INTERFACE_NODE, &ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &no_ospf_authentication_key_cmd); install_element (INTERFACE_NODE, &ospf_message_digest_key_cmd); install_element (INTERFACE_NODE, &no_ospf_message_digest_key_cmd); install_element (INTERFACE_NODE, &ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_u32_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_u32_inet4_cmd); install_element (INTERFACE_NODE, &no_ospf_cost_inet4_cmd); install_element (INTERFACE_NODE, &ospf_dead_interval_cmd); install_element (INTERFACE_NODE, &no_ospf_dead_interval_cmd); install_element (INTERFACE_NODE, &ospf_hello_interval_cmd); install_element (INTERFACE_NODE, &no_ospf_hello_interval_cmd); install_element (INTERFACE_NODE, &ospf_network_cmd); install_element (INTERFACE_NODE, &no_ospf_network_cmd); install_element (INTERFACE_NODE, &ospf_priority_cmd); install_element (INTERFACE_NODE, &no_ospf_priority_cmd); install_element (INTERFACE_NODE, &ospf_retransmit_interval_cmd); install_element (INTERFACE_NODE, &no_ospf_retransmit_interval_cmd); install_element (INTERFACE_NODE, &ospf_transmit_delay_cmd); install_element (INTERFACE_NODE, &no_ospf_transmit_delay_cmd); } static void ospf_vty_zebra_init (void) { install_element (OSPF_NODE, &ospf_redistribute_source_cmd); install_element (OSPF_NODE, &no_ospf_redistribute_source_cmd); install_element (OSPF_NODE, &ospf_distribute_list_out_cmd); install_element (OSPF_NODE, &no_ospf_distribute_list_out_cmd); install_element (OSPF_NODE, &ospf_default_information_originate_cmd); install_element (OSPF_NODE, &no_ospf_default_information_originate_cmd); install_element (OSPF_NODE, &ospf_default_metric_cmd); install_element (OSPF_NODE, &no_ospf_default_metric_cmd); install_element (OSPF_NODE, &no_ospf_default_metric_val_cmd); install_element (OSPF_NODE, &ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_cmd); install_element (OSPF_NODE, &no_ospf_distance_ospf_cmd); install_element (OSPF_NODE, &ospf_distance_ospf_cmd); #if 0 install_element (OSPF_NODE, &ospf_distance_source_cmd); install_element (OSPF_NODE, &no_ospf_distance_source_cmd); install_element (OSPF_NODE, &ospf_distance_source_access_list_cmd); install_element (OSPF_NODE, &no_ospf_distance_source_access_list_cmd); #endif /* 0 */ } static struct cmd_node ospf_node = { OSPF_NODE, "%s(config-router)# ", 1 }; /* Install OSPF related vty commands. */ void ospf_vty_init (void) { /* Install ospf top node. */ install_node (&ospf_node, ospf_config_write); /* "router ospf" commands. */ install_element (CONFIG_NODE, &router_ospf_cmd); install_element (CONFIG_NODE, &no_router_ospf_cmd); install_default (OSPF_NODE); /* "ospf router-id" commands. */ install_element (OSPF_NODE, &ospf_router_id_cmd); install_element (OSPF_NODE, &no_ospf_router_id_cmd); install_element (OSPF_NODE, &router_ospf_id_cmd); install_element (OSPF_NODE, &no_router_ospf_id_cmd); /* "passive-interface" commands. */ install_element (OSPF_NODE, &ospf_passive_interface_addr_cmd); install_element (OSPF_NODE, &ospf_passive_interface_cmd); install_element (OSPF_NODE, &ospf_passive_interface_default_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_addr_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_cmd); install_element (OSPF_NODE, &no_ospf_passive_interface_default_cmd); /* "ospf abr-type" commands. */ install_element (OSPF_NODE, &ospf_abr_type_cmd); install_element (OSPF_NODE, &no_ospf_abr_type_cmd); /* "ospf log-adjacency-changes" commands. */ install_element (OSPF_NODE, &ospf_log_adjacency_changes_cmd); install_element (OSPF_NODE, &ospf_log_adjacency_changes_detail_cmd); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_cmd); install_element (OSPF_NODE, &no_ospf_log_adjacency_changes_detail_cmd); /* "ospf rfc1583-compatible" commands. */ install_element (OSPF_NODE, &ospf_rfc1583_flag_cmd); install_element (OSPF_NODE, &no_ospf_rfc1583_flag_cmd); install_element (OSPF_NODE, &ospf_compatible_rfc1583_cmd); install_element (OSPF_NODE, &no_ospf_compatible_rfc1583_cmd); /* "network area" commands. */ install_element (OSPF_NODE, &ospf_network_area_cmd); install_element (OSPF_NODE, &no_ospf_network_area_cmd); /* "area authentication" commands. */ install_element (OSPF_NODE, &ospf_area_authentication_message_digest_cmd); install_element (OSPF_NODE, &ospf_area_authentication_cmd); install_element (OSPF_NODE, &no_ospf_area_authentication_cmd); /* "area range" commands. */ install_element (OSPF_NODE, &ospf_area_range_cmd); install_element (OSPF_NODE, &ospf_area_range_advertise_cmd); install_element (OSPF_NODE, &ospf_area_range_cost_cmd); install_element (OSPF_NODE, &ospf_area_range_advertise_cost_cmd); install_element (OSPF_NODE, &ospf_area_range_not_advertise_cmd); install_element (OSPF_NODE, &no_ospf_area_range_cmd); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cmd); install_element (OSPF_NODE, &no_ospf_area_range_cost_cmd); install_element (OSPF_NODE, &no_ospf_area_range_advertise_cost_cmd); install_element (OSPF_NODE, &ospf_area_range_substitute_cmd); install_element (OSPF_NODE, &no_ospf_area_range_substitute_cmd); /* "area virtual-link" commands. */ install_element (OSPF_NODE, &ospf_area_vlink_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_cmd); install_element (OSPF_NODE, &ospf_area_vlink_param1_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_param1_cmd); install_element (OSPF_NODE, &ospf_area_vlink_param2_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_param2_cmd); install_element (OSPF_NODE, &ospf_area_vlink_param3_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_param3_cmd); install_element (OSPF_NODE, &ospf_area_vlink_param4_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_param4_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_cmd); install_element (OSPF_NODE, &ospf_area_vlink_md5_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_md5_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authkey_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_authkey_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_authkey_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_authkey_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_authkey_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_args_md5_cmd); install_element (OSPF_NODE, &ospf_area_vlink_authtype_md5_cmd); install_element (OSPF_NODE, &no_ospf_area_vlink_authtype_md5_cmd); /* "area stub" commands. */ install_element (OSPF_NODE, &ospf_area_stub_no_summary_cmd); install_element (OSPF_NODE, &ospf_area_stub_cmd); install_element (OSPF_NODE, &no_ospf_area_stub_no_summary_cmd); install_element (OSPF_NODE, &no_ospf_area_stub_cmd); /* "area nssa" commands. */ install_element (OSPF_NODE, &ospf_area_nssa_cmd); install_element (OSPF_NODE, &ospf_area_nssa_translate_no_summary_cmd); install_element (OSPF_NODE, &ospf_area_nssa_translate_cmd); install_element (OSPF_NODE, &ospf_area_nssa_no_summary_cmd); install_element (OSPF_NODE, &no_ospf_area_nssa_cmd); install_element (OSPF_NODE, &no_ospf_area_nssa_no_summary_cmd); install_element (OSPF_NODE, &ospf_area_default_cost_cmd); install_element (OSPF_NODE, &no_ospf_area_default_cost_cmd); install_element (OSPF_NODE, &ospf_area_shortcut_cmd); install_element (OSPF_NODE, &no_ospf_area_shortcut_cmd); install_element (OSPF_NODE, &ospf_area_export_list_cmd); install_element (OSPF_NODE, &no_ospf_area_export_list_cmd); install_element (OSPF_NODE, &ospf_area_filter_list_cmd); install_element (OSPF_NODE, &no_ospf_area_filter_list_cmd); install_element (OSPF_NODE, &ospf_area_import_list_cmd); install_element (OSPF_NODE, &no_ospf_area_import_list_cmd); /* SPF timer commands */ install_element (OSPF_NODE, &ospf_timers_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_spf_cmd); install_element (OSPF_NODE, &ospf_timers_throttle_spf_cmd); install_element (OSPF_NODE, &no_ospf_timers_throttle_spf_cmd); /* refresh timer commands */ install_element (OSPF_NODE, &ospf_refresh_timer_cmd); install_element (OSPF_NODE, &no_ospf_refresh_timer_val_cmd); install_element (OSPF_NODE, &no_ospf_refresh_timer_cmd); /* max-metric commands */ install_element (OSPF_NODE, &ospf_max_metric_router_lsa_admin_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_admin_cmd); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_startup_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_startup_cmd); install_element (OSPF_NODE, &ospf_max_metric_router_lsa_shutdown_cmd); install_element (OSPF_NODE, &no_ospf_max_metric_router_lsa_shutdown_cmd); /* reference bandwidth commands */ install_element (OSPF_NODE, &ospf_auto_cost_reference_bandwidth_cmd); install_element (OSPF_NODE, &no_ospf_auto_cost_reference_bandwidth_cmd); /* "neighbor" commands. */ install_element (OSPF_NODE, &ospf_neighbor_cmd); install_element (OSPF_NODE, &ospf_neighbor_priority_poll_interval_cmd); install_element (OSPF_NODE, &ospf_neighbor_priority_cmd); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_cmd); install_element (OSPF_NODE, &ospf_neighbor_poll_interval_priority_cmd); install_element (OSPF_NODE, &no_ospf_neighbor_cmd); install_element (OSPF_NODE, &no_ospf_neighbor_priority_cmd); install_element (OSPF_NODE, &no_ospf_neighbor_poll_interval_cmd); /* Init interface related vty commands. */ ospf_vty_if_init (); /* Init zebra related vty commands. */ ospf_vty_zebra_init (); } quagga-0.99.24.1/ospfd/ospf_te.c0000644000175000017500000014724612476520570013170 00000000000000/* * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /***** MTYPE definition is not reflected to "memory.h" yet. *****/ #define MTYPE_OSPF_MPLS_TE_LINKPARAMS 0 #include #ifdef HAVE_OSPF_TE #ifndef HAVE_OPAQUE_LSA #error "Wrong configure option" #endif /* HAVE_OPAQUE_LSA */ #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_te.h" /* Following structure are internal use only. */ struct ospf_mpls_te { enum { disabled, enabled } status; /* List elements are zebra-interfaces (ifp), not ospf-interfaces (oi). */ struct list *iflist; /* Store Router-TLV in network byte order. */ struct te_tlv_router_addr router_addr; }; struct mpls_te_link { /* * According to MPLS-TE (draft) specification, 24-bit Opaque-ID field * is subdivided into 8-bit "unused" field and 16-bit "instance" field. * In this implementation, each Link-TLV has its own instance. */ u_int32_t instance; /* Reference pointer to a Zebra-interface. */ struct interface *ifp; /* Area info in which this MPLS-TE link belongs to. */ struct ospf_area *area; /* Flags to manage this link parameters. */ u_int32_t flags; #define LPFLG_LOOKUP_DONE 0x1 #define LPFLG_LSA_ENGAGED 0x2 #define LPFLG_LSA_FORCED_REFRESH 0x4 /* Store Link-TLV in network byte order. */ struct te_tlv_link link_header; struct te_link_subtlv_link_type link_type; struct te_link_subtlv_link_id link_id; struct te_link_subtlv_lclif_ipaddr *lclif_ipaddr; struct te_link_subtlv_rmtif_ipaddr *rmtif_ipaddr; struct te_link_subtlv_te_metric te_metric; struct te_link_subtlv_max_bw max_bw; struct te_link_subtlv_max_rsv_bw max_rsv_bw; struct te_link_subtlv_unrsv_bw unrsv_bw; struct te_link_subtlv_rsc_clsclr rsc_clsclr; }; /* * Global variable to manage Opaque-LSA/MPLS-TE on this node. * Note that all parameter values are stored in network byte order. */ static struct ospf_mpls_te OspfMplsTE; enum oifstate { OI_ANY, OI_DOWN, OI_UP }; enum sched_opcode { REORIGINATE_PER_AREA, REFRESH_THIS_LSA, FLUSH_THIS_LSA }; /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for MPLS-TE handling. *------------------------------------------------------------------------*/ static int ospf_mpls_te_new_if (struct interface *ifp); static int ospf_mpls_te_del_if (struct interface *ifp); static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_status); static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router (struct vty *vty); static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp); static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate (void *arg); static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa); static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode); static void del_mpls_te_link (void *val); static void ospf_mpls_te_register_vty (void); int ospf_mpls_te_init (void) { int rc; rc = ospf_register_opaque_functab ( OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, ospf_mpls_te_new_if, ospf_mpls_te_del_if, ospf_mpls_te_ism_change, ospf_mpls_te_nsm_change, ospf_mpls_te_config_write_router, ospf_mpls_te_config_write_if, NULL,/* ospf_mpls_te_config_write_debug */ ospf_mpls_te_show_info, ospf_mpls_te_lsa_originate, ospf_mpls_te_lsa_refresh, NULL,/* ospf_mpls_te_new_lsa_hook */ NULL /* ospf_mpls_te_del_lsa_hook */); if (rc != 0) { zlog_warn ("ospf_mpls_te_init: Failed to register functions"); goto out; } memset (&OspfMplsTE, 0, sizeof (struct ospf_mpls_te)); OspfMplsTE.status = disabled; OspfMplsTE.iflist = list_new (); OspfMplsTE.iflist->del = del_mpls_te_link; ospf_mpls_te_register_vty (); out: return rc; } void ospf_mpls_te_term (void) { list_delete (OspfMplsTE.iflist); OspfMplsTE.iflist = NULL; OspfMplsTE.status = disabled; ospf_delete_opaque_functab (OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); return; } /*------------------------------------------------------------------------* * Followings are control functions for MPLS-TE parameters management. *------------------------------------------------------------------------*/ static void del_mpls_te_link (void *val) { XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, val); return; } static u_int32_t get_mpls_te_instance_value (void) { static u_int32_t seqno = 0; if (seqno < MAX_LEGAL_TE_INSTANCE_NUM ) seqno += 1; else seqno = 1; /* Avoid zero. */ return seqno; } static struct ospf_interface * lookup_oi_by_ifp (struct interface *ifp, struct ospf_area *area, enum oifstate oifstate) { struct ospf_interface *oi = NULL; struct route_node *rn; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { if ((oi = rn->info) == NULL) continue; switch (oifstate) { case OI_ANY: break; case OI_DOWN: if (ospf_if_is_enable (oi)) continue; break; case OI_UP: if (! ospf_if_is_enable (oi)) continue; break; default: zlog_warn ("lookup_oi_by_ifp: Unknown oifstate: %x", oifstate); goto out; } if (area == NULL || oi->area == area) return oi; } out: return NULL; } static struct mpls_te_link * lookup_linkparams_by_ifp (struct interface *ifp) { struct listnode *node, *nnode; struct mpls_te_link *lp; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) if (lp->ifp == ifp) return lp; return NULL; } static struct mpls_te_link * lookup_linkparams_by_instance (struct ospf_lsa *lsa) { struct listnode *node; struct mpls_te_link *lp; unsigned int key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->instance == key) return lp; zlog_warn ("lookup_linkparams_by_instance: Entry not found: key(%x)", key); return NULL; } static void ospf_mpls_te_foreach_area ( void (*func)(struct mpls_te_link *lp, enum sched_opcode), enum sched_opcode sched_opcode) { struct listnode *node, *nnode; struct listnode *node2; struct mpls_te_link *lp; struct ospf_area *area; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if ((area = lp->area) == NULL) continue; if (lp->flags & LPFLG_LOOKUP_DONE) continue; if (func != NULL) (* func)(lp, sched_opcode); for (node2 = listnextnode (node); node2; node2 = listnextnode (node2)) if ((lp = listgetdata (node2)) != NULL) if (lp->area != NULL) if (IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) lp->flags |= LPFLG_LOOKUP_DONE; } for (ALL_LIST_ELEMENTS_RO (OspfMplsTE.iflist, node, lp)) if (lp->area != NULL) lp->flags &= ~LPFLG_LOOKUP_DONE; return; } static void set_mpls_te_router_addr (struct in_addr ipv4) { OspfMplsTE.router_addr.header.type = htons (TE_TLV_ROUTER_ADDR); OspfMplsTE.router_addr.header.length = htons (sizeof (ipv4)); OspfMplsTE.router_addr.value = ipv4; return; } static void set_linkparams_link_header (struct mpls_te_link *lp) { struct te_tlv_header *tlvh; u_int16_t length = 0; /* TE_LINK_SUBTLV_LINK_TYPE */ if (ntohs (lp->link_type.header.type) != 0) length += TLV_SIZE (&lp->link_type.header); /* TE_LINK_SUBTLV_LINK_ID */ if (ntohs (lp->link_id.header.type) != 0) length += TLV_SIZE (&lp->link_id.header); /* TE_LINK_SUBTLV_LCLIF_IPADDR */ if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL && ntohs (tlvh->type) != 0) length += TLV_SIZE (tlvh); /* TE_LINK_SUBTLV_RMTIF_IPADDR */ if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL && ntohs (tlvh->type) != 0) length += TLV_SIZE (tlvh); /* TE_LINK_SUBTLV_TE_METRIC */ if (ntohs (lp->te_metric.header.type) != 0) length += TLV_SIZE (&lp->te_metric.header); /* TE_LINK_SUBTLV_MAX_BW */ if (ntohs (lp->max_bw.header.type) != 0) length += TLV_SIZE (&lp->max_bw.header); /* TE_LINK_SUBTLV_MAX_RSV_BW */ if (ntohs (lp->max_rsv_bw.header.type) != 0) length += TLV_SIZE (&lp->max_rsv_bw.header); /* TE_LINK_SUBTLV_UNRSV_BW */ if (ntohs (lp->unrsv_bw.header.type) != 0) length += TLV_SIZE (&lp->unrsv_bw.header); /* TE_LINK_SUBTLV_RSC_CLSCLR */ if (ntohs (lp->rsc_clsclr.header.type) != 0) length += TLV_SIZE (&lp->rsc_clsclr.header); lp->link_header.header.type = htons (TE_TLV_LINK); lp->link_header.header.length = htons (length); return; } static void set_linkparams_link_type (struct ospf_interface *oi, struct mpls_te_link *lp) { lp->link_type.header.type = htons (TE_LINK_SUBTLV_LINK_TYPE); lp->link_type.header.length = htons (sizeof (lp->link_type.link_type.value)); switch (oi->type) { case OSPF_IFTYPE_POINTOPOINT: lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_PTP; break; case OSPF_IFTYPE_BROADCAST: case OSPF_IFTYPE_NBMA: lp->link_type.link_type.value = LINK_TYPE_SUBTLV_VALUE_MA; break; default: /* Not supported yet. *//* XXX */ lp->link_type.header.type = htons (0); break; } return; } static void set_linkparams_link_id (struct ospf_interface *oi, struct mpls_te_link *lp) { struct ospf_neighbor *nbr; int done = 0; lp->link_id.header.type = htons (TE_LINK_SUBTLV_LINK_ID); lp->link_id.header.length = htons (sizeof (lp->link_id.value)); /* * The Link ID is identical to the contents of the Link ID field * in the Router LSA for these link types. */ switch (oi->type) { case OSPF_IFTYPE_POINTOPOINT: /* Take the router ID of the neighbor. */ if ((nbr = ospf_nbr_lookup_ptop (oi)) && nbr->state == NSM_Full) { lp->link_id.value = nbr->router_id; done = 1; } break; case OSPF_IFTYPE_BROADCAST: case OSPF_IFTYPE_NBMA: /* Take the interface address of the designated router. */ if ((nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi))) == NULL) break; if (nbr->state == NSM_Full || (IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) && ospf_nbr_count (oi, NSM_Full) > 0)) { lp->link_id.value = DR (oi); done = 1; } break; default: /* Not supported yet. *//* XXX */ lp->link_id.header.type = htons (0); break; } if (! done) { struct in_addr mask; masklen2ip (oi->address->prefixlen, &mask); lp->link_id.value.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; } return; } static void set_linkparams_te_metric (struct mpls_te_link *lp, u_int32_t te_metric) { lp->te_metric.header.type = htons (TE_LINK_SUBTLV_TE_METRIC); lp->te_metric.header.length = htons (sizeof (lp->te_metric.value)); lp->te_metric.value = htonl (te_metric); return; } static void set_linkparams_max_bw (struct mpls_te_link *lp, float *fp) { lp->max_bw.header.type = htons (TE_LINK_SUBTLV_MAX_BW); lp->max_bw.header.length = htons (sizeof (lp->max_bw.value)); htonf (fp, &lp->max_bw.value); return; } static void set_linkparams_max_rsv_bw (struct mpls_te_link *lp, float *fp) { lp->max_rsv_bw.header.type = htons (TE_LINK_SUBTLV_MAX_RSV_BW); lp->max_rsv_bw.header.length = htons (sizeof (lp->max_rsv_bw.value)); htonf (fp, &lp->max_rsv_bw.value); return; } static void set_linkparams_unrsv_bw (struct mpls_te_link *lp, int priority, float *fp) { /* Note that TLV-length field is the size of array. */ lp->unrsv_bw.header.type = htons (TE_LINK_SUBTLV_UNRSV_BW); lp->unrsv_bw.header.length = htons (sizeof (lp->unrsv_bw.value)); htonf (fp, &lp->unrsv_bw.value [priority]); return; } static void set_linkparams_rsc_clsclr (struct mpls_te_link *lp, u_int32_t classcolor) { lp->rsc_clsclr.header.type = htons (TE_LINK_SUBTLV_RSC_CLSCLR); lp->rsc_clsclr.header.length = htons (sizeof (lp->rsc_clsclr.value)); lp->rsc_clsclr.value = htonl (classcolor); return; } static void initialize_linkparams (struct mpls_te_link *lp) { struct interface *ifp = lp->ifp; struct ospf_interface *oi; float fval; int i; if ((oi = lookup_oi_by_ifp (ifp, NULL, OI_ANY)) == NULL) return; /* * Try to set initial values those can be derived from * zebra-interface information. */ set_linkparams_link_type (oi, lp); /* * Linux and *BSD kernel holds bandwidth parameter as an "int" type. * We may have to reconsider, if "ifp->bandwidth" type changes to float. */ fval = (float)((ifp->bandwidth ? ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH) * 1000 / 8); set_linkparams_max_bw (lp, &fval); set_linkparams_max_rsv_bw (lp, &fval); for (i = 0; i < 8; i++) set_linkparams_unrsv_bw (lp, i, &fval); return; } static int is_mandated_params_set (struct mpls_te_link *lp) { int rc = 0; if (ntohs (OspfMplsTE.router_addr.header.type) == 0) goto out; if (ntohs (lp->link_type.header.type) == 0) goto out; if (ntohs (lp->link_id.header.type) == 0) goto out; rc = 1; out: return rc; } /*------------------------------------------------------------------------* * Followings are callback functions against generic Opaque-LSAs handling. *------------------------------------------------------------------------*/ static int ospf_mpls_te_new_if (struct interface *ifp) { struct mpls_te_link *new; int rc = -1; if (lookup_linkparams_by_ifp (ifp) != NULL) { zlog_warn ("ospf_mpls_te_new_if: ifp(%p) already in use?", ifp); rc = 0; /* Do nothing here. */ goto out; } new = XCALLOC (MTYPE_OSPF_MPLS_TE_LINKPARAMS, sizeof (struct mpls_te_link)); if (new == NULL) { zlog_warn ("ospf_mpls_te_new_if: XMALLOC: %s", safe_strerror (errno)); goto out; } new->area = NULL; new->flags = 0; new->instance = get_mpls_te_instance_value (); new->ifp = ifp; initialize_linkparams (new); listnode_add (OspfMplsTE.iflist, new); /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; out: return rc; } static int ospf_mpls_te_del_if (struct interface *ifp) { struct mpls_te_link *lp; int rc = -1; if ((lp = lookup_linkparams_by_ifp (ifp)) != NULL) { struct list *iflist = OspfMplsTE.iflist; /* Dequeue listnode entry from the list. */ listnode_delete (iflist, lp); /* Avoid misjudgement in the next lookup. */ if (listcount (iflist) == 0) iflist->head = iflist->tail = NULL; XFREE (MTYPE_OSPF_MPLS_TE_LINKPARAMS, lp); } /* Schedule Opaque-LSA refresh. *//* XXX */ rc = 0; /*out:*/ return rc; } static void ospf_mpls_te_ism_change (struct ospf_interface *oi, int old_state) { struct te_link_subtlv_link_type old_type; struct te_link_subtlv_link_id old_id; struct mpls_te_link *lp; if ((lp = lookup_linkparams_by_ifp (oi->ifp)) == NULL) { zlog_warn ("ospf_mpls_te_ism_change: Cannot get linkparams from OI(%s)?", IF_NAME (oi)); goto out; } if (oi->area == NULL || oi->area->ospf == NULL) { zlog_warn ("ospf_mpls_te_ism_change: Cannot refer to OSPF from OI(%s)?", IF_NAME (oi)); goto out; } #ifdef notyet if ((lp->area != NULL && ! IPV4_ADDR_SAME (&lp->area->area_id, &oi->area->area_id)) || (lp->area != NULL && oi->area == NULL)) { /* How should we consider this case? */ zlog_warn ("MPLS-TE: Area for OI(%s) has changed to [%s], flush previous LSAs", IF_NAME (oi), oi->area ? inet_ntoa (oi->area->area_id) : "N/A"); ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); } #endif /* Keep Area information in conbination with linkparams. */ lp->area = oi->area; switch (oi->state) { case ISM_PointToPoint: case ISM_DROther: case ISM_Backup: case ISM_DR: old_type = lp->link_type; old_id = lp->link_id; set_linkparams_link_type (oi, lp); set_linkparams_link_id (oi, lp); if ((ntohs (old_type.header.type) != ntohs (lp->link_type.header.type) || old_type.link_type.value != lp->link_type.link_type.value) || (ntohs (old_id.header.type) != ntohs (lp->link_id.header.type) || ntohl (old_id.value.s_addr) != ntohl (lp->link_id.value.s_addr))) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } break; default: lp->link_type.header.type = htons (0); lp->link_id.header.type = htons (0); if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); break; } out: return; } static void ospf_mpls_te_nsm_change (struct ospf_neighbor *nbr, int old_state) { /* So far, nothing to do here. */ return; } /*------------------------------------------------------------------------* * Followings are OSPF protocol processing functions for MPLS-TE. *------------------------------------------------------------------------*/ static void build_tlv_header (struct stream *s, struct te_tlv_header *tlvh) { stream_put (s, tlvh, sizeof (struct te_tlv_header)); return; } static void build_router_tlv (struct stream *s) { struct te_tlv_header *tlvh = &OspfMplsTE.router_addr.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_link_type (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->link_type.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_link_id (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->link_id.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_lclif_ipaddr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->lclif_ipaddr; if (tlvh != NULL && ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_rmtif_ipaddr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr; if (tlvh != NULL && ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_te_metric (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->te_metric.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_max_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->max_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_max_rsv_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->max_rsv_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_unrsv_bw (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->unrsv_bw.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_subtlv_rsc_clsclr (struct stream *s, struct mpls_te_link *lp) { struct te_tlv_header *tlvh = &lp->rsc_clsclr.header; if (ntohs (tlvh->type) != 0) { build_tlv_header (s, tlvh); stream_put (s, tlvh+1, TLV_BODY_SIZE (tlvh)); } return; } static void build_link_tlv (struct stream *s, struct mpls_te_link *lp) { set_linkparams_link_header (lp); build_tlv_header (s, &lp->link_header.header); build_link_subtlv_link_type (s, lp); build_link_subtlv_link_id (s, lp); build_link_subtlv_lclif_ipaddr (s, lp); build_link_subtlv_rmtif_ipaddr (s, lp); build_link_subtlv_te_metric (s, lp); build_link_subtlv_max_bw (s, lp); build_link_subtlv_max_rsv_bw (s, lp); build_link_subtlv_unrsv_bw (s, lp); build_link_subtlv_rsc_clsclr (s, lp); return; } static void ospf_mpls_te_lsa_body_set (struct stream *s, struct mpls_te_link *lp) { /* * The router address TLV is type 1, and ... * It must appear in exactly one * Traffic Engineering LSA originated by a router. */ build_router_tlv (s); /* * Only one Link TLV shall be carried in each LSA, allowing for fine * granularity changes in topology. */ build_link_tlv (s, lp); return; } /* Create new opaque-LSA. */ static struct ospf_lsa * ospf_mpls_te_lsa_new (struct ospf_area *area, struct mpls_te_link *lp) { struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new = NULL; u_char options, lsa_type; struct in_addr lsa_id; u_int32_t tmp; u_int16_t length; /* Create a stream for LSA. */ if ((s = stream_new (OSPF_MAX_LSA_SIZE)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: stream_new() ?"); goto out; } lsah = (struct lsa_header *) STREAM_DATA (s); options = LSA_OPTIONS_GET (area); options |= LSA_OPTIONS_NSSA_GET (area); options |= OSPF_OPTION_O; /* Don't forget this :-) */ lsa_type = OSPF_OPAQUE_AREA_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsa_id.s_addr = htonl (tmp); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Create an Opaque-LSA/MPLS-TE instance", lsa_type, inet_ntoa (lsa_id)); /* Set opaque-LSA header fields. */ lsa_header_set (s, options, lsa_type, lsa_id, area->ospf->router_id); /* Set opaque-LSA body fields. */ ospf_mpls_te_lsa_body_set (s, lp); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Now, create an OSPF LSA instance. */ if ((new = ospf_lsa_new ()) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_new() ?"); stream_free (s); goto out; } if ((new->data = ospf_lsa_data_new (length)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_new: ospf_lsa_data_new() ?"); ospf_lsa_unlock (&new); new = NULL; stream_free (s); goto out; } new->area = area; SET_FLAG (new->flags, OSPF_LSA_SELF); memcpy (new->data, lsah, length); stream_free (s); out: return new; } static int ospf_mpls_te_lsa_originate1 (struct ospf_area *area, struct mpls_te_link *lp) { struct ospf_lsa *new; int rc = -1; /* Create new Opaque-LSA/MPLS-TE instance. */ if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_mpls_te_lsa_new() ?"); goto out; } /* Install this LSA into LSDB. */ if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_originate1: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Now this linkparameter entry has associated LSA. */ lp->flags |= LPFLG_LSA_ENGAGED; /* Update new LSA origination count. */ area->ospf->lsa_originate_count++; /* Flood new LSA through area. */ ospf_flood_through_area (area, NULL/*nbr*/, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { char area_id[INET_ADDRSTRLEN]; strcpy (area_id, inet_ntoa (area->area_id)); zlog_debug ("LSA[Type%d:%s]: Originate Opaque-LSA/MPLS-TE: Area(%s), Link(%s)", new->data->type, inet_ntoa (new->data->id), area_id, lp->ifp->name); ospf_lsa_header_dump (new->data); } rc = 0; out: return rc; } static int ospf_mpls_te_lsa_originate (void *arg) { struct ospf_area *area = (struct ospf_area *) arg; struct listnode *node, *nnode; struct mpls_te_link *lp; int rc = -1; if (OspfMplsTE.status == disabled) { zlog_info ("ospf_mpls_te_lsa_originate: MPLS-TE is disabled now."); rc = 0; /* This is not an error case. */ goto out; } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if (lp->area == NULL) continue; if (! IPV4_ADDR_SAME (&lp->area->area_id, &area->area_id)) continue; if (lp->flags & LPFLG_LSA_ENGAGED) { if (lp->flags & LPFLG_LSA_FORCED_REFRESH) { lp->flags &= ~LPFLG_LSA_FORCED_REFRESH; ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } continue; } if (! is_mandated_params_set (lp)) { zlog_warn ("ospf_mpls_te_lsa_originate: Link(%s) lacks some mandated MPLS-TE parameters.", lp->ifp ? lp->ifp->name : "?"); continue; } /* Ok, let's try to originate an LSA for this area and Link. */ if (ospf_mpls_te_lsa_originate1 (area, lp) != 0) goto out; } rc = 0; out: return rc; } static struct ospf_lsa * ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa) { struct mpls_te_link *lp; struct ospf_area *area = lsa->area; struct ospf_lsa *new = NULL; if (OspfMplsTE.status == disabled) { /* * This LSA must have flushed before due to MPLS-TE status change. * It seems a slip among routers in the routing domain. */ zlog_info ("ospf_mpls_te_lsa_refresh: MPLS-TE is disabled now."); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } /* At first, resolve lsa/lp relationship. */ if ((lp = lookup_linkparams_by_instance (lsa)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: Invalid parameter?"); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); /* Flush it anyway. */ } /* If the lsa's age reached to MaxAge, start flushing procedure. */ if (IS_LSA_MAXAGE (lsa)) { if (lp) lp->flags &= ~LPFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (lsa); goto out; } /* Create new Opaque-LSA/MPLS-TE instance. */ if ((new = ospf_mpls_te_lsa_new (area, lp)) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_mpls_te_lsa_new() ?"); goto out; } new->data->ls_seqnum = lsa_seqnum_increment (lsa); /* Install this LSA into LSDB. */ /* Given "lsa" will be freed in the next function. */ if (ospf_lsa_install (area->ospf, NULL/*oi*/, new) == NULL) { zlog_warn ("ospf_mpls_te_lsa_refresh: ospf_lsa_install() ?"); ospf_lsa_unlock (&new); goto out; } /* Flood updated LSA through area. */ ospf_flood_through_area (area, NULL/*nbr*/, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Refresh Opaque-LSA/MPLS-TE", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } out: return new; } static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode opcode) { struct ospf_lsa lsa; struct lsa_header lsah; u_int32_t tmp; memset (&lsa, 0, sizeof (lsa)); memset (&lsah, 0, sizeof (lsah)); lsa.area = lp->area; lsa.data = &lsah; lsah.type = OSPF_OPAQUE_AREA_LSA; tmp = SET_OPAQUE_LSID (OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA, lp->instance); lsah.id.s_addr = htonl (tmp); switch (opcode) { case REORIGINATE_PER_AREA: ospf_opaque_lsa_reoriginate_schedule ((void *) lp->area, OSPF_OPAQUE_AREA_LSA, OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA); break; case REFRESH_THIS_LSA: ospf_opaque_lsa_refresh_schedule (&lsa); break; case FLUSH_THIS_LSA: lp->flags &= ~LPFLG_LSA_ENGAGED; ospf_opaque_lsa_flush_schedule (&lsa); break; default: zlog_warn ("ospf_mpls_te_lsa_schedule: Unknown opcode (%u)", opcode); break; } return; } /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ static u_int16_t show_vty_router_addr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_tlv_router_addr *top = (struct te_tlv_router_addr *) tlvh; if (vty != NULL) vty_out (vty, " Router-Address: %s%s", inet_ntoa (top->value), VTY_NEWLINE); else zlog_debug (" Router-Address: %s", inet_ntoa (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_header (struct vty *vty, struct te_tlv_header *tlvh) { struct te_tlv_link *top = (struct te_tlv_link *) tlvh; if (vty != NULL) vty_out (vty, " Link: %u octets of data%s", ntohs (top->header.length), VTY_NEWLINE); else zlog_debug (" Link: %u octets of data", ntohs (top->header.length)); return TLV_HDR_SIZE; /* Here is special, not "TLV_SIZE". */ } static u_int16_t show_vty_link_subtlv_link_type (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_link_type *top; const char *cp = "Unknown"; top = (struct te_link_subtlv_link_type *) tlvh; switch (top->link_type.value) { case LINK_TYPE_SUBTLV_VALUE_PTP: cp = "Point-to-point"; break; case LINK_TYPE_SUBTLV_VALUE_MA: cp = "Multiaccess"; break; default: break; } if (vty != NULL) vty_out (vty, " Link-Type: %s (%u)%s", cp, top->link_type.value, VTY_NEWLINE); else zlog_debug (" Link-Type: %s (%u)", cp, top->link_type.value); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_link_id (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_link_id *top; top = (struct te_link_subtlv_link_id *) tlvh; if (vty != NULL) vty_out (vty, " Link-ID: %s%s", inet_ntoa (top->value), VTY_NEWLINE); else zlog_debug (" Link-ID: %s", inet_ntoa (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_lclif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_lclif_ipaddr *top; int i, n; top = (struct te_link_subtlv_lclif_ipaddr *) tlvh; n = ntohs (tlvh->length) / sizeof (top->value[0]); if (vty != NULL) vty_out (vty, " Local Interface IP Address(es): %d%s", n, VTY_NEWLINE); else zlog_debug (" Local Interface IP Address(es): %d", n); for (i = 0; i < n; i++) { if (vty != NULL) vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_rmtif_ipaddr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_rmtif_ipaddr *top; int i, n; top = (struct te_link_subtlv_rmtif_ipaddr *) tlvh; n = ntohs (tlvh->length) / sizeof (top->value[0]); if (vty != NULL) vty_out (vty, " Remote Interface IP Address(es): %d%s", n, VTY_NEWLINE); else zlog_debug (" Remote Interface IP Address(es): %d", n); for (i = 0; i < n; i++) { if (vty != NULL) vty_out (vty, " #%d: %s%s", i, inet_ntoa (top->value[i]), VTY_NEWLINE); else zlog_debug (" #%d: %s", i, inet_ntoa (top->value[i])); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_te_metric (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_te_metric *top; top = (struct te_link_subtlv_te_metric *) tlvh; if (vty != NULL) vty_out (vty, " Traffic Engineering Metric: %u%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); else zlog_debug (" Traffic Engineering Metric: %u", (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_max_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_max_bw *top; float fval; top = (struct te_link_subtlv_max_bw *) tlvh; ntohf (&top->value, &fval); if (vty != NULL) vty_out (vty, " Maximum Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Maximum Bandwidth: %g (Bytes/sec)", fval); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_max_rsv_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_max_rsv_bw *top; float fval; top = (struct te_link_subtlv_max_rsv_bw *) tlvh; ntohf (&top->value, &fval); if (vty != NULL) vty_out (vty, " Maximum Reservable Bandwidth: %g (Bytes/sec)%s", fval, VTY_NEWLINE); else zlog_debug (" Maximum Reservable Bandwidth: %g (Bytes/sec)", fval); return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_unrsv_bw (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_unrsv_bw *top; float fval; int i; top = (struct te_link_subtlv_unrsv_bw *) tlvh; for (i = 0; i < 8; i++) { ntohf (&top->value[i], &fval); if (vty != NULL) vty_out (vty, " Unreserved Bandwidth (pri %d): %g (Bytes/sec)%s", i, fval, VTY_NEWLINE); else zlog_debug (" Unreserved Bandwidth (pri %d): %g (Bytes/sec)", i, fval); } return TLV_SIZE (tlvh); } static u_int16_t show_vty_link_subtlv_rsc_clsclr (struct vty *vty, struct te_tlv_header *tlvh) { struct te_link_subtlv_rsc_clsclr *top; top = (struct te_link_subtlv_rsc_clsclr *) tlvh; if (vty != NULL) vty_out (vty, " Resource class/color: 0x%x%s", (u_int32_t) ntohl (top->value), VTY_NEWLINE); else zlog_debug (" Resource Class/Color: 0x%x", (u_int32_t) ntohl (top->value)); return TLV_SIZE (tlvh); } static u_int16_t show_vty_unknown_tlv (struct vty *vty, struct te_tlv_header *tlvh) { if (vty != NULL) vty_out (vty, " Unknown TLV: [type(0x%x), length(0x%x)]%s", ntohs (tlvh->type), ntohs (tlvh->length), VTY_NEWLINE); else zlog_debug (" Unknown TLV: [type(0x%x), length(0x%x)]", ntohs (tlvh->type), ntohs (tlvh->length)); return TLV_SIZE (tlvh); } static u_int16_t ospf_mpls_te_show_link_subtlv (struct vty *vty, struct te_tlv_header *tlvh0, u_int16_t subtotal, u_int16_t total) { struct te_tlv_header *tlvh, *next; u_int16_t sum = subtotal; for (tlvh = tlvh0; sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) { next = NULL; switch (ntohs (tlvh->type)) { case TE_LINK_SUBTLV_LINK_TYPE: sum += show_vty_link_subtlv_link_type (vty, tlvh); break; case TE_LINK_SUBTLV_LINK_ID: sum += show_vty_link_subtlv_link_id (vty, tlvh); break; case TE_LINK_SUBTLV_LCLIF_IPADDR: sum += show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); break; case TE_LINK_SUBTLV_RMTIF_IPADDR: sum += show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); break; case TE_LINK_SUBTLV_TE_METRIC: sum += show_vty_link_subtlv_te_metric (vty, tlvh); break; case TE_LINK_SUBTLV_MAX_BW: sum += show_vty_link_subtlv_max_bw (vty, tlvh); break; case TE_LINK_SUBTLV_MAX_RSV_BW: sum += show_vty_link_subtlv_max_rsv_bw (vty, tlvh); break; case TE_LINK_SUBTLV_UNRSV_BW: sum += show_vty_link_subtlv_unrsv_bw (vty, tlvh); break; case TE_LINK_SUBTLV_RSC_CLSCLR: sum += show_vty_link_subtlv_rsc_clsclr (vty, tlvh); break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return sum; } static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *) lsa->data; struct te_tlv_header *tlvh, *next; u_int16_t sum, total; u_int16_t (* subfunc)(struct vty *vty, struct te_tlv_header *tlvh, u_int16_t subtotal, u_int16_t total) = NULL; sum = 0; total = ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE; for (tlvh = TLV_HDR_TOP (lsah); sum < total; tlvh = (next ? next : TLV_HDR_NEXT (tlvh))) { if (subfunc != NULL) { sum = (* subfunc)(vty, tlvh, sum, total); next = (struct te_tlv_header *)((char *) tlvh + sum); subfunc = NULL; continue; } next = NULL; switch (ntohs (tlvh->type)) { case TE_TLV_ROUTER_ADDR: sum += show_vty_router_addr (vty, tlvh); break; case TE_TLV_LINK: sum += show_vty_link_header (vty, tlvh); subfunc = ospf_mpls_te_show_link_subtlv; next = tlvh + 1; break; default: sum += show_vty_unknown_tlv (vty, tlvh); break; } } return; } static void ospf_mpls_te_config_write_router (struct vty *vty) { if (OspfMplsTE.status == enabled) { vty_out (vty, " mpls-te%s", VTY_NEWLINE); vty_out (vty, " mpls-te router-address %s%s", inet_ntoa (OspfMplsTE.router_addr.value), VTY_NEWLINE); } return; } static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; if ((OspfMplsTE.status == enabled) && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { float fval; int i; vty_out (vty, " mpls-te link metric %u%s", (u_int32_t) ntohl (lp->te_metric.value), VTY_NEWLINE); ntohf (&lp->max_bw.value, &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-bw %g%s", fval, VTY_NEWLINE); ntohf (&lp->max_rsv_bw.value, &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link max-rsv-bw %g%s", fval, VTY_NEWLINE); for (i = 0; i < 8; i++) { ntohf (&lp->unrsv_bw.value[i], &fval); if (fval >= MPLS_TE_MINIMUM_BANDWIDTH) vty_out (vty, " mpls-te link unrsv-bw %d %g%s", i, fval, VTY_NEWLINE); } vty_out (vty, " mpls-te link rsc-clsclr 0x%x%s", (u_int32_t) ntohl (lp->rsc_clsclr.value), VTY_NEWLINE); } return; } /*------------------------------------------------------------------------* * Followings are vty command functions. *------------------------------------------------------------------------*/ DEFUN (mpls_te, mpls_te_cmd, "mpls-te", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") { struct listnode *node, *nnode; struct mpls_te_link *lp; if (OspfMplsTE.status == enabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: OFF -> ON"); OspfMplsTE.status = enabled; /* * Following code is intended to handle two cases; * * 1) MPLS-TE was disabled at startup time, but now become enabled. * 2) MPLS-TE was once enabled then disabled, and now enabled again. */ for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) initialize_linkparams (lp); ospf_mpls_te_foreach_area (ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); return CMD_SUCCESS; } ALIAS (mpls_te, mpls_te_on_cmd, "mpls-te on", "Configure MPLS-TE parameters\n" "Enable the MPLS-TE functionality\n") DEFUN (no_mpls_te, no_mpls_te_cmd, "no mpls-te", NO_STR "Configure MPLS-TE parameters\n" "Disable the MPLS-TE functionality\n") { struct listnode *node, *nnode; struct mpls_te_link *lp; if (OspfMplsTE.status == disabled) return CMD_SUCCESS; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("MPLS-TE: ON -> OFF"); OspfMplsTE.status = disabled; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) if (lp->area != NULL) if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, FLUSH_THIS_LSA); return CMD_SUCCESS; } DEFUN (mpls_te_router_addr, mpls_te_router_addr_cmd, "mpls-te router-address A.B.C.D", "MPLS-TE specific commands\n" "Stable IP address of the advertising router\n" "MPLS-TE router address in IPv4 address format\n") { struct te_tlv_router_addr *ra = &OspfMplsTE.router_addr; struct in_addr value; if (! inet_aton (argv[0], &value)) { vty_out (vty, "Please specify Router-Addr by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } if (ntohs (ra->header.type) == 0 || ntohl (ra->value.s_addr) != ntohl (value.s_addr)) { struct listnode *node, *nnode; struct mpls_te_link *lp; int need_to_reoriginate = 0; set_mpls_te_router_addr (value); if (OspfMplsTE.status == disabled) goto out; for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if (lp->area == NULL) continue; if ((lp->flags & LPFLG_LSA_ENGAGED) == 0) { need_to_reoriginate = 1; break; } } for (ALL_LIST_ELEMENTS (OspfMplsTE.iflist, node, nnode, lp)) { if (lp->area == NULL) continue; if (need_to_reoriginate) lp->flags |= LPFLG_LSA_FORCED_REFRESH; else ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); } if (need_to_reoriginate) ospf_mpls_te_foreach_area ( ospf_mpls_te_lsa_schedule, REORIGINATE_PER_AREA); } out: return CMD_SUCCESS; } DEFUN (mpls_te_link_metric, mpls_te_link_metric_cmd, "mpls-te link metric <0-4294967295>", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Link metric for MPLS-TE purpose\n" "Metric\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; u_int32_t value; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_metric: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } value = strtoul (argv[0], NULL, 10); if (ntohs (lp->te_metric.header.type) == 0 || ntohl (lp->te_metric.value) != value) { set_linkparams_te_metric (lp, value); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_maxbw, mpls_te_link_maxbw_cmd, "mpls-te link max-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that can be used\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_maxbw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->max_bw.value, &f1); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_maxbw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->max_bw.header.type) == 0 || f1 != f2) { set_linkparams_max_bw (lp, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_max_rsv_bw, mpls_te_link_max_rsv_bw_cmd, "mpls-te link max-rsv-bw BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Maximum bandwidth that may be reserved\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_max_rsv_bw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->max_rsv_bw.value, &f1); if (sscanf (argv[0], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_max_rsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->max_rsv_bw.header.type) == 0 || f1 != f2) { set_linkparams_max_rsv_bw (lp, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_unrsv_bw, mpls_te_link_unrsv_bw_cmd, "mpls-te link unrsv-bw <0-7> BANDWIDTH", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Unreserved bandwidth at each priority level\n" "Priority\n" "Bytes/second (IEEE floating point format)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; int priority; float f1, f2; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_unrsv_bw: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } /* We don't have to consider about range check here. */ if (sscanf (argv[0], "%d", &priority) != 1) { vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } ntohf (&lp->unrsv_bw.value [priority], &f1); if (sscanf (argv[1], "%g", &f2) != 1) { vty_out (vty, "mpls_te_link_unrsv_bw: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->unrsv_bw.header.type) == 0 || f1 != f2) { set_linkparams_unrsv_bw (lp, priority, &f2); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (mpls_te_link_rsc_clsclr, mpls_te_link_rsc_clsclr_cmd, "mpls-te link rsc-clsclr BITPATTERN", "MPLS-TE specific commands\n" "Configure MPLS-TE link parameters\n" "Administrative group membership\n" "32-bit Hexadecimal value (ex. 0xa1)\n") { struct interface *ifp = (struct interface *) vty->index; struct mpls_te_link *lp; unsigned long value; if ((lp = lookup_linkparams_by_ifp (ifp)) == NULL) { vty_out (vty, "mpls_te_link_rsc_clsclr: Something wrong!%s", VTY_NEWLINE); return CMD_WARNING; } if (sscanf (argv[0], "0x%lx", &value) != 1) { vty_out (vty, "mpls_te_link_rsc_clsclr: fscanf: %s%s", safe_strerror (errno), VTY_NEWLINE); return CMD_WARNING; } if (ntohs (lp->rsc_clsclr.header.type) == 0 || ntohl (lp->rsc_clsclr.value) != value) { set_linkparams_rsc_clsclr (lp, value); if (OspfMplsTE.status == enabled) if (lp->area != NULL) { if (lp->flags & LPFLG_LSA_ENGAGED) ospf_mpls_te_lsa_schedule (lp, REFRESH_THIS_LSA); else ospf_mpls_te_lsa_schedule (lp, REORIGINATE_PER_AREA); } } return CMD_SUCCESS; } DEFUN (show_mpls_te_router, show_mpls_te_router_cmd, "show mpls-te router", SHOW_STR "MPLS-TE information\n" "Router information\n") { if (OspfMplsTE.status == enabled) { vty_out (vty, "--- MPLS-TE router parameters ---%s", VTY_NEWLINE); if (ntohs (OspfMplsTE.router_addr.header.type) != 0) show_vty_router_addr (vty, &OspfMplsTE.router_addr.header); else if (vty != NULL) vty_out (vty, " N/A%s", VTY_NEWLINE); } return CMD_SUCCESS; } static void show_mpls_te_link_sub (struct vty *vty, struct interface *ifp) { struct mpls_te_link *lp; struct te_tlv_header *tlvh; if ((OspfMplsTE.status == enabled) && (! if_is_loopback (ifp) && if_is_up (ifp) && ospf_oi_count (ifp) > 0) && ((lp = lookup_linkparams_by_ifp (ifp)) != NULL)) { vty_out (vty, "-- MPLS-TE link parameters for %s --%s", ifp->name, VTY_NEWLINE); show_vty_link_subtlv_link_type (vty, &lp->link_type.header); show_vty_link_subtlv_link_id (vty, &lp->link_id.header); if ((tlvh = (struct te_tlv_header *) lp->lclif_ipaddr) != NULL) show_vty_link_subtlv_lclif_ipaddr (vty, tlvh); if ((tlvh = (struct te_tlv_header *) lp->rmtif_ipaddr) != NULL) show_vty_link_subtlv_rmtif_ipaddr (vty, tlvh); show_vty_link_subtlv_te_metric (vty, &lp->te_metric.header); show_vty_link_subtlv_max_bw (vty, &lp->max_bw.header); show_vty_link_subtlv_max_rsv_bw (vty, &lp->max_rsv_bw.header); show_vty_link_subtlv_unrsv_bw (vty, &lp->unrsv_bw.header); show_vty_link_subtlv_rsc_clsclr (vty, &lp->rsc_clsclr.header); } else { vty_out (vty, " %s: MPLS-TE is disabled on this interface%s", ifp->name, VTY_NEWLINE); } return; } DEFUN (show_mpls_te_link, show_mpls_te_link_cmd, "show mpls-te interface [INTERFACE]", SHOW_STR "MPLS-TE information\n" "Interface information\n" "Interface name\n") { struct interface *ifp; struct listnode *node, *nnode; /* Show All Interfaces. */ if (argc == 0) { for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) show_mpls_te_link_sub (vty, ifp); } /* Interface name is specified. */ else { if ((ifp = if_lookup_by_name (argv[0])) == NULL) vty_out (vty, "No such interface name%s", VTY_NEWLINE); else show_mpls_te_link_sub (vty, ifp); } return CMD_SUCCESS; } static void ospf_mpls_te_register_vty (void) { install_element (VIEW_NODE, &show_mpls_te_router_cmd); install_element (VIEW_NODE, &show_mpls_te_link_cmd); install_element (ENABLE_NODE, &show_mpls_te_router_cmd); install_element (ENABLE_NODE, &show_mpls_te_link_cmd); install_element (OSPF_NODE, &mpls_te_cmd); install_element (OSPF_NODE, &no_mpls_te_cmd); install_element (OSPF_NODE, &mpls_te_on_cmd); install_element (OSPF_NODE, &mpls_te_router_addr_cmd); install_element (INTERFACE_NODE, &mpls_te_link_metric_cmd); install_element (INTERFACE_NODE, &mpls_te_link_maxbw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_max_rsv_bw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_unrsv_bw_cmd); install_element (INTERFACE_NODE, &mpls_te_link_rsc_clsclr_cmd); return; } #endif /* HAVE_OSPF_TE */ quagga-0.99.24.1/ospfd/ospf_opaque.c0000644000175000017500000021527212476520570014045 00000000000000/* * This is an implementation of rfc2370. * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /***** MTYPE definitions are not reflected to "memory.h" yet. *****/ #define MTYPE_OSPF_OPAQUE_FUNCTAB 0 #define MTYPE_OPAQUE_INFO_PER_TYPE 0 #define MTYPE_OPAQUE_INFO_PER_ID 0 #include #ifdef HAVE_OPAQUE_LSA #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "vty.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" /*------------------------------------------------------------------------* * Followings are initialize/terminate functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ #ifdef HAVE_OSPF_TE #include "ospfd/ospf_te.h" #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API int ospf_apiserver_init (void); void ospf_apiserver_term (void); /* Init apiserver? It's disabled by default. */ int ospf_apiserver_enable; #endif /* SUPPORT_OSPF_API */ static void ospf_opaque_register_vty (void); static void ospf_opaque_funclist_init (void); static void ospf_opaque_funclist_term (void); static void free_opaque_info_per_type (void *val); static void free_opaque_info_per_id (void *val); static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa); static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa); void ospf_opaque_init (void) { ospf_opaque_register_vty (); ospf_opaque_funclist_init (); #ifdef HAVE_OSPF_TE if (ospf_mpls_te_init () != 0) exit (1); #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API if ((ospf_apiserver_enable) && (ospf_apiserver_init () != 0)) exit (1); #endif /* SUPPORT_OSPF_API */ return; } void ospf_opaque_term (void) { #ifdef HAVE_OSPF_TE ospf_mpls_te_term (); #endif /* HAVE_OSPF_TE */ #ifdef SUPPORT_OSPF_API ospf_apiserver_term (); #endif /* SUPPORT_OSPF_API */ ospf_opaque_funclist_term (); return; } int ospf_opaque_type9_lsa_init (struct ospf_interface *oi) { if (oi->opaque_lsa_self != NULL) list_delete (oi->opaque_lsa_self); oi->opaque_lsa_self = list_new (); oi->opaque_lsa_self->del = free_opaque_info_per_type; oi->t_opaque_lsa_self = NULL; return 0; } void ospf_opaque_type9_lsa_term (struct ospf_interface *oi) { OSPF_TIMER_OFF (oi->t_opaque_lsa_self); if (oi->opaque_lsa_self != NULL) list_delete (oi->opaque_lsa_self); oi->opaque_lsa_self = NULL; return; } int ospf_opaque_type10_lsa_init (struct ospf_area *area) { if (area->opaque_lsa_self != NULL) list_delete (area->opaque_lsa_self); area->opaque_lsa_self = list_new (); area->opaque_lsa_self->del = free_opaque_info_per_type; area->t_opaque_lsa_self = NULL; #ifdef MONITOR_LSDB_CHANGE area->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; area->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; #endif /* MONITOR_LSDB_CHANGE */ return 0; } void ospf_opaque_type10_lsa_term (struct ospf_area *area) { #ifdef MONITOR_LSDB_CHANGE area->lsdb->new_lsa_hook = area->lsdb->del_lsa_hook = NULL; #endif /* MONITOR_LSDB_CHANGE */ OSPF_TIMER_OFF (area->t_opaque_lsa_self); if (area->opaque_lsa_self != NULL) list_delete (area->opaque_lsa_self); area->opaque_lsa_self = NULL; return; } int ospf_opaque_type11_lsa_init (struct ospf *top) { if (top->opaque_lsa_self != NULL) list_delete (top->opaque_lsa_self); top->opaque_lsa_self = list_new (); top->opaque_lsa_self->del = free_opaque_info_per_type; top->t_opaque_lsa_self = NULL; #ifdef MONITOR_LSDB_CHANGE top->lsdb->new_lsa_hook = ospf_opaque_lsa_install_hook; top->lsdb->del_lsa_hook = ospf_opaque_lsa_delete_hook; #endif /* MONITOR_LSDB_CHANGE */ return 0; } void ospf_opaque_type11_lsa_term (struct ospf *top) { #ifdef MONITOR_LSDB_CHANGE top->lsdb->new_lsa_hook = top->lsdb->del_lsa_hook = NULL; #endif /* MONITOR_LSDB_CHANGE */ OSPF_TIMER_OFF (top->t_opaque_lsa_self); if (top->opaque_lsa_self != NULL) list_delete (top->opaque_lsa_self); top->opaque_lsa_self = NULL; return; } static const char * ospf_opaque_type_name (u_char opaque_type) { const char *name = "Unknown"; switch (opaque_type) { case OPAQUE_TYPE_WILDCARD: /* This is a special assignment! */ name = "Wildcard"; break; case OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA: name = "Traffic Engineering LSA"; break; case OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC: name = "Sycamore optical topology description"; break; case OPAQUE_TYPE_GRACE_LSA: name = "Grace-LSA"; break; default: if (OPAQUE_TYPE_RANGE_UNASSIGNED (opaque_type)) name = "Unassigned"; else { u_int32_t bigger_range = opaque_type; /* * Get around type-limits warning: comparison is always true due to limited range of data type */ if (OPAQUE_TYPE_RANGE_RESERVED (bigger_range)) name = "Private/Experimental"; } break; } return name; } /*------------------------------------------------------------------------* * Followings are management functions to store user specified callbacks. *------------------------------------------------------------------------*/ struct opaque_info_per_type; /* Forward declaration. */ struct ospf_opaque_functab { u_char opaque_type; struct opaque_info_per_type *oipt; int (* new_if_hook)(struct interface *ifp); int (* del_if_hook)(struct interface *ifp); void (* ism_change_hook)(struct ospf_interface *oi, int old_status); void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status); void (* config_write_router)(struct vty *vty); void (* config_write_if )(struct vty *vty, struct interface *ifp); void (* config_write_debug )(struct vty *vty); void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa); int (* lsa_originator)(void *arg); struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa); int (* new_lsa_hook)(struct ospf_lsa *lsa); int (* del_lsa_hook)(struct ospf_lsa *lsa); }; /* Handle LSA-9/10/11 altogether. */ static struct list *ospf_opaque_wildcard_funclist; static struct list *ospf_opaque_type9_funclist; static struct list *ospf_opaque_type10_funclist; static struct list *ospf_opaque_type11_funclist; static void ospf_opaque_del_functab (void *val) { XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, val); return; } static void ospf_opaque_funclist_init (void) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type9_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type10_funclist = list_new (); funclist->del = ospf_opaque_del_functab; funclist = ospf_opaque_type11_funclist = list_new (); funclist->del = ospf_opaque_del_functab; return; } static void ospf_opaque_funclist_term (void) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; list_delete (funclist); funclist = ospf_opaque_type9_funclist; list_delete (funclist); funclist = ospf_opaque_type10_funclist; list_delete (funclist); funclist = ospf_opaque_type11_funclist; list_delete (funclist); return; } static struct list * ospf_get_opaque_funclist (u_char lsa_type) { struct list *funclist = NULL; switch (lsa_type) { case OPAQUE_TYPE_WILDCARD: /* XXX * This is an ugly trick to handle type-9/10/11 LSA altogether. * Yes, "OPAQUE_TYPE_WILDCARD (value 0)" is not an LSA-type, nor * an officially assigned opaque-type. * Though it is possible that the value might be officially used * in the future, we use it internally as a special label, for now. */ funclist = ospf_opaque_wildcard_funclist; break; case OSPF_OPAQUE_LINK_LSA: funclist = ospf_opaque_type9_funclist; break; case OSPF_OPAQUE_AREA_LSA: funclist = ospf_opaque_type10_funclist; break; case OSPF_OPAQUE_AS_LSA: funclist = ospf_opaque_type11_funclist; break; default: zlog_warn ("ospf_get_opaque_funclist: Unexpected LSA-type(%u)", lsa_type); break; } return funclist; } /* XXX: such a huge argument list can /not/ be healthy... */ int ospf_register_opaque_functab ( u_char lsa_type, u_char opaque_type, int (* new_if_hook)(struct interface *ifp), int (* del_if_hook)(struct interface *ifp), void (* ism_change_hook)(struct ospf_interface *oi, int old_status), void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), void (* config_write_router)(struct vty *vty), void (* config_write_if )(struct vty *vty, struct interface *ifp), void (* config_write_debug )(struct vty *vty), void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), int (* lsa_originator)(void *arg), struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa), int (* new_lsa_hook)(struct ospf_lsa *lsa), int (* del_lsa_hook)(struct ospf_lsa *lsa)) { struct list *funclist; struct ospf_opaque_functab *new; int rc = -1; if ((funclist = ospf_get_opaque_funclist (lsa_type)) == NULL) { zlog_warn ("ospf_register_opaque_functab: Cannot get funclist" " for Type-%u LSAs?", lsa_type); goto out; } else { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->opaque_type == opaque_type) { zlog_warn ("ospf_register_opaque_functab: Duplicated entry?:" " lsa_type(%u), opaque_type(%u)", lsa_type, opaque_type); goto out; } } if ((new = XCALLOC (MTYPE_OSPF_OPAQUE_FUNCTAB, sizeof (struct ospf_opaque_functab))) == NULL) { zlog_warn ("ospf_register_opaque_functab: XMALLOC: %s", safe_strerror (errno)); goto out; } new->opaque_type = opaque_type; new->oipt = NULL; new->new_if_hook = new_if_hook; new->del_if_hook = del_if_hook; new->ism_change_hook = ism_change_hook; new->nsm_change_hook = nsm_change_hook; new->config_write_router = config_write_router; new->config_write_if = config_write_if; new->config_write_debug = config_write_debug; new->show_opaque_info = show_opaque_info; new->lsa_originator = lsa_originator; new->lsa_refresher = lsa_refresher; new->new_lsa_hook = new_lsa_hook; new->del_lsa_hook = del_lsa_hook; listnode_add (funclist, new); rc = 0; out: return rc; } void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type) { struct list *funclist; struct listnode *node, *nnode; struct ospf_opaque_functab *functab; if ((funclist = ospf_get_opaque_funclist (lsa_type)) != NULL) for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) { if (functab->opaque_type == opaque_type) { /* Cleanup internal control information, if it still remains. */ if (functab->oipt != NULL) free_opaque_info_per_type (functab->oipt); /* Dequeue listnode entry from the list. */ listnode_delete (funclist, functab); /* Avoid misjudgement in the next lookup. */ if (listcount (funclist) == 0) funclist->head = funclist->tail = NULL; XFREE (MTYPE_OSPF_OPAQUE_FUNCTAB, functab); break; } } return; } static struct ospf_opaque_functab * ospf_opaque_functab_lookup (struct ospf_lsa *lsa) { struct list *funclist; struct listnode *node; struct ospf_opaque_functab *functab; u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); if ((funclist = ospf_get_opaque_funclist (lsa->data->type)) != NULL) for (ALL_LIST_ELEMENTS_RO (funclist, node, functab)) if (functab->opaque_type == key) return functab; return NULL; } /*------------------------------------------------------------------------* * Followings are management functions for self-originated LSA entries. *------------------------------------------------------------------------*/ /* * Opaque-LSA control information per opaque-type. * Single Opaque-Type may have multiple instances; each of them will be * identified by their opaque-id. */ struct opaque_info_per_type { u_char lsa_type; u_char opaque_type; enum { PROC_NORMAL, PROC_SUSPEND } status; /* * Thread for (re-)origination scheduling for this opaque-type. * * Initial origination of Opaque-LSAs is controlled by generic * Opaque-LSA handling module so that same opaque-type entries are * called all at once when certain conditions are met. * However, there might be cases that some Opaque-LSA clients need * to (re-)originate their own Opaque-LSAs out-of-sync with others. * This thread is prepared for that specific purpose. */ struct thread *t_opaque_lsa_self; /* * Backpointer to an "owner" which is LSA-type dependent. * type-9: struct ospf_interface * type-10: struct ospf_area * type-11: struct ospf */ void *owner; /* Collection of callback functions for this opaque-type. */ struct ospf_opaque_functab *functab; /* List of Opaque-LSA control informations per opaque-id. */ struct list *id_list; }; /* Opaque-LSA control information per opaque-id. */ struct opaque_info_per_id { u_int32_t opaque_id; /* Thread for refresh/flush scheduling for this opaque-type/id. */ struct thread *t_opaque_lsa_self; /* Backpointer to Opaque-LSA control information per opaque-type. */ struct opaque_info_per_type *opqctl_type; /* Here comes an actual Opaque-LSA entry for this opaque-type/id. */ struct ospf_lsa *lsa; }; static struct opaque_info_per_type *register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new); static struct opaque_info_per_type *lookup_opaque_info_by_type (struct ospf_lsa *lsa); static struct opaque_info_per_id *register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new); static struct opaque_info_per_id *lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa); static struct opaque_info_per_id *register_opaque_lsa (struct ospf_lsa *new); static struct opaque_info_per_type * register_opaque_info_per_type (struct ospf_opaque_functab *functab, struct ospf_lsa *new) { struct ospf *top; struct opaque_info_per_type *oipt; if ((oipt = XCALLOC (MTYPE_OPAQUE_INFO_PER_TYPE, sizeof (struct opaque_info_per_type))) == NULL) { zlog_warn ("register_opaque_info_per_type: XMALLOC: %s", safe_strerror (errno)); goto out; } switch (new->data->type) { case OSPF_OPAQUE_LINK_LSA: oipt->owner = new->oi; listnode_add (new->oi->opaque_lsa_self, oipt); break; case OSPF_OPAQUE_AREA_LSA: oipt->owner = new->area; listnode_add (new->area->opaque_lsa_self, oipt); break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if (new->area != NULL && (top = new->area->ospf) == NULL) { free_opaque_info_per_type ((void *) oipt); oipt = NULL; goto out; /* This case may not exist. */ } oipt->owner = top; listnode_add (top->opaque_lsa_self, oipt); break; default: zlog_warn ("register_opaque_info_per_type: Unexpected LSA-type(%u)", new->data->type); free_opaque_info_per_type ((void *) oipt); oipt = NULL; goto out; /* This case may not exist. */ } oipt->lsa_type = new->data->type; oipt->opaque_type = GET_OPAQUE_TYPE (ntohl (new->data->id.s_addr)); oipt->status = PROC_NORMAL; oipt->t_opaque_lsa_self = NULL; oipt->functab = functab; functab->oipt = oipt; oipt->id_list = list_new (); oipt->id_list->del = free_opaque_info_per_id; out: return oipt; } static void free_opaque_info_per_type (void *val) { struct opaque_info_per_type *oipt = (struct opaque_info_per_type *) val; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; struct listnode *node, *nnode; /* Control information per opaque-id may still exist. */ for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) { if ((lsa = oipi->lsa) == NULL) continue; if (IS_LSA_MAXAGE (lsa)) continue; ospf_opaque_lsa_flush_schedule (lsa); } /* Remove "oipt" from its owner's self-originated LSA list. */ switch (oipt->lsa_type) { case OSPF_OPAQUE_LINK_LSA: { struct ospf_interface *oi = (struct ospf_interface *)(oipt->owner); listnode_delete (oi->opaque_lsa_self, oipt); break; } case OSPF_OPAQUE_AREA_LSA: { struct ospf_area *area = (struct ospf_area *)(oipt->owner); listnode_delete (area->opaque_lsa_self, oipt); break; } case OSPF_OPAQUE_AS_LSA: { struct ospf *top = (struct ospf *)(oipt->owner); listnode_delete (top->opaque_lsa_self, oipt); break; } default: zlog_warn ("free_opaque_info_per_type: Unexpected LSA-type(%u)", oipt->lsa_type); break; /* This case may not exist. */ } OSPF_TIMER_OFF (oipt->t_opaque_lsa_self); list_delete (oipt->id_list); XFREE (MTYPE_OPAQUE_INFO_PER_TYPE, oipt); return; } static struct opaque_info_per_type * lookup_opaque_info_by_type (struct ospf_lsa *lsa) { struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; struct list *listtop = NULL; struct listnode *node, *nnode; struct opaque_info_per_type *oipt = NULL; u_char key = GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if ((oi = lsa->oi) != NULL) listtop = oi->opaque_lsa_self; else zlog_warn ("Type-9 Opaque-LSA: Reference to OI is missing?"); break; case OSPF_OPAQUE_AREA_LSA: if ((area = lsa->area) != NULL) listtop = area->opaque_lsa_self; else zlog_warn ("Type-10 Opaque-LSA: Reference to AREA is missing?"); break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if ((area = lsa->area) != NULL && (top = area->ospf) == NULL) { zlog_warn ("Type-11 Opaque-LSA: Reference to OSPF is missing?"); break; /* Unlikely to happen. */ } listtop = top->opaque_lsa_self; break; default: zlog_warn ("lookup_opaque_info_by_type: Unexpected LSA-type(%u)", lsa->data->type); break; } if (listtop != NULL) for (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) if (oipt->opaque_type == key) return oipt; return NULL; } static struct opaque_info_per_id * register_opaque_info_per_id (struct opaque_info_per_type *oipt, struct ospf_lsa *new) { struct opaque_info_per_id *oipi; if ((oipi = XCALLOC (MTYPE_OPAQUE_INFO_PER_ID, sizeof (struct opaque_info_per_id))) == NULL) { zlog_warn ("register_opaque_info_per_id: XMALLOC: %s", safe_strerror (errno)); goto out; } oipi->opaque_id = GET_OPAQUE_ID (ntohl (new->data->id.s_addr)); oipi->t_opaque_lsa_self = NULL; oipi->opqctl_type = oipt; oipi->lsa = ospf_lsa_lock (new); listnode_add (oipt->id_list, oipi); out: return oipi; } static void free_opaque_info_per_id (void *val) { struct opaque_info_per_id *oipi = (struct opaque_info_per_id *) val; OSPF_TIMER_OFF (oipi->t_opaque_lsa_self); if (oipi->lsa != NULL) ospf_lsa_unlock (&oipi->lsa); XFREE (MTYPE_OPAQUE_INFO_PER_ID, oipi); return; } static struct opaque_info_per_id * lookup_opaque_info_by_id (struct opaque_info_per_type *oipt, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct opaque_info_per_id *oipi; u_int32_t key = GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)); for (ALL_LIST_ELEMENTS (oipt->id_list, node, nnode, oipi)) if (oipi->opaque_id == key) return oipi; return NULL; } static struct opaque_info_per_id * register_opaque_lsa (struct ospf_lsa *new) { struct ospf_opaque_functab *functab; struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi = NULL; if ((functab = ospf_opaque_functab_lookup (new)) == NULL) goto out; if ((oipt = lookup_opaque_info_by_type (new)) == NULL && (oipt = register_opaque_info_per_type (functab, new)) == NULL) goto out; if ((oipi = register_opaque_info_per_id (oipt, new)) == NULL) goto out; out: return oipi; } /*------------------------------------------------------------------------* * Followings are (vty) configuration functions for Opaque-LSAs handling. *------------------------------------------------------------------------*/ DEFUN (capability_opaque, capability_opaque_cmd, "capability opaque", "Enable specific OSPF feature\n" "Opaque LSA\n") { struct ospf *ospf = (struct ospf *) vty->index; /* Turn on the "master switch" of opaque-lsa capability. */ if (!CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque capability: OFF -> ON"); SET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); ospf_renegotiate_optional_capabilities (ospf); } return CMD_SUCCESS; } ALIAS (capability_opaque, ospf_opaque_capable_cmd, "ospf opaque-lsa", "OSPF specific commands\n" "Enable the Opaque-LSA capability (rfc2370)\n") DEFUN (no_capability_opaque, no_capability_opaque_cmd, "no capability opaque", NO_STR "Enable specific OSPF feature\n" "Opaque LSA\n") { struct ospf *ospf = (struct ospf *) vty->index; /* Turn off the "master switch" of opaque-lsa capability. */ if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque capability: ON -> OFF"); UNSET_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE); ospf_renegotiate_optional_capabilities (ospf); } return CMD_SUCCESS; } ALIAS (no_capability_opaque, no_ospf_opaque_capable_cmd, "no ospf opaque-lsa", NO_STR "OSPF specific commands\n" "Disable the Opaque-LSA capability (rfc2370)\n") static void ospf_opaque_register_vty (void) { install_element (OSPF_NODE, &capability_opaque_cmd); install_element (OSPF_NODE, &no_capability_opaque_cmd); install_element (OSPF_NODE, &ospf_opaque_capable_cmd); install_element (OSPF_NODE, &no_ospf_opaque_capable_cmd); return; } /*------------------------------------------------------------------------* * Followings are collection of user-registered function callers. *------------------------------------------------------------------------*/ static int opaque_lsa_new_if_callback (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->new_if_hook != NULL) if ((* functab->new_if_hook)(ifp) != 0) goto out; rc = 0; out: return rc; } static int opaque_lsa_del_if_callback (struct list *funclist, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->del_if_hook != NULL) if ((* functab->del_if_hook)(ifp) != 0) goto out; rc = 0; out: return rc; } static void opaque_lsa_ism_change_callback (struct list *funclist, struct ospf_interface *oi, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->ism_change_hook != NULL) (* functab->ism_change_hook)(oi, old_status); return; } static void opaque_lsa_nsm_change_callback (struct list *funclist, struct ospf_neighbor *nbr, int old_status) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->nsm_change_hook != NULL) (* functab->nsm_change_hook)(nbr, old_status); return; } static void opaque_lsa_config_write_router_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_router != NULL) (* functab->config_write_router)(vty); return; } static void opaque_lsa_config_write_if_callback (struct list *funclist, struct vty *vty, struct interface *ifp) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_if != NULL) (* functab->config_write_if)(vty, ifp); return; } static void opaque_lsa_config_write_debug_callback (struct list *funclist, struct vty *vty) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->config_write_debug != NULL) (* functab->config_write_debug)(vty); return; } static int opaque_lsa_originate_callback (struct list *funclist, void *lsa_type_dependent) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->lsa_originator != NULL) if ((* functab->lsa_originator)(lsa_type_dependent) != 0) goto out; rc = 0; out: return rc; } static int new_lsa_callback (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->new_lsa_hook != NULL) if ((* functab->new_lsa_hook)(lsa) != 0) goto out; rc = 0; out: return rc; } static int del_lsa_callback (struct list *funclist, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_opaque_functab *functab; int rc = -1; /* This function handles ALL types of LSAs, not only opaque ones. */ for (ALL_LIST_ELEMENTS (funclist, node, nnode, functab)) if (functab->del_lsa_hook != NULL) if ((* functab->del_lsa_hook)(lsa) != 0) goto out; rc = 0; out: return rc; } /*------------------------------------------------------------------------* * Followings are glue functions to call Opaque-LSA specific processing. *------------------------------------------------------------------------*/ int ospf_opaque_new_if (struct interface *ifp) { struct list *funclist; int rc = -1; funclist = ospf_opaque_wildcard_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (opaque_lsa_new_if_callback (funclist, ifp) != 0) goto out; rc = 0; out: return rc; } int ospf_opaque_del_if (struct interface *ifp) { struct list *funclist; int rc = -1; funclist = ospf_opaque_wildcard_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (opaque_lsa_del_if_callback (funclist, ifp) != 0) goto out; rc = 0; out: return rc; } void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type9_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type10_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); funclist = ospf_opaque_type11_funclist; opaque_lsa_ism_change_callback (funclist, oi, old_status); return; } void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_state) { struct ospf *top; struct list *funclist; if ((top = oi_to_top (nbr->oi)) == NULL) goto out; if (old_state != NSM_Full && nbr->state == NSM_Full) { if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Opaque-LSA: Now get operational!"); SET_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT); } ospf_opaque_lsa_originate_schedule (nbr->oi, NULL); } } else if (old_state == NSM_Full && nbr->state != NSM_Full) { #ifdef NOTYET /* * If no more opaque-capable full-state neighbor remains in the * flooding scope which corresponds to Opaque-LSA type, periodic * LS flooding should be stopped. */ #endif /* NOTYET */ ; } funclist = ospf_opaque_wildcard_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type9_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type10_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); funclist = ospf_opaque_type11_funclist; opaque_lsa_nsm_change_callback (funclist, nbr, old_state); out: return; } void ospf_opaque_config_write_router (struct vty *vty, struct ospf *ospf) { struct list *funclist; if (CHECK_FLAG (ospf->config, OSPF_OPAQUE_CAPABLE)) vty_out (vty, " capability opaque%s", VTY_NEWLINE); funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_router_callback (funclist, vty); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_router_callback (funclist, vty); return; } void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_if_callback (funclist, vty, ifp); return; } void ospf_opaque_config_write_debug (struct vty *vty) { struct list *funclist; funclist = ospf_opaque_wildcard_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type9_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type10_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); funclist = ospf_opaque_type11_funclist; opaque_lsa_config_write_debug_callback (funclist, vty); return; } void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *) lsa->data; u_int32_t lsid = ntohl (lsah->id.s_addr); u_char opaque_type = GET_OPAQUE_TYPE (lsid); u_int32_t opaque_id = GET_OPAQUE_ID (lsid); struct ospf_opaque_functab *functab; /* Switch output functionality by vty address. */ if (vty != NULL) { vty_out (vty, " Opaque-Type %u (%s)%s", opaque_type, ospf_opaque_type_name (opaque_type), VTY_NEWLINE); vty_out (vty, " Opaque-ID 0x%x%s", opaque_id, VTY_NEWLINE); vty_out (vty, " Opaque-Info: %u octets of data%s%s", ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)", VTY_NEWLINE); } else { zlog_debug (" Opaque-Type %u (%s)", opaque_type, ospf_opaque_type_name (opaque_type)); zlog_debug (" Opaque-ID 0x%x", opaque_id); zlog_debug (" Opaque-Info: %u octets of data%s", ntohs (lsah->length) - OSPF_LSA_HEADER_SIZE, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); } /* Call individual output functions. */ if ((functab = ospf_opaque_functab_lookup (lsa)) != NULL) if (functab->show_opaque_info != NULL) (* functab->show_opaque_info)(vty, lsa); return; } void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length) { struct ospf_lsa lsa; lsa.data = (struct lsa_header *) STREAM_PNT (s); show_opaque_info_detail (NULL, &lsa); return; } static int ospf_opaque_lsa_install_hook (struct ospf_lsa *lsa) { struct list *funclist; int rc = -1; /* * Some Opaque-LSA user may want to monitor every LSA installation * into the LSDB, regardless with target LSA type. */ funclist = ospf_opaque_wildcard_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (new_lsa_callback (funclist, lsa) != 0) goto out; rc = 0; out: return rc; } static int ospf_opaque_lsa_delete_hook (struct ospf_lsa *lsa) { struct list *funclist; int rc = -1; /* * Some Opaque-LSA user may want to monitor every LSA deletion * from the LSDB, regardless with target LSA type. */ funclist = ospf_opaque_wildcard_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type9_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type10_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; funclist = ospf_opaque_type11_funclist; if (del_lsa_callback (funclist, lsa) != 0) goto out; rc = 0; out: return rc; } /*------------------------------------------------------------------------* * Followings are Opaque-LSA origination/refresh management functions. *------------------------------------------------------------------------*/ static int ospf_opaque_type9_lsa_originate (struct thread *t); static int ospf_opaque_type10_lsa_originate (struct thread *t); static int ospf_opaque_type11_lsa_originate (struct thread *t); static void ospf_opaque_lsa_reoriginate_resume (struct list *listtop, void *arg); void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *delay0) { struct ospf *top; struct ospf_area *area; struct listnode *node, *nnode; struct opaque_info_per_type *oipt; int delay = 0; if ((top = oi_to_top (oi)) == NULL || (area = oi->area) == NULL) { zlog_warn ("ospf_opaque_lsa_originate_schedule: Invalid argument?"); goto out; } /* It may not a right time to schedule origination now. */ if (! CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_originate_schedule: Not operational."); goto out; /* This is not an error. */ } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_originate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } if (delay0 != NULL) delay = *delay0; /* * There might be some entries that have been waiting for triggering * of per opaque-type re-origination get resumed. */ ospf_opaque_lsa_reoriginate_resume ( oi->opaque_lsa_self, (void *) oi); ospf_opaque_lsa_reoriginate_resume (area->opaque_lsa_self, (void *) area); ospf_opaque_lsa_reoriginate_resume ( top->opaque_lsa_self, (void *) top); /* * Now, schedule origination of all Opaque-LSAs per opaque-type. */ if (! list_isempty (ospf_opaque_type9_funclist) && list_isempty (oi->opaque_lsa_self) && oi->t_opaque_lsa_self == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-9 Opaque-LSA origination in %d sec later.", delay); oi->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type9_lsa_originate, oi, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type10_funclist) && list_isempty (area->opaque_lsa_self) && area->t_opaque_lsa_self == NULL) { /* * One AREA may contain multiple OIs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-10 Opaque-LSA origination in %d sec later.", delay); area->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type10_lsa_originate, area, delay); delay += OSPF_MIN_LS_INTERVAL; } if (! list_isempty (ospf_opaque_type11_funclist) && list_isempty (top->opaque_lsa_self) && top->t_opaque_lsa_self == NULL) { /* * One OSPF may contain multiple AREAs, but above 2nd and 3rd * conditions prevent from scheduling the originate function * again and again. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-11 Opaque-LSA origination in %d sec later.", delay); top->t_opaque_lsa_self = thread_add_timer (master, ospf_opaque_type11_lsa_originate, top, delay); delay += OSPF_MIN_LS_INTERVAL; } /* * Following section treats a special situation that this node's * opaque capability has changed as "ON -> OFF -> ON". */ if (! list_isempty (ospf_opaque_type9_funclist) && ! list_isempty (oi->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (oi->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) oi, OSPF_OPAQUE_LINK_LSA, oipt->opaque_type); } } if (! list_isempty (ospf_opaque_type10_funclist) && ! list_isempty (area->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (area->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) area, OSPF_OPAQUE_AREA_LSA, oipt->opaque_type); } } if (! list_isempty (ospf_opaque_type11_funclist) && ! list_isempty (top->opaque_lsa_self)) { for (ALL_LIST_ELEMENTS (top->opaque_lsa_self, node, nnode, oipt)) { /* * removed the test for * (! list_isempty (oipt->id_list)) * Handler is already active. * * because opaque cababilities ON -> OFF -> ON result in list_isempty (oipt->id_list) * not being empty. */ if (oipt->t_opaque_lsa_self != NULL /* Waiting for a thread call. */ || oipt->status == PROC_SUSPEND) /* Cannot originate now. */ continue; ospf_opaque_lsa_reoriginate_schedule ((void *) top, OSPF_OPAQUE_AS_LSA, oipt->opaque_type); } } if (delay0 != NULL) *delay0 = delay; out: return; } static int ospf_opaque_type9_lsa_originate (struct thread *t) { struct ospf_interface *oi; int rc; oi = THREAD_ARG (t); oi->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type9-LSA]: Originate Opaque-LSAs for OI %s", IF_NAME (oi)); rc = opaque_lsa_originate_callback (ospf_opaque_type9_funclist, oi); return rc; } static int ospf_opaque_type10_lsa_originate (struct thread *t) { struct ospf_area *area; int rc; area = THREAD_ARG (t); area->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type10-LSA]: Originate Opaque-LSAs for Area %s", inet_ntoa (area->area_id)); rc = opaque_lsa_originate_callback (ospf_opaque_type10_funclist, area); return rc; } static int ospf_opaque_type11_lsa_originate (struct thread *t) { struct ospf *top; int rc; top = THREAD_ARG (t); top->t_opaque_lsa_self = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type11-LSA]: Originate AS-External Opaque-LSAs"); rc = opaque_lsa_originate_callback (ospf_opaque_type11_funclist, top); return rc; } static void ospf_opaque_lsa_reoriginate_resume (struct list *listtop, void *arg) { struct listnode *node, *nnode; struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; if (listtop == NULL) goto out; /* * Pickup oipt entries those which in SUSPEND status, and give * them a chance to start re-origination now. */ for (ALL_LIST_ELEMENTS (listtop, node, nnode, oipt)) { if (oipt->status != PROC_SUSPEND) continue; oipt->status = PROC_NORMAL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) continue; if ((* functab->lsa_originator)(arg) != 0) { zlog_warn ("ospf_opaque_lsa_reoriginate_resume: Failed (opaque-type=%u)", oipt->opaque_type); continue; } } out: return; } struct ospf_lsa * ospf_opaque_lsa_install (struct ospf_lsa *lsa, int rt_recalc) { struct ospf_lsa *new = NULL; struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf *top; /* Don't take "rt_recalc" into consideration for now. *//* XXX */ if (! IS_LSA_SELF (lsa)) { new = lsa; /* Don't touch this LSA. */ goto out; } if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("Install Type-%u Opaque-LSA: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* Replace the existing lsa with the new one. */ if ((oipt = lookup_opaque_info_by_type (lsa)) != NULL && (oipi = lookup_opaque_info_by_id (oipt, lsa)) != NULL) { ospf_lsa_unlock (&oipi->lsa); oipi->lsa = ospf_lsa_lock (lsa); } /* Register the new lsa entry and get its control info. */ else if ((oipi = register_opaque_lsa (lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_install: register_opaque_lsa() ?"); goto out; } /* * Make use of a common mechanism (ospf_lsa_refresh_walker) * for periodic refresh of self-originated Opaque-LSAs. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if ((top = oi_to_top (lsa->oi)) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; case OSPF_OPAQUE_AREA_LSA: if (lsa->area == NULL || (top = lsa->area->ospf) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; case OSPF_OPAQUE_AS_LSA: top = ospf_lookup (); if (lsa->area != NULL && (top = lsa->area->ospf) == NULL) { /* Above conditions must have passed. */ zlog_warn ("ospf_opaque_lsa_install: Sonmething wrong?"); goto out; } break; default: zlog_warn ("ospf_opaque_lsa_install: Unexpected LSA-type(%u)", lsa->data->type); goto out; } ospf_refresher_register_lsa (top, lsa); new = lsa; out: return new; } struct ospf_lsa * ospf_opaque_lsa_refresh (struct ospf_lsa *lsa) { struct ospf *ospf; struct ospf_opaque_functab *functab; struct ospf_lsa *new = NULL; ospf = ospf_lookup (); if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL || functab->lsa_refresher == NULL) { /* * Though this LSA seems to have originated on this node, the * handling module for this "lsa-type and opaque-type" was * already deleted sometime ago. * Anyway, this node still has a responsibility to flush this * LSA from the routing domain. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id)); lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); ospf_lsa_flush (ospf, lsa); } else new = (* functab->lsa_refresher)(lsa); return new; } /*------------------------------------------------------------------------* * Followings are re-origination/refresh/flush operations of Opaque-LSAs, * triggered by external interventions (vty session, signaling, etc). *------------------------------------------------------------------------*/ #define OSPF_OPAQUE_TIMER_ON(T,F,L,V) \ if (!(T)) \ (T) = thread_add_timer (master, (F), (L), (V)) static struct ospf_lsa *pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type); static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t); static int ospf_opaque_lsa_refresh_timer (struct thread *t); void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type) { struct ospf *top; struct ospf_area dummy, *area = NULL; struct ospf_interface *oi = NULL; struct ospf_lsa *lsa; struct opaque_info_per_type *oipt; int (*func) (struct thread * t) = NULL; int delay; switch (lsa_type) { case OSPF_OPAQUE_LINK_LSA: if ((oi = (struct ospf_interface *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-9 Opaque-LSA: Invalid parameter?"); goto out; } if ((top = oi_to_top (oi)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule: OI(%s) -> TOP?", IF_NAME (oi)); goto out; } if (!list_isempty (ospf_opaque_type9_funclist) && list_isempty (oi->opaque_lsa_self) && oi->t_opaque_lsa_self != NULL) { zlog_warn ("Type-9 Opaque-LSA (opaque_type=%u):" " Common origination for OI(%s) has already started", opaque_type, IF_NAME (oi)); goto out; } func = ospf_opaque_type9_lsa_reoriginate_timer; break; case OSPF_OPAQUE_AREA_LSA: if ((area = (struct ospf_area *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-10 Opaque-LSA: Invalid parameter?"); goto out; } if ((top = area->ospf) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " AREA(%s) -> TOP?", inet_ntoa (area->area_id)); goto out; } if (!list_isempty (ospf_opaque_type10_funclist) && list_isempty (area->opaque_lsa_self) && area->t_opaque_lsa_self != NULL) { zlog_warn ("Type-10 Opaque-LSA (opaque_type=%u):" " Common origination for AREA(%s) has already started", opaque_type, inet_ntoa (area->area_id)); goto out; } func = ospf_opaque_type10_lsa_reoriginate_timer; break; case OSPF_OPAQUE_AS_LSA: if ((top = (struct ospf *) lsa_type_dependent) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Type-11 Opaque-LSA: Invalid parameter?"); goto out; } if (!list_isempty (ospf_opaque_type11_funclist) && list_isempty (top->opaque_lsa_self) && top->t_opaque_lsa_self != NULL) { zlog_warn ("Type-11 Opaque-LSA (opaque_type=%u):" " Common origination has already started", opaque_type); goto out; } /* Fake "area" to pass "ospf" to a lookup function later. */ dummy.ospf = top; area = &dummy; func = ospf_opaque_type11_lsa_reoriginate_timer; break; default: zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Unexpected LSA-type(%u)", lsa_type); goto out; } /* It may not a right time to schedule reorigination now. */ if (!CHECK_FLAG (top->opaque, OPAQUE_OPERATION_READY_BIT)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Not operational."); goto out; /* This is not an error. */ } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_opaque_lsa_reoriginate_schedule: Under blockade."); goto out; /* This is not an error, too. */ } /* Generate a dummy lsa to be passed for a lookup function. */ lsa = pseudo_lsa (oi, area, lsa_type, opaque_type); if ((oipt = lookup_opaque_info_by_type (lsa)) == NULL) { struct ospf_opaque_functab *functab; if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " No associated function?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } if ((oipt = register_opaque_info_per_type (functab, lsa)) == NULL) { zlog_warn ("ospf_opaque_lsa_reoriginate_schedule:" " Cannot get a control info?: lsa_type(%u)," " opaque_type(%u)", lsa_type, opaque_type); goto out; } } if (oipt->t_opaque_lsa_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Type-%u Opaque-LSA has already scheduled to" " RE-ORIGINATE: [opaque-type=%u]", lsa_type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); goto out; } /* * Different from initial origination time, in which various conditions * (opaque capability, neighbor status etc) are assured by caller of * the originating function "ospf_opaque_lsa_originate_schedule ()", * it is highly possible that these conditions might not be satisfied * at the time of re-origination function is to be called. */ delay = OSPF_MIN_LS_INTERVAL; /* XXX */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to RE-ORIGINATE in %d" " sec later: [opaque-type=%u]", lsa_type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipt->t_opaque_lsa_self, func, oipt, delay); out: return; } static struct ospf_lsa * pseudo_lsa (struct ospf_interface *oi, struct ospf_area *area, u_char lsa_type, u_char opaque_type) { static struct ospf_lsa lsa = { 0 }; static struct lsa_header lsah = { 0 }; u_int32_t tmp; lsa.oi = oi; lsa.area = area; lsa.data = &lsah; lsah.type = lsa_type; tmp = SET_OPAQUE_LSID (opaque_type, 0); /* Opaque-ID is unused here. */ lsah.id.s_addr = htonl (tmp); return &lsa; } static int ospf_opaque_type9_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; struct ospf_interface *oi; int rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: No associated function?"); goto out; } oi = (struct ospf_interface *) oipt->owner; if ((top = oi_to_top (oi)) == NULL) { zlog_warn ("ospf_opaque_type9_lsa_reoriginate_timer: Something wrong?"); goto out; } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE) || ! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type9-LSA]: Re-originate Opaque-LSAs (opaque-type=%u) for OI (%s)", oipt->opaque_type, IF_NAME (oi)); rc = (* functab->lsa_originator)(oi); out: return rc; } static int ospf_opaque_type10_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct listnode *node, *nnode; struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; int n, rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: No associated function?"); goto out; } area = (struct ospf_area *) oipt->owner; if (area == NULL || (top = area->ospf) == NULL) { zlog_warn ("ospf_opaque_type10_lsa_reoriginate_timer: Something wrong?"); goto out; } /* There must be at least one "opaque-capable, full-state" neighbor. */ n = 0; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) { if ((n = ospf_nbr_count_opaque_capable (oi)) > 0) break; } if (n == 0 || ! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-10 Opaque-LSAs" " (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type10-LSA]: Re-originate Opaque-LSAs" " (opaque-type=%u) for Area %s", oipt->opaque_type, inet_ntoa (area->area_id)); rc = (* functab->lsa_originator)(area); out: return rc; } static int ospf_opaque_type11_lsa_reoriginate_timer (struct thread *t) { struct opaque_info_per_type *oipt; struct ospf_opaque_functab *functab; struct ospf *top; int rc = -1; oipt = THREAD_ARG (t); oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer:" " No associated function?"); goto out; } if ((top = (struct ospf *) oipt->owner) == NULL) { zlog_warn ("ospf_opaque_type11_lsa_reoriginate_timer: Something wrong?"); goto out; } if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Suspend re-origination of Type-11 Opaque-LSAs (opaque-type=%u) for a while...", oipt->opaque_type); oipt->status = PROC_SUSPEND; rc = 0; goto out; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Type11-LSA]: Re-originate Opaque-LSAs (opaque-type=%u).", oipt->opaque_type); rc = (* functab->lsa_originator)(top); out: return rc; } void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa0) { struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; int delay; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) { zlog_warn ("ospf_opaque_lsa_refresh_schedule: Invalid parameter?"); goto out; } /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ if ((lsa = oipi->lsa) == NULL) { zlog_warn ("ospf_opaque_lsa_refresh_schedule: Something wrong?"); goto out; } if (oipi->t_opaque_lsa_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Type-%u Opaque-LSA has already scheduled to REFRESH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); goto out; } /* Delete this lsa from neighbor retransmit-list. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_refresh_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } delay = ospf_lsa_refresh_delay (lsa); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to REFRESH in %d sec later: [opaque-type=%u, opaque-id=%x]", lsa->data->type, delay, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); OSPF_OPAQUE_TIMER_ON (oipi->t_opaque_lsa_self, ospf_opaque_lsa_refresh_timer, oipi, delay); out: return; } static int ospf_opaque_lsa_refresh_timer (struct thread *t) { struct opaque_info_per_id *oipi; struct ospf_opaque_functab *functab; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)"); oipi = THREAD_ARG (t); oipi->t_opaque_lsa_self = NULL; if ((lsa = oipi->lsa) != NULL) if ((functab = oipi->opqctl_type->functab) != NULL) if (functab->lsa_refresher != NULL) (* functab->lsa_refresher)(lsa); return 0; } void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa0) { struct opaque_info_per_type *oipt; struct opaque_info_per_id *oipi; struct ospf_lsa *lsa; if ((oipt = lookup_opaque_info_by_type (lsa0)) == NULL || (oipi = lookup_opaque_info_by_id (oipt, lsa0)) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Invalid parameter?"); goto out; } /* Given "lsa0" and current "oipi->lsa" may different, but harmless. */ if ((lsa = oipi->lsa) == NULL) { zlog_warn ("ospf_opaque_lsa_flush_schedule: Something wrong?"); goto out; } /* Delete this lsa from neighbor retransmit-list. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: ospf_ls_retransmit_delete_nbr_area (lsa->area, lsa); break; case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (lsa0->area->ospf, lsa); break; default: zlog_warn ("ospf_opaque_lsa_flush_schedule: Unexpected LSA-type(%u)", lsa->data->type); goto out; } /* Dequeue listnode entry from the list. */ listnode_delete (oipt->id_list, oipi); /* Avoid misjudgement in the next lookup. */ if (listcount (oipt->id_list) == 0) oipt->id_list->head = oipt->id_list->tail = NULL; /* Disassociate internal control information with the given lsa. */ free_opaque_info_per_id ((void *) oipi); /* Force given lsa's age to MaxAge. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr))); /* This lsa will be flushed and removed eventually. */ ospf_lsa_flush (lsa0->area->ospf, lsa); out: return; } /*------------------------------------------------------------------------* * Followings are control functions to block origination after restart. *------------------------------------------------------------------------*/ static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa); #ifdef BUGGY_UNLOCK static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi); static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area); static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top); static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type); #endif /* BUGGY_UNLOCK */ void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas) { struct ospf *top; struct ospf_area *area; struct ospf_interface *oi; struct listnode *node1, *nnode1; struct listnode *node2, *nnode2; struct ospf_lsa *lsa; if ((top = oi_to_top (nbr->oi)) == NULL) goto out; /* * If an instance of self-originated Opaque-LSA is found in the given * LSA list, and it is not installed to LSDB yet, exclude it from the * list "nbr->ls_req". In this way, it is assured that an LSReq message, * which might be sent in the process of flooding, will not request for * the LSA to be flushed immediately; otherwise, depending on timing, * an LSUpd message will carry instances of target LSAs with MaxAge, * while other LSUpd message might carry old LSA instances (non-MaxAge). * Obviously, the latter would trigger miserable situations that repeat * installation and removal of unwanted LSAs indefinitely. */ for (ALL_LIST_ELEMENTS (lsas, node1, nnode1, lsa)) { /* Filter out unwanted LSAs. */ if (! IS_OPAQUE_LSA (lsa->data->type)) continue; if (! IPV4_ADDR_SAME (&lsa->data->adv_router, &top->router_id)) continue; /* * Don't touch an LSA which has MaxAge; two possible cases. * * 1) This LSA has originally flushed by myself (received LSUpd * message's router-id is equal to my router-id), and flooded * back by an opaque-capable router. * * 2) This LSA has expired in an opaque-capable router and thus * flushed by the router. */ if (IS_LSA_MAXAGE (lsa)) continue; /* If the LSA has installed in the LSDB, nothing to do here. */ if (ospf_lsa_lookup_by_header (nbr->oi->area, lsa->data) != NULL) continue; /* Ok, here we go. */ switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: oi = nbr->oi; ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AREA_LSA: area = nbr->oi->area; for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; case OSPF_OPAQUE_AS_LSA: for (ALL_LIST_ELEMENTS (top->oiflist, node2, nnode2, oi)) ospf_opaque_exclude_lsa_from_lsreq (oi->nbrs, nbr, lsa); break; default: break; } } out: return; } static void ospf_opaque_exclude_lsa_from_lsreq (struct route_table *nbrs, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct route_node *rn; struct ospf_neighbor *onbr; struct ospf_lsa *ls_req; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((onbr = rn->info) == NULL) continue; if (onbr == inbr) continue; if ((ls_req = ospf_ls_request_lookup (onbr, lsa)) == NULL) continue; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[%s]: Exclude this entry from LSReq to send.", dump_lsa_key (lsa)); ospf_ls_request_delete (onbr, ls_req); /* ospf_check_nbr_loading (onbr);*//* XXX */ } return; } void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; u_char before; if ((top = oi_to_top (nbr->oi)) == NULL) return; before = IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque); /* * Since these LSA entries are not yet installed into corresponding * LSDB, just flush them without calling ospf_ls_maxage() afterward. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AREA_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); ospf_flood_through_area (nbr->oi->area, NULL/*inbr*/, lsa); break; case OSPF_OPAQUE_AS_LSA: SET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); ospf_flood_through_as (top, NULL/*inbr*/, lsa); break; default: zlog_warn ("ospf_opaque_self_originated_lsa_received: Unexpected LSA-type(%u)", lsa->data->type); return; } ospf_lsa_discard (lsa); /* List "lsas" will be deleted by caller. */ if (before == 0 && IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: OFF -> ON"); } } void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf *top; int delay; struct ospf_interface *oi; struct listnode *node, *nnode; if ((top = oi_to_top (nbr->oi)) == NULL) return; if (!IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) return; switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT)) UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); /* BUGGY_UNLOCK: ospf_opaque_type9_lsa_rxmt_nbr_check (nbr->oi); */ /* Callback function... */ break; case OSPF_OPAQUE_AREA_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT)) UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); /* BUGGY_UNLOCK: ospf_opaque_type10_lsa_rxmt_nbr_check (nbr->oi->area); */ /* Callback function... */ break; case OSPF_OPAQUE_AS_LSA: if (CHECK_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT)) UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); /* BUGGY_UNLOCK: ospf_opaque_type11_lsa_rxmt_nbr_check (top); */ /* Callback function... */ break; default: zlog_warn ("ospf_opaque_ls_ack_received: Unexpected LSA-type(%u)", lsa->data->type); return; } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (top->opaque)) return; /* Blocking still in progress. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Block Opaque-LSA origination: ON -> OFF"); if (! CHECK_FLAG (top->config, OSPF_OPAQUE_CAPABLE)) return; /* Opaque capability condition must have changed. */ /* Ok, let's start origination of Opaque-LSAs. */ delay = OSPF_MIN_LS_INTERVAL; for (ALL_LIST_ELEMENTS (top->oiflist, node, nnode, oi)) { if (! ospf_if_is_enable (oi) || ospf_nbr_count_opaque_capable (oi) == 0) continue; ospf_opaque_lsa_originate_schedule (oi, &delay); } return; } #ifdef BUGGY_UNLOCK static void ospf_opaque_type9_lsa_rxmt_nbr_check (struct ospf_interface *oi) { unsigned long n; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_LINK_LSA); if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-9 Opaque-LSAs: OI(%s): Flush completed", IF_NAME (oi)); UNSET_FLAG (oi->area->ospf->opaque, OPAQUE_BLOCK_TYPE_09_LSA_BIT); } return; } static void ospf_opaque_type10_lsa_rxmt_nbr_check (struct ospf_area *area) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { if (area->area_id.s_addr != OSPF_AREA_BACKBONE && oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AREA_LSA); if (n > 0) break; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-10 Opaque-LSAs: AREA(%s): Flush completed", inet_ntoa (area->area_id)); UNSET_FLAG (area->ospf->opaque, OPAQUE_BLOCK_TYPE_10_LSA_BIT); } return; } static void ospf_opaque_type11_lsa_rxmt_nbr_check (struct ospf *top) { struct listnode *node; struct ospf_interface *oi; unsigned long n = 0; for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) { switch (oi->type) { case OSPF_IFTYPE_VIRTUALLINK: continue; default: break; } n = ospf_opaque_nrxmt_self (oi->nbrs, OSPF_OPAQUE_AS_LSA); if (n > 0) goto out; } if (n == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Self-originated type-11 Opaque-LSAs: Flush completed"); UNSET_FLAG (top->opaque, OPAQUE_BLOCK_TYPE_11_LSA_BIT); } out: return; } static unsigned long ospf_opaque_nrxmt_self (struct route_table *nbrs, int lsa_type) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf *top; unsigned long n = 0; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((nbr = rn->info) == NULL) continue; if ((top = oi_to_top (nbr->oi)) == NULL) continue; if (IPV4_ADDR_SAME (&nbr->router_id, &top->router_id)) continue; n += ospf_ls_retransmit_count_self (nbr, lsa_type); } return n; } #endif /* BUGGY_UNLOCK */ /*------------------------------------------------------------------------* * Followings are util functions; probably be used by Opaque-LSAs only... *------------------------------------------------------------------------*/ void htonf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = htonl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } void ntohf (float *src, float *dst) { u_int32_t lu1, lu2; memcpy (&lu1, src, sizeof (u_int32_t)); lu2 = ntohl (lu1); memcpy (dst, &lu2, sizeof (u_int32_t)); return; } struct ospf * oi_to_top (struct ospf_interface *oi) { struct ospf *top = NULL; struct ospf_area *area; if (oi == NULL || (area = oi->area) == NULL || (top = area->ospf) == NULL) zlog_warn ("Broken relationship for \"OI -> AREA -> OSPF\"?"); return top; } #endif /* HAVE_OPAQUE_LSA */ quagga-0.99.24.1/ospfd/ospf_snmp.c0000644000175000017500000021636212476520570013531 00000000000000/* OSPFv2 SNMP support * Copyright (C) 2005 6WIND * Copyright (C) 2000 IP Infusion Inc. * * Written by Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "table.h" #include "command.h" #include "memory.h" #include "smux.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_snmp.h" /* OSPF2-MIB. */ #define OSPF2MIB 1,3,6,1,2,1,14 /* OSPF MIB General Group values. */ #define OSPFROUTERID 1 #define OSPFADMINSTAT 2 #define OSPFVERSIONNUMBER 3 #define OSPFAREABDRRTRSTATUS 4 #define OSPFASBDRRTRSTATUS 5 #define OSPFEXTERNLSACOUNT 6 #define OSPFEXTERNLSACKSUMSUM 7 #define OSPFTOSSUPPORT 8 #define OSPFORIGINATENEWLSAS 9 #define OSPFRXNEWLSAS 10 #define OSPFEXTLSDBLIMIT 11 #define OSPFMULTICASTEXTENSIONS 12 #define OSPFEXITOVERFLOWINTERVAL 13 #define OSPFDEMANDEXTENSIONS 14 /* OSPF MIB ospfAreaTable. */ #define OSPFAREAID 1 #define OSPFAUTHTYPE 2 #define OSPFIMPORTASEXTERN 3 #define OSPFSPFRUNS 4 #define OSPFAREABDRRTRCOUNT 5 #define OSPFASBDRRTRCOUNT 6 #define OSPFAREALSACOUNT 7 #define OSPFAREALSACKSUMSUM 8 #define OSPFAREASUMMARY 9 #define OSPFAREASTATUS 10 /* OSPF MIB ospfStubAreaTable. */ #define OSPFSTUBAREAID 1 #define OSPFSTUBTOS 2 #define OSPFSTUBMETRIC 3 #define OSPFSTUBSTATUS 4 #define OSPFSTUBMETRICTYPE 5 /* OSPF MIB ospfLsdbTable. */ #define OSPFLSDBAREAID 1 #define OSPFLSDBTYPE 2 #define OSPFLSDBLSID 3 #define OSPFLSDBROUTERID 4 #define OSPFLSDBSEQUENCE 5 #define OSPFLSDBAGE 6 #define OSPFLSDBCHECKSUM 7 #define OSPFLSDBADVERTISEMENT 8 /* OSPF MIB ospfAreaRangeTable. */ #define OSPFAREARANGEAREAID 1 #define OSPFAREARANGENET 2 #define OSPFAREARANGEMASK 3 #define OSPFAREARANGESTATUS 4 #define OSPFAREARANGEEFFECT 5 /* OSPF MIB ospfHostTable. */ #define OSPFHOSTIPADDRESS 1 #define OSPFHOSTTOS 2 #define OSPFHOSTMETRIC 3 #define OSPFHOSTSTATUS 4 #define OSPFHOSTAREAID 5 /* OSPF MIB ospfIfTable. */ #define OSPFIFIPADDRESS 1 #define OSPFADDRESSLESSIF 2 #define OSPFIFAREAID 3 #define OSPFIFTYPE 4 #define OSPFIFADMINSTAT 5 #define OSPFIFRTRPRIORITY 6 #define OSPFIFTRANSITDELAY 7 #define OSPFIFRETRANSINTERVAL 8 #define OSPFIFHELLOINTERVAL 9 #define OSPFIFRTRDEADINTERVAL 10 #define OSPFIFPOLLINTERVAL 11 #define OSPFIFSTATE 12 #define OSPFIFDESIGNATEDROUTER 13 #define OSPFIFBACKUPDESIGNATEDROUTER 14 #define OSPFIFEVENTS 15 #define OSPFIFAUTHKEY 16 #define OSPFIFSTATUS 17 #define OSPFIFMULTICASTFORWARDING 18 #define OSPFIFDEMAND 19 #define OSPFIFAUTHTYPE 20 /* OSPF MIB ospfIfMetricTable. */ #define OSPFIFMETRICIPADDRESS 1 #define OSPFIFMETRICADDRESSLESSIF 2 #define OSPFIFMETRICTOS 3 #define OSPFIFMETRICVALUE 4 #define OSPFIFMETRICSTATUS 5 /* OSPF MIB ospfVirtIfTable. */ #define OSPFVIRTIFAREAID 1 #define OSPFVIRTIFNEIGHBOR 2 #define OSPFVIRTIFTRANSITDELAY 3 #define OSPFVIRTIFRETRANSINTERVAL 4 #define OSPFVIRTIFHELLOINTERVAL 5 #define OSPFVIRTIFRTRDEADINTERVAL 6 #define OSPFVIRTIFSTATE 7 #define OSPFVIRTIFEVENTS 8 #define OSPFVIRTIFAUTHKEY 9 #define OSPFVIRTIFSTATUS 10 #define OSPFVIRTIFAUTHTYPE 11 /* OSPF MIB ospfNbrTable. */ #define OSPFNBRIPADDR 1 #define OSPFNBRADDRESSLESSINDEX 2 #define OSPFNBRRTRID 3 #define OSPFNBROPTIONS 4 #define OSPFNBRPRIORITY 5 #define OSPFNBRSTATE 6 #define OSPFNBREVENTS 7 #define OSPFNBRLSRETRANSQLEN 8 #define OSPFNBMANBRSTATUS 9 #define OSPFNBMANBRPERMANENCE 10 #define OSPFNBRHELLOSUPPRESSED 11 /* OSPF MIB ospfVirtNbrTable. */ #define OSPFVIRTNBRAREA 1 #define OSPFVIRTNBRRTRID 2 #define OSPFVIRTNBRIPADDR 3 #define OSPFVIRTNBROPTIONS 4 #define OSPFVIRTNBRSTATE 5 #define OSPFVIRTNBREVENTS 6 #define OSPFVIRTNBRLSRETRANSQLEN 7 #define OSPFVIRTNBRHELLOSUPPRESSED 8 /* OSPF MIB ospfExtLsdbTable. */ #define OSPFEXTLSDBTYPE 1 #define OSPFEXTLSDBLSID 2 #define OSPFEXTLSDBROUTERID 3 #define OSPFEXTLSDBSEQUENCE 4 #define OSPFEXTLSDBAGE 5 #define OSPFEXTLSDBCHECKSUM 6 #define OSPFEXTLSDBADVERTISEMENT 7 /* OSPF MIB ospfAreaAggregateTable. */ #define OSPFAREAAGGREGATEAREAID 1 #define OSPFAREAAGGREGATELSDBTYPE 2 #define OSPFAREAAGGREGATENET 3 #define OSPFAREAAGGREGATEMASK 4 #define OSPFAREAAGGREGATESTATUS 5 #define OSPFAREAAGGREGATEEFFECT 6 /* SYNTAX Status from OSPF-MIB. */ #define OSPF_STATUS_ENABLED 1 #define OSPF_STATUS_DISABLED 2 /* SNMP value hack. */ #define COUNTER ASN_COUNTER #define INTEGER ASN_INTEGER #define GAUGE ASN_GAUGE #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES /* OSPF-MIB instances. */ oid ospf_oid [] = { OSPF2MIB }; oid ospf_trap_oid [] = { OSPF2MIB, 16, 2 }; /* Not reverse mappable! */ /* IP address 0.0.0.0. */ static struct in_addr ospf_empty_addr = {0}; /* Hook functions. */ static u_char *ospfGeneralGroup (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfStubAreaEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaRangeEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfHostEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfIfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfIfMetricEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfVirtIfEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfNbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfVirtNbrEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfExtLsdbEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); static u_char *ospfAreaAggregateEntry (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **); struct variable ospf_variables[] = { /* OSPF general variables */ {OSPFROUTERID, IPADDRESS, RWRITE, ospfGeneralGroup, 2, {1, 1}}, {OSPFADMINSTAT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 2}}, {OSPFVERSIONNUMBER, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 3}}, {OSPFAREABDRRTRSTATUS, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 4}}, {OSPFASBDRRTRSTATUS, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 5}}, {OSPFEXTERNLSACOUNT, GAUGE, RONLY, ospfGeneralGroup, 2, {1, 6}}, {OSPFEXTERNLSACKSUMSUM, INTEGER, RONLY, ospfGeneralGroup, 2, {1, 7}}, {OSPFTOSSUPPORT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 8}}, {OSPFORIGINATENEWLSAS, COUNTER, RONLY, ospfGeneralGroup, 2, {1, 9}}, {OSPFRXNEWLSAS, COUNTER, RONLY, ospfGeneralGroup, 2, {1, 10}}, {OSPFEXTLSDBLIMIT, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 11}}, {OSPFMULTICASTEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 12}}, {OSPFEXITOVERFLOWINTERVAL, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 13}}, {OSPFDEMANDEXTENSIONS, INTEGER, RWRITE, ospfGeneralGroup, 2, {1, 14}}, /* OSPF area data structure. */ {OSPFAREAID, IPADDRESS, RONLY, ospfAreaEntry, 3, {2, 1, 1}}, {OSPFAUTHTYPE, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 2}}, {OSPFIMPORTASEXTERN, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 3}}, {OSPFSPFRUNS, COUNTER, RONLY, ospfAreaEntry, 3, {2, 1, 4}}, {OSPFAREABDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 5}}, {OSPFASBDRRTRCOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 6}}, {OSPFAREALSACOUNT, GAUGE, RONLY, ospfAreaEntry, 3, {2, 1, 7}}, {OSPFAREALSACKSUMSUM, INTEGER, RONLY, ospfAreaEntry, 3, {2, 1, 8}}, {OSPFAREASUMMARY, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 9}}, {OSPFAREASTATUS, INTEGER, RWRITE, ospfAreaEntry, 3, {2, 1, 10}}, /* OSPF stub area information. */ {OSPFSTUBAREAID, IPADDRESS, RONLY, ospfStubAreaEntry, 3, {3, 1, 1}}, {OSPFSTUBTOS, INTEGER, RONLY, ospfStubAreaEntry, 3, {3, 1, 2}}, {OSPFSTUBMETRIC, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 3}}, {OSPFSTUBSTATUS, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 4}}, {OSPFSTUBMETRICTYPE, INTEGER, RWRITE, ospfStubAreaEntry, 3, {3, 1, 5}}, /* OSPF link state database. */ {OSPFLSDBAREAID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 1}}, {OSPFLSDBTYPE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 2}}, {OSPFLSDBLSID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 3}}, {OSPFLSDBROUTERID, IPADDRESS, RONLY, ospfLsdbEntry, 3, {4, 1, 4}}, {OSPFLSDBSEQUENCE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 5}}, {OSPFLSDBAGE, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 6}}, {OSPFLSDBCHECKSUM, INTEGER, RONLY, ospfLsdbEntry, 3, {4, 1, 7}}, {OSPFLSDBADVERTISEMENT, STRING, RONLY, ospfLsdbEntry, 3, {4, 1, 8}}, /* Area range table. */ {OSPFAREARANGEAREAID, IPADDRESS, RONLY, ospfAreaRangeEntry, 3, {5, 1, 1}}, {OSPFAREARANGENET, IPADDRESS, RONLY, ospfAreaRangeEntry, 3, {5, 1, 2}}, {OSPFAREARANGEMASK, IPADDRESS, RWRITE, ospfAreaRangeEntry, 3, {5, 1, 3}}, {OSPFAREARANGESTATUS, INTEGER, RWRITE, ospfAreaRangeEntry, 3, {5, 1, 4}}, {OSPFAREARANGEEFFECT, INTEGER, RWRITE, ospfAreaRangeEntry, 3, {5, 1, 5}}, /* OSPF host table. */ {OSPFHOSTIPADDRESS, IPADDRESS, RONLY, ospfHostEntry, 3, {6, 1, 1}}, {OSPFHOSTTOS, INTEGER, RONLY, ospfHostEntry, 3, {6, 1, 2}}, {OSPFHOSTMETRIC, INTEGER, RWRITE, ospfHostEntry, 3, {6, 1, 3}}, {OSPFHOSTSTATUS, INTEGER, RWRITE, ospfHostEntry, 3, {6, 1, 4}}, {OSPFHOSTAREAID, IPADDRESS, RONLY, ospfHostEntry, 3, {6, 1, 5}}, /* OSPF interface table. */ {OSPFIFIPADDRESS, IPADDRESS, RONLY, ospfIfEntry, 3, {7, 1, 1}}, {OSPFADDRESSLESSIF, INTEGER, RONLY, ospfIfEntry, 3, {7, 1, 2}}, {OSPFIFAREAID, IPADDRESS, RWRITE, ospfIfEntry, 3, {7, 1, 3}}, {OSPFIFTYPE, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 4}}, {OSPFIFADMINSTAT, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 5}}, {OSPFIFRTRPRIORITY, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 6}}, {OSPFIFTRANSITDELAY, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 7}}, {OSPFIFRETRANSINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 8}}, {OSPFIFHELLOINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 9}}, {OSPFIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 10}}, {OSPFIFPOLLINTERVAL, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 11}}, {OSPFIFSTATE, INTEGER, RONLY, ospfIfEntry, 3, {7, 1, 12}}, {OSPFIFDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, 3, {7, 1, 13}}, {OSPFIFBACKUPDESIGNATEDROUTER, IPADDRESS, RONLY, ospfIfEntry, 3, {7, 1, 14}}, {OSPFIFEVENTS, COUNTER, RONLY, ospfIfEntry, 3, {7, 1, 15}}, {OSPFIFAUTHKEY, STRING, RWRITE, ospfIfEntry, 3, {7, 1, 16}}, {OSPFIFSTATUS, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 17}}, {OSPFIFMULTICASTFORWARDING, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 18}}, {OSPFIFDEMAND, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 19}}, {OSPFIFAUTHTYPE, INTEGER, RWRITE, ospfIfEntry, 3, {7, 1, 20}}, /* OSPF interface metric table. */ {OSPFIFMETRICIPADDRESS, IPADDRESS, RONLY, ospfIfMetricEntry, 3, {8, 1, 1}}, {OSPFIFMETRICADDRESSLESSIF, INTEGER, RONLY, ospfIfMetricEntry, 3, {8, 1, 2}}, {OSPFIFMETRICTOS, INTEGER, RONLY, ospfIfMetricEntry, 3, {8, 1, 3}}, {OSPFIFMETRICVALUE, INTEGER, RWRITE, ospfIfMetricEntry, 3, {8, 1, 4}}, {OSPFIFMETRICSTATUS, INTEGER, RWRITE, ospfIfMetricEntry, 3, {8, 1, 5}}, /* OSPF virtual interface table. */ {OSPFVIRTIFAREAID, IPADDRESS, RONLY, ospfVirtIfEntry, 3, {9, 1, 1}}, {OSPFVIRTIFNEIGHBOR, IPADDRESS, RONLY, ospfVirtIfEntry, 3, {9, 1, 2}}, {OSPFVIRTIFTRANSITDELAY, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 3}}, {OSPFVIRTIFRETRANSINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 4}}, {OSPFVIRTIFHELLOINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 5}}, {OSPFVIRTIFRTRDEADINTERVAL, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 6}}, {OSPFVIRTIFSTATE, INTEGER, RONLY, ospfVirtIfEntry, 3, {9, 1, 7}}, {OSPFVIRTIFEVENTS, COUNTER, RONLY, ospfVirtIfEntry, 3, {9, 1, 8}}, {OSPFVIRTIFAUTHKEY, STRING, RWRITE, ospfVirtIfEntry, 3, {9, 1, 9}}, {OSPFVIRTIFSTATUS, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 10}}, {OSPFVIRTIFAUTHTYPE, INTEGER, RWRITE, ospfVirtIfEntry, 3, {9, 1, 11}}, /* OSPF neighbor table. */ {OSPFNBRIPADDR, IPADDRESS, RONLY, ospfNbrEntry, 3, {10, 1, 1}}, {OSPFNBRADDRESSLESSINDEX, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 2}}, {OSPFNBRRTRID, IPADDRESS, RONLY, ospfNbrEntry, 3, {10, 1, 3}}, {OSPFNBROPTIONS, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 4}}, {OSPFNBRPRIORITY, INTEGER, RWRITE, ospfNbrEntry, 3, {10, 1, 5}}, {OSPFNBRSTATE, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 6}}, {OSPFNBREVENTS, COUNTER, RONLY, ospfNbrEntry, 3, {10, 1, 7}}, {OSPFNBRLSRETRANSQLEN, GAUGE, RONLY, ospfNbrEntry, 3, {10, 1, 8}}, {OSPFNBMANBRSTATUS, INTEGER, RWRITE, ospfNbrEntry, 3, {10, 1, 9}}, {OSPFNBMANBRPERMANENCE, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 10}}, {OSPFNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfNbrEntry, 3, {10, 1, 11}}, /* OSPF virtual neighbor table. */ {OSPFVIRTNBRAREA, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 1}}, {OSPFVIRTNBRRTRID, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 2}}, {OSPFVIRTNBRIPADDR, IPADDRESS, RONLY, ospfVirtNbrEntry, 3, {11, 1, 3}}, {OSPFVIRTNBROPTIONS, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 4}}, {OSPFVIRTNBRSTATE, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 5}}, {OSPFVIRTNBREVENTS, COUNTER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 6}}, {OSPFVIRTNBRLSRETRANSQLEN, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 7}}, {OSPFVIRTNBRHELLOSUPPRESSED, INTEGER, RONLY, ospfVirtNbrEntry, 3, {11, 1, 8}}, /* OSPF link state database, external. */ {OSPFEXTLSDBTYPE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 1}}, {OSPFEXTLSDBLSID, IPADDRESS, RONLY, ospfExtLsdbEntry, 3, {12, 1, 2}}, {OSPFEXTLSDBROUTERID, IPADDRESS, RONLY, ospfExtLsdbEntry, 3, {12, 1, 3}}, {OSPFEXTLSDBSEQUENCE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 4}}, {OSPFEXTLSDBAGE, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 5}}, {OSPFEXTLSDBCHECKSUM, INTEGER, RONLY, ospfExtLsdbEntry, 3, {12, 1, 6}}, {OSPFEXTLSDBADVERTISEMENT, STRING, RONLY, ospfExtLsdbEntry, 3, {12, 1, 7}}, /* OSPF area aggregate table. */ {OSPFAREAAGGREGATEAREAID, IPADDRESS, RONLY, ospfAreaAggregateEntry, 3, {14, 1, 1}}, {OSPFAREAAGGREGATELSDBTYPE, INTEGER, RONLY, ospfAreaAggregateEntry, 3, {14, 1, 2}}, {OSPFAREAAGGREGATENET, IPADDRESS, RONLY, ospfAreaAggregateEntry, 3, {14, 1, 3}}, {OSPFAREAAGGREGATEMASK, IPADDRESS, RONLY, ospfAreaAggregateEntry, 3, {14, 1, 4}}, {OSPFAREAAGGREGATESTATUS, INTEGER, RWRITE, ospfAreaAggregateEntry, 3, {14, 1, 5}}, {OSPFAREAAGGREGATEEFFECT, INTEGER, RWRITE, ospfAreaAggregateEntry, 3, {14, 1, 6}} }; /* The administrative status of OSPF. When OSPF is enbled on at least one interface return 1. */ static int ospf_admin_stat (struct ospf *ospf) { struct listnode *node; struct ospf_interface *oi; if (ospf == NULL) return 0; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (oi && oi->address) return 1; return 0; } static u_char * ospfGeneralGroup (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf *ospf; ospf = ospf_lookup (); /* Check whether the instance identifier is valid */ if (smux_header_generic (v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFROUTERID: /* 1 */ /* Router-ID of this OSPF instance. */ if (ospf) return SNMP_IPADDRESS (ospf->router_id); else return SNMP_IPADDRESS (ospf_empty_addr); break; case OSPFADMINSTAT: /* 2 */ /* The administrative status of OSPF in the router. */ if (ospf_admin_stat (ospf)) return SNMP_INTEGER (OSPF_STATUS_ENABLED); else return SNMP_INTEGER (OSPF_STATUS_DISABLED); break; case OSPFVERSIONNUMBER: /* 3 */ /* OSPF version 2. */ return SNMP_INTEGER (OSPF_VERSION); break; case OSPFAREABDRRTRSTATUS: /* 4 */ /* Area Border router status. */ if (ospf && CHECK_FLAG (ospf->flags, OSPF_FLAG_ABR)) return SNMP_INTEGER (SNMP_TRUE); else return SNMP_INTEGER (SNMP_FALSE); break; case OSPFASBDRRTRSTATUS: /* 5 */ /* AS Border router status. */ if (ospf && CHECK_FLAG (ospf->flags, OSPF_FLAG_ASBR)) return SNMP_INTEGER (SNMP_TRUE); else return SNMP_INTEGER (SNMP_FALSE); break; case OSPFEXTERNLSACOUNT: /* 6 */ /* External LSA counts. */ if (ospf) return SNMP_INTEGER (ospf_lsdb_count_all (ospf->lsdb)); else return SNMP_INTEGER (0); break; case OSPFEXTERNLSACKSUMSUM: /* 7 */ /* External LSA checksum. */ return SNMP_INTEGER (0); break; case OSPFTOSSUPPORT: /* 8 */ /* TOS is not supported. */ return SNMP_INTEGER (SNMP_FALSE); break; case OSPFORIGINATENEWLSAS: /* 9 */ /* The number of new link-state advertisements. */ if (ospf) return SNMP_INTEGER (ospf->lsa_originate_count); else return SNMP_INTEGER (0); break; case OSPFRXNEWLSAS: /* 10 */ /* The number of link-state advertisements received determined to be new instantiations. */ if (ospf) return SNMP_INTEGER (ospf->rx_lsa_count); else return SNMP_INTEGER (0); break; case OSPFEXTLSDBLIMIT: /* 11 */ /* There is no limit for the number of non-default AS-external-LSAs. */ return SNMP_INTEGER (-1); break; case OSPFMULTICASTEXTENSIONS: /* 12 */ /* Multicast Extensions to OSPF is not supported. */ return SNMP_INTEGER (0); break; case OSPFEXITOVERFLOWINTERVAL: /* 13 */ /* Overflow is not supported. */ return SNMP_INTEGER (0); break; case OSPFDEMANDEXTENSIONS: /* 14 */ /* Demand routing is not supported. */ return SNMP_INTEGER (SNMP_FALSE); break; default: return NULL; } return NULL; } static struct ospf_area * ospf_area_lookup_next (struct ospf *ospf, struct in_addr *area_id, int first) { struct ospf_area *area; struct listnode *node; if (ospf == NULL) return NULL; if (first) { node = listhead (ospf->areas); if (node) { area = listgetdata (node); *area_id = area->area_id; return area; } return NULL; } for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) { *area_id = area->area_id; return area; } } return NULL; } static struct ospf_area * ospfAreaLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct ospf *ospf; struct ospf_area *area; int len; ospf = ospf_lookup (); if (ospf == NULL) return NULL; if (exact) { /* Length is insufficient to lookup OSPF area. */ if (*length - v->namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); area = ospf_area_lookup_by_area_id (ospf, *addr); return area; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); area = ospf_area_lookup_next (ospf, addr, len == 0 ? 1 : 0); if (area == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); *length = sizeof (struct in_addr) + v->namelen; return area; } return NULL; } static u_char * ospfAreaEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_area *area; struct in_addr addr; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); area = ospfAreaLookup (v, name, length, &addr, exact); if (! area) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFAREAID: /* 1 */ return SNMP_IPADDRESS (area->area_id); break; case OSPFAUTHTYPE: /* 2 */ return SNMP_INTEGER (area->auth_type); break; case OSPFIMPORTASEXTERN: /* 3 */ return SNMP_INTEGER (area->external_routing + 1); break; case OSPFSPFRUNS: /* 4 */ return SNMP_INTEGER (area->spf_calculation); break; case OSPFAREABDRRTRCOUNT: /* 5 */ return SNMP_INTEGER (area->abr_count); break; case OSPFASBDRRTRCOUNT: /* 6 */ return SNMP_INTEGER (area->asbr_count); break; case OSPFAREALSACOUNT: /* 7 */ return SNMP_INTEGER (area->lsdb->total); break; case OSPFAREALSACKSUMSUM: /* 8 */ return SNMP_INTEGER (0); break; case OSPFAREASUMMARY: /* 9 */ #define OSPF_noAreaSummary 1 #define OSPF_sendAreaSummary 2 if (area->no_summary) return SNMP_INTEGER (OSPF_noAreaSummary); else return SNMP_INTEGER (OSPF_sendAreaSummary); break; case OSPFAREASTATUS: /* 10 */ return SNMP_INTEGER (SNMP_VALID); break; default: return NULL; break; } return NULL; } static struct ospf_area * ospf_stub_area_lookup_next (struct in_addr *area_id, int first) { struct ospf_area *area; struct listnode *node; struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (area->external_routing == OSPF_AREA_STUB) { if (first) { *area_id = area->area_id; return area; } else if (ntohl (area->area_id.s_addr) > ntohl (area_id->s_addr)) { *area_id = area->area_id; return area; } } } return NULL; } static struct ospf_area * ospfStubAreaLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct ospf *ospf; struct ospf_area *area; int len; ospf = ospf_lookup (); if (ospf == NULL) return NULL; /* Exact lookup. */ if (exact) { /* ospfStubAreaID + ospfStubTOS. */ if (*length != v->namelen + sizeof (struct in_addr) + 1) return NULL; /* Check ospfStubTOS is zero. */ if (name[*length - 1] != 0) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); area = ospf_area_lookup_by_area_id (ospf, *addr); if (area->external_routing == OSPF_AREA_STUB) return area; else return NULL; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); area = ospf_stub_area_lookup_next (addr, len == 0 ? 1 : 0); if (area == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); /* Set TOS 0. */ name[v->namelen + sizeof (struct in_addr)] = 0; *length = v->namelen + sizeof (struct in_addr) + 1; return area; } return NULL; } static u_char * ospfStubAreaEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_area *area; struct in_addr addr; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); area = ospfStubAreaLookup (v, name, length, &addr, exact); if (! area) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFSTUBAREAID: /* 1 */ /* OSPF stub area id. */ return SNMP_IPADDRESS (area->area_id); break; case OSPFSTUBTOS: /* 2 */ /* TOS value is not supported. */ return SNMP_INTEGER (0); break; case OSPFSTUBMETRIC: /* 3 */ /* Default cost to stub area. */ return SNMP_INTEGER (area->default_cost); break; case OSPFSTUBSTATUS: /* 4 */ /* Status of the stub area. */ return SNMP_INTEGER (SNMP_VALID); break; case OSPFSTUBMETRICTYPE: /* 5 */ /* OSPF Metric type. */ #define OSPF_ospfMetric 1 #define OSPF_comparableCost 2 #define OSPF_nonComparable 3 return SNMP_INTEGER (OSPF_ospfMetric); break; default: return NULL; break; } return NULL; } static struct ospf_lsa * lsdb_lookup_next (struct ospf_area *area, u_char *type, int type_next, struct in_addr *ls_id, int ls_id_next, struct in_addr *router_id, int router_id_next) { struct ospf_lsa *lsa; int i; if (type_next) i = OSPF_MIN_LSA; else i = *type; /* Sanity check, if LSA type unknwon merley skip any LSA */ if ((i < OSPF_MIN_LSA) || (i >= OSPF_MAX_LSA)) { zlog_debug("Strange request with LSA type %d\n", i); return NULL; } for (; i < OSPF_MAX_LSA; i++) { *type = i; lsa = ospf_lsdb_lookup_by_id_next (area->lsdb, *type, *ls_id, *router_id, ls_id_next); if (lsa) return lsa; ls_id_next = 1; } return NULL; } static struct ospf_lsa * ospfLsdbLookup (struct variable *v, oid *name, size_t *length, struct in_addr *area_id, u_char *type, struct in_addr *ls_id, struct in_addr *router_id, int exact) { struct ospf *ospf; struct ospf_area *area; struct ospf_lsa *lsa; int len; int type_next; int ls_id_next; int router_id_next; oid *offset; int offsetlen; ospf = ospf_lookup (); #define OSPF_LSDB_ENTRY_OFFSET \ (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) if (exact) { /* Area ID + Type + LS ID + Router ID. */ if (*length - v->namelen != OSPF_LSDB_ENTRY_OFFSET) return NULL; /* Set OID offset for Area ID. */ offset = name + v->namelen; /* Lookup area first. */ oid2in_addr (offset, IN_ADDR_SIZE, area_id); area = ospf_area_lookup_by_area_id (ospf, *area_id); if (! area) return NULL; offset += IN_ADDR_SIZE; /* Type. */ *type = *offset; offset++; /* LS ID. */ oid2in_addr (offset, IN_ADDR_SIZE, ls_id); offset += IN_ADDR_SIZE; /* Router ID. */ oid2in_addr (offset, IN_ADDR_SIZE, router_id); /* Lookup LSDB. */ return ospf_lsdb_lookup_by_id (area->lsdb, *type, *ls_id, *router_id); } else { /* Get variable length. */ offset = name + v->namelen; offsetlen = *length - v->namelen; len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, area_id); /* First we search area. */ if (len == IN_ADDR_SIZE) area = ospf_area_lookup_by_area_id (ospf, *area_id); else area = ospf_area_lookup_next (ospf, area_id, 1); if (area == NULL) return NULL; do { /* Next we lookup type. */ offset += len; offsetlen -= len; len = offsetlen; if (len <= 0) type_next = 1; else { len = 1; type_next = 0; *type = *offset; } /* LS ID. */ offset++; offsetlen--; len = offsetlen; if (len <= 0) ls_id_next = 1; else { ls_id_next = 0; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, ls_id); } /* Router ID. */ offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; if (len <= 0) router_id_next = 1; else { router_id_next = 0; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, router_id); } lsa = lsdb_lookup_next (area, type, type_next, ls_id, ls_id_next, router_id, router_id_next); if (lsa) { /* Fill in length. */ *length = v->namelen + OSPF_LSDB_ENTRY_OFFSET; /* Fill in value. */ offset = name + v->namelen; oid_copy_addr (offset, area_id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = lsa->data->type; offset++; oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); return lsa; } } while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); } return NULL; } static u_char * ospfLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_lsa *lsa; struct lsa_header *lsah; struct in_addr area_id; u_char type; struct in_addr ls_id; struct in_addr router_id; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* INDEX { ospfLsdbAreaId, ospfLsdbType, ospfLsdbLsid, ospfLsdbRouterId } */ memset (&area_id, 0, sizeof (struct in_addr)); type = 0; memset (&ls_id, 0, sizeof (struct in_addr)); memset (&router_id, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; lsa = ospfLsdbLookup (v, name, length, &area_id, &type, &ls_id, &router_id, exact); if (! lsa) return NULL; lsah = lsa->data; /* Return the current value of the variable */ switch (v->magic) { case OSPFLSDBAREAID: /* 1 */ return SNMP_IPADDRESS (lsa->area->area_id); break; case OSPFLSDBTYPE: /* 2 */ return SNMP_INTEGER (lsah->type); break; case OSPFLSDBLSID: /* 3 */ return SNMP_IPADDRESS (lsah->id); break; case OSPFLSDBROUTERID: /* 4 */ return SNMP_IPADDRESS (lsah->adv_router); break; case OSPFLSDBSEQUENCE: /* 5 */ return SNMP_INTEGER (lsah->ls_seqnum); break; case OSPFLSDBAGE: /* 6 */ return SNMP_INTEGER (lsah->ls_age); break; case OSPFLSDBCHECKSUM: /* 7 */ return SNMP_INTEGER (lsah->checksum); break; case OSPFLSDBADVERTISEMENT: /* 8 */ *var_len = ntohs (lsah->length); return (u_char *) lsah; break; default: return NULL; break; } return NULL; } static struct ospf_area_range * ospfAreaRangeLookup (struct variable *v, oid *name, size_t *length, struct in_addr *area_id, struct in_addr *range_net, int exact) { oid *offset; int offsetlen; unsigned int len; struct ospf *ospf; struct ospf_area *area; struct ospf_area_range *range; struct prefix_ipv4 p; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; ospf = ospf_lookup (); if (exact) { /* Area ID + Range Network. */ if (v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE != *length) return NULL; /* Set OID offset for Area ID. */ offset = name + v->namelen; /* Lookup area first. */ oid2in_addr (offset, IN_ADDR_SIZE, area_id); area = ospf_area_lookup_by_area_id (ospf, *area_id); if (! area) return NULL; offset += IN_ADDR_SIZE; /* Lookup area range. */ oid2in_addr (offset, IN_ADDR_SIZE, range_net); p.prefix = *range_net; return ospf_area_range_lookup (area, &p); } else { /* Set OID offset for Area ID. */ offset = name + v->namelen; offsetlen = *length - v->namelen; len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, area_id); /* First we search area. */ if (len == IN_ADDR_SIZE) area = ospf_area_lookup_by_area_id (ospf,*area_id); else area = ospf_area_lookup_next (ospf, area_id, len == 0 ? 1 : 0); if (area == NULL) return NULL; do { offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; len = offsetlen; if (len < 0) len = 0; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, range_net); range = ospf_area_range_lookup_next (area, range_net, len == 0 ? 1 : 0); if (range) { /* Fill in length. */ *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; /* Fill in value. */ offset = name + v->namelen; oid_copy_addr (offset, area_id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, range_net, IN_ADDR_SIZE); return range; } } while ((area = ospf_area_lookup_next (ospf, area_id, 0)) != NULL); } return NULL; } static u_char * ospfAreaRangeEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_area_range *range; struct in_addr area_id; struct in_addr range_net; struct in_addr mask; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; memset (&area_id, 0, IN_ADDR_SIZE); memset (&range_net, 0, IN_ADDR_SIZE); range = ospfAreaRangeLookup (v, name, length, &area_id, &range_net, exact); if (! range) return NULL; /* Convert prefixlen to network mask format. */ masklen2ip (range->subst_masklen, &mask); /* Return the current value of the variable */ switch (v->magic) { case OSPFAREARANGEAREAID: /* 1 */ return SNMP_IPADDRESS (area_id); break; case OSPFAREARANGENET: /* 2 */ return SNMP_IPADDRESS (range_net); break; case OSPFAREARANGEMASK: /* 3 */ return SNMP_IPADDRESS (mask); break; case OSPFAREARANGESTATUS: /* 4 */ return SNMP_INTEGER (SNMP_VALID); break; case OSPFAREARANGEEFFECT: /* 5 */ #define OSPF_advertiseMatching 1 #define OSPF_doNotAdvertiseMatching 2 return SNMP_INTEGER (OSPF_advertiseMatching); break; default: return NULL; break; } return NULL; } static struct ospf_nbr_nbma * ospfHostLookup (struct variable *v, oid *name, size_t *length, struct in_addr *addr, int exact) { int len; struct ospf_nbr_nbma *nbr_nbma; struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) return NULL; if (exact) { /* INDEX { ospfHostIpAddress, ospfHostTOS } */ if (*length != v->namelen + IN_ADDR_SIZE + 1) return NULL; /* Check ospfHostTOS. */ if (name[*length - 1] != 0) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); nbr_nbma = ospf_nbr_nbma_lookup (ospf, *addr); return nbr_nbma; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); nbr_nbma = ospf_nbr_nbma_lookup_next (ospf, addr, len == 0 ? 1 : 0); if (nbr_nbma == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, IN_ADDR_SIZE); /* Set TOS 0. */ name[v->namelen + IN_ADDR_SIZE] = 0; *length = v->namelen + IN_ADDR_SIZE + 1; return nbr_nbma; } return NULL; } static u_char * ospfHostEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_nbr_nbma *nbr_nbma; struct ospf_interface *oi; struct in_addr addr; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; memset (&addr, 0, sizeof (struct in_addr)); nbr_nbma = ospfHostLookup (v, name, length, &addr, exact); if (nbr_nbma == NULL) return NULL; oi = nbr_nbma->oi; /* Return the current value of the variable */ switch (v->magic) { case OSPFHOSTIPADDRESS: /* 1 */ return SNMP_IPADDRESS (nbr_nbma->addr); break; case OSPFHOSTTOS: /* 2 */ return SNMP_INTEGER (0); break; case OSPFHOSTMETRIC: /* 3 */ if (oi) return SNMP_INTEGER (oi->output_cost); else return SNMP_INTEGER (1); break; case OSPFHOSTSTATUS: /* 4 */ return SNMP_INTEGER (SNMP_VALID); break; case OSPFHOSTAREAID: /* 5 */ if (oi && oi->area) return SNMP_IPADDRESS (oi->area->area_id); else return SNMP_IPADDRESS (ospf_empty_addr); break; default: return NULL; break; } return NULL; } struct list *ospf_snmp_iflist; struct ospf_snmp_if { struct in_addr addr; unsigned int ifindex; struct interface *ifp; }; static struct ospf_snmp_if * ospf_snmp_if_new (void) { return XCALLOC (0, sizeof (struct ospf_snmp_if)); } static void ospf_snmp_if_free (struct ospf_snmp_if *osif) { XFREE (0, osif); } void ospf_snmp_if_delete (struct interface *ifp) { struct listnode *node, *nnode; struct ospf_snmp_if *osif; for (ALL_LIST_ELEMENTS (ospf_snmp_iflist, node, nnode, osif)) { if (osif->ifp == ifp) { list_delete_node (ospf_snmp_iflist, node); ospf_snmp_if_free (osif); return; } } } void ospf_snmp_if_update (struct interface *ifp) { struct listnode *node; struct listnode *pn; struct connected *ifc; struct prefix *p; struct ospf_snmp_if *osif; struct in_addr *addr; unsigned int ifindex; ospf_snmp_if_delete (ifp); p = NULL; addr = NULL; ifindex = 0; /* Lookup first IPv4 address entry. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { p = CONNECTED_ID(ifc); if (p->family == AF_INET) { addr = &p->u.prefix4; break; } } if (! addr) ifindex = ifp->ifindex; /* Add interface to the list. */ pn = NULL; for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, node, osif)) { if (addr) { /* Usual interfaces --> Sort them based on interface IPv4 addresses */ if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr)) break; } else { /* Unnumbered interfaces --> Sort them based on interface indexes */ if (osif->addr.s_addr != 0 || osif->ifindex > ifindex) break; } pn = node; } osif = ospf_snmp_if_new (); if (addr) /* Usual interface */ { osif->addr = *addr; /* This field is used for storing ospfAddressLessIf OID value, * conform to RFC1850 OSPF-MIB specification, it must be 0 for * usual interface */ osif->ifindex = 0; } else /* Unnumbered interface */ osif->ifindex = ifindex; osif->ifp = ifp; listnode_add_after (ospf_snmp_iflist, pn, osif); } static int ospf_snmp_is_if_have_addr (struct interface *ifp) { struct listnode *nn; struct connected *ifc; /* Is this interface having any connected IPv4 address ? */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, ifc)) { if (CONNECTED_PREFIX(ifc)->family == AF_INET) return 1; } return 0; } static struct ospf_interface * ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex) { struct listnode *node; struct ospf_snmp_if *osif; struct ospf_interface *oi = NULL; struct ospf *ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, node, osif)) { if (ifaddr->s_addr) { if (IPV4_ADDR_SAME (&osif->addr, ifaddr)) oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); } else { if (osif->ifindex == *ifindex) oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); } } return oi; } static struct ospf_interface * ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex, int ifaddr_next, int ifindex_next) { struct ospf_snmp_if *osif; struct listnode *nn; struct ospf *ospf = ospf_lookup (); struct ospf_interface *oi = NULL; if (ospf == NULL) return NULL; /* No instance is specified --> Return the first OSPF interface */ if (ifaddr_next) { for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif)) { osif = listgetdata (nn); *ifaddr = osif->addr; *ifindex = osif->ifindex; /* Because no instance is specified, we don't care about the kind of * interface (usual or unnumbered), just returning the first valid * OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return (oi); } return NULL; } /* An instance is specified --> Return the next OSPF interface */ for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif)) { /* Usual interface */ if (ifaddr->s_addr) { /* The interface must have valid AF_INET connected address */ /* it must have lager IPv4 address value than the lookup entry */ if ((ospf_snmp_is_if_have_addr(osif->ifp)) && (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr))) { *ifaddr = osif->addr; *ifindex = osif->ifindex; /* and it must be an OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return oi; } } /* Unnumbered interface */ else /* The interface must NOT have valid AF_INET connected address */ /* it must have lager interface index than the lookup entry */ if ((!ospf_snmp_is_if_have_addr(osif->ifp)) && (osif->ifindex > *ifindex)) { *ifaddr = osif->addr; *ifindex = osif->ifindex; /* and it must be an OSPF interface */ oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr); if (oi) return oi; } } return NULL; } static int ospf_snmp_iftype (struct interface *ifp) { #define ospf_snmp_iftype_broadcast 1 #define ospf_snmp_iftype_nbma 2 #define ospf_snmp_iftype_pointToPoint 3 #define ospf_snmp_iftype_pointToMultipoint 5 if (if_is_broadcast (ifp)) return ospf_snmp_iftype_broadcast; if (if_is_pointopoint (ifp)) return ospf_snmp_iftype_pointToPoint; return ospf_snmp_iftype_broadcast; } static struct ospf_interface * ospfIfLookup (struct variable *v, oid *name, size_t *length, struct in_addr *ifaddr, unsigned int *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; int ifindex_next = 0; struct ospf_interface *oi; oid *offset; if (exact) { if (*length != v->namelen + IN_ADDR_SIZE + 1) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); *ifindex = name[v->namelen + IN_ADDR_SIZE]; return ospf_snmp_if_lookup (ifaddr, ifindex); } else { len = *length - v->namelen; if (len >= IN_ADDR_SIZE) len = IN_ADDR_SIZE; if (len <= 0) ifaddr_next = 1; oid2in_addr (name + v->namelen, len, ifaddr); len = *length - v->namelen - IN_ADDR_SIZE; if (len >= 1) len = 1; else ifindex_next = 1; if (len == 1) *ifindex = name[v->namelen + IN_ADDR_SIZE]; oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, ifindex_next); if (oi) { *length = v->namelen + IN_ADDR_SIZE + 1; offset = name + v->namelen; oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = *ifindex; return oi; } } return NULL; } static u_char * ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { unsigned int ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; oi = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact); if (oi == NULL) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFIFIPADDRESS: /* 1 */ return SNMP_IPADDRESS (ifaddr); break; case OSPFADDRESSLESSIF: /* 2 */ return SNMP_INTEGER (ifindex); break; case OSPFIFAREAID: /* 3 */ if (oi->area) return SNMP_IPADDRESS (oi->area->area_id); else return SNMP_IPADDRESS (ospf_empty_addr); break; case OSPFIFTYPE: /* 4 */ return SNMP_INTEGER (ospf_snmp_iftype (oi->ifp)); break; case OSPFIFADMINSTAT: /* 5 */ if (oi) return SNMP_INTEGER (OSPF_STATUS_ENABLED); else return SNMP_INTEGER (OSPF_STATUS_DISABLED); break; case OSPFIFRTRPRIORITY: /* 6 */ return SNMP_INTEGER (PRIORITY (oi)); break; case OSPFIFTRANSITDELAY: /* 7 */ return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); break; case OSPFIFRETRANSINTERVAL: /* 8 */ return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); break; case OSPFIFHELLOINTERVAL: /* 9 */ return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); break; case OSPFIFRTRDEADINTERVAL: /* 10 */ return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); break; case OSPFIFPOLLINTERVAL: /* 11 */ return SNMP_INTEGER (OSPF_POLL_INTERVAL_DEFAULT); break; case OSPFIFSTATE: /* 12 */ return SNMP_INTEGER (ISM_SNMP(oi->state)); break; case OSPFIFDESIGNATEDROUTER: /* 13 */ return SNMP_IPADDRESS (DR (oi)); break; case OSPFIFBACKUPDESIGNATEDROUTER: /* 14 */ return SNMP_IPADDRESS (BDR (oi)); break; case OSPFIFEVENTS: /* 15 */ return SNMP_INTEGER (oi->state_change); break; case OSPFIFAUTHKEY: /* 16 */ *var_len = 0; return (u_char *) OSPF_IF_PARAM (oi, auth_simple); break; case OSPFIFSTATUS: /* 17 */ return SNMP_INTEGER (SNMP_VALID); break; case OSPFIFMULTICASTFORWARDING: /* 18 */ #define ospf_snmp_multiforward_blocked 1 #define ospf_snmp_multiforward_multicast 2 #define ospf_snmp_multiforward_unicast 3 return SNMP_INTEGER (ospf_snmp_multiforward_blocked); break; case OSPFIFDEMAND: /* 19 */ return SNMP_INTEGER (SNMP_FALSE); break; case OSPFIFAUTHTYPE: /* 20 */ if (oi->area) return SNMP_INTEGER (oi->area->auth_type); else return SNMP_INTEGER (0); break; default: return NULL; break; } return NULL; } #define OSPF_SNMP_METRIC_VALUE 1 static struct ospf_interface * ospfIfMetricLookup (struct variable *v, oid *name, size_t *length, struct in_addr *ifaddr, unsigned int *ifindex, int exact) { unsigned int len; int ifaddr_next = 0; int ifindex_next = 0; struct ospf_interface *oi; oid *offset; int metric; if (exact) { if (*length != v->namelen + IN_ADDR_SIZE + 1 + 1) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, ifaddr); *ifindex = name[v->namelen + IN_ADDR_SIZE]; metric = name[v->namelen + IN_ADDR_SIZE + 1]; if (metric != OSPF_SNMP_METRIC_VALUE) return NULL; return ospf_snmp_if_lookup (ifaddr, ifindex); } else { len = *length - v->namelen; if (len >= IN_ADDR_SIZE) len = IN_ADDR_SIZE; else ifaddr_next = 1; oid2in_addr (name + v->namelen, len, ifaddr); len = *length - v->namelen - IN_ADDR_SIZE; if (len >= 1) len = 1; else ifindex_next = 1; if (len == 1) *ifindex = name[v->namelen + IN_ADDR_SIZE]; oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next, ifindex_next); if (oi) { *length = v->namelen + IN_ADDR_SIZE + 1 + 1; offset = name + v->namelen; oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = *ifindex; offset++; *offset = OSPF_SNMP_METRIC_VALUE; return oi; } } return NULL; } static u_char * ospfIfMetricEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { /* Currently we support metric 1 only. */ unsigned int ifindex; struct in_addr ifaddr; struct ospf_interface *oi; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; ifindex = 0; memset (&ifaddr, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; oi = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact); if (oi == NULL) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFIFMETRICIPADDRESS: return SNMP_IPADDRESS (ifaddr); break; case OSPFIFMETRICADDRESSLESSIF: return SNMP_INTEGER (ifindex); break; case OSPFIFMETRICTOS: return SNMP_INTEGER (0); break; case OSPFIFMETRICVALUE: return SNMP_INTEGER (OSPF_SNMP_METRIC_VALUE); break; case OSPFIFMETRICSTATUS: return SNMP_INTEGER (1); break; default: return NULL; break; } return NULL; } struct route_table *ospf_snmp_vl_table; void ospf_snmp_vl_add (struct ospf_vl_data *vl_data) { struct prefix_ls lp; struct route_node *rn; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = vl_data->vl_area_id; lp.adv_router = vl_data->vl_peer; rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); rn->info = vl_data; } void ospf_snmp_vl_delete (struct ospf_vl_data *vl_data) { struct prefix_ls lp; struct route_node *rn; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = vl_data->vl_area_id; lp.adv_router = vl_data->vl_peer; rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); if (! rn) return; rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } static struct ospf_vl_data * ospf_snmp_vl_lookup (struct in_addr *area_id, struct in_addr *neighbor) { struct prefix_ls lp; struct route_node *rn; struct ospf_vl_data *vl_data; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = *area_id; lp.adv_router = *neighbor; rn = route_node_lookup (ospf_snmp_vl_table, (struct prefix *) &lp); if (rn) { vl_data = rn->info; route_unlock_node (rn); return vl_data; } return NULL; } static struct ospf_vl_data * ospf_snmp_vl_lookup_next (struct in_addr *area_id, struct in_addr *neighbor, int first) { struct prefix_ls lp; struct route_node *rn; struct ospf_vl_data *vl_data; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = *area_id; lp.adv_router = *neighbor; if (first) rn = route_top (ospf_snmp_vl_table); else { rn = route_node_get (ospf_snmp_vl_table, (struct prefix *) &lp); rn = route_next (rn); } for (; rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { vl_data = rn->info; *area_id = vl_data->vl_area_id; *neighbor = vl_data->vl_peer; route_unlock_node (rn); return vl_data; } return NULL; } static struct ospf_vl_data * ospfVirtIfLookup (struct variable *v, oid *name, size_t *length, struct in_addr *area_id, struct in_addr *neighbor, int exact) { int first; unsigned int len; struct ospf_vl_data *vl_data; if (exact) { if (*length != v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, area_id); oid2in_addr (name + v->namelen + IN_ADDR_SIZE, IN_ADDR_SIZE, neighbor); return ospf_snmp_vl_lookup (area_id, neighbor); } else { first = 0; len = *length - v->namelen; if (len <= 0) first = 1; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (name + v->namelen, len, area_id); len = *length - v->namelen - IN_ADDR_SIZE; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (name + v->namelen + IN_ADDR_SIZE, len, neighbor); vl_data = ospf_snmp_vl_lookup_next (area_id, neighbor, first); if (vl_data) { *length = v->namelen + IN_ADDR_SIZE + IN_ADDR_SIZE; oid_copy_addr (name + v->namelen, area_id, IN_ADDR_SIZE); oid_copy_addr (name + v->namelen + IN_ADDR_SIZE, neighbor, IN_ADDR_SIZE); return vl_data; } } return NULL; } static u_char * ospfVirtIfEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_vl_data *vl_data; struct ospf_interface *oi; struct in_addr area_id; struct in_addr neighbor; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&area_id, 0, sizeof (struct in_addr)); memset (&neighbor, 0, sizeof (struct in_addr)); vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); if (! vl_data) return NULL; oi = vl_data->vl_oi; if (! oi) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFVIRTIFAREAID: return SNMP_IPADDRESS (area_id); break; case OSPFVIRTIFNEIGHBOR: return SNMP_IPADDRESS (neighbor); break; case OSPFVIRTIFTRANSITDELAY: return SNMP_INTEGER (OSPF_IF_PARAM (oi, transmit_delay)); break; case OSPFVIRTIFRETRANSINTERVAL: return SNMP_INTEGER (OSPF_IF_PARAM (oi, retransmit_interval)); break; case OSPFVIRTIFHELLOINTERVAL: return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_hello)); break; case OSPFVIRTIFRTRDEADINTERVAL: return SNMP_INTEGER (OSPF_IF_PARAM (oi, v_wait)); break; case OSPFVIRTIFSTATE: return SNMP_INTEGER (oi->state); break; case OSPFVIRTIFEVENTS: return SNMP_INTEGER (oi->state_change); break; case OSPFVIRTIFAUTHKEY: *var_len = 0; return (u_char *) OSPF_IF_PARAM (oi, auth_simple); break; case OSPFVIRTIFSTATUS: return SNMP_INTEGER (SNMP_VALID); break; case OSPFVIRTIFAUTHTYPE: if (oi->area) return SNMP_INTEGER (oi->area->auth_type); else return SNMP_INTEGER (0); break; default: return NULL; break; } return NULL; } static struct ospf_neighbor * ospf_snmp_nbr_lookup (struct ospf *ospf, struct in_addr *nbr_addr, unsigned int *ifindex) { struct listnode *node, *nnode; struct ospf_interface *oi; struct ospf_neighbor *nbr; struct route_node *rn; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL && nbr != oi->nbr_self /* If EXACT match is needed, provide ALL entry found && nbr->state != NSM_Down */ && nbr->src.s_addr != 0) { if (IPV4_ADDR_SAME (&nbr->src, nbr_addr)) { route_unlock_node (rn); return nbr; } } } return NULL; } static struct ospf_neighbor * ospf_snmp_nbr_lookup_next (struct in_addr *nbr_addr, unsigned int *ifindex, int first) { struct listnode *nn; struct ospf_interface *oi; struct ospf_neighbor *nbr; struct route_node *rn; struct ospf_neighbor *min = NULL; struct ospf *ospf = ospf; ospf = ospf_lookup (); for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, nn, oi)) { for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL && nbr != oi->nbr_self && nbr->state != NSM_Down && nbr->src.s_addr != 0) { if (first) { if (! min) min = nbr; else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) min = nbr; } else if (ntohl (nbr->src.s_addr) > ntohl (nbr_addr->s_addr)) { if (! min) min = nbr; else if (ntohl (nbr->src.s_addr) < ntohl (min->src.s_addr)) min = nbr; } } } if (min) { *nbr_addr = min->src; *ifindex = 0; return min; } return NULL; } static struct ospf_neighbor * ospfNbrLookup (struct variable *v, oid *name, size_t *length, struct in_addr *nbr_addr, unsigned int *ifindex, int exact) { unsigned int len; int first; struct ospf_neighbor *nbr; struct ospf *ospf; ospf = ospf_lookup (); if (! ospf) return NULL; if (exact) { if (*length != v->namelen + IN_ADDR_SIZE + 1) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, nbr_addr); *ifindex = name[v->namelen + IN_ADDR_SIZE]; return ospf_snmp_nbr_lookup (ospf, nbr_addr, ifindex); } else { first = 0; len = *length - v->namelen; if (len <= 0) first = 1; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (name + v->namelen, len, nbr_addr); len = *length - v->namelen - IN_ADDR_SIZE; if (len >= 1) *ifindex = name[v->namelen + IN_ADDR_SIZE]; nbr = ospf_snmp_nbr_lookup_next (nbr_addr, ifindex, first); if (nbr) { *length = v->namelen + IN_ADDR_SIZE + 1; oid_copy_addr (name + v->namelen, nbr_addr, IN_ADDR_SIZE); name[v->namelen + IN_ADDR_SIZE] = *ifindex; return nbr; } } return NULL; } /* map internal quagga neighbor states to official MIB values: ospfNbrState OBJECT-TYPE SYNTAX INTEGER { down (1), attempt (2), init (3), twoWay (4), exchangeStart (5), exchange (6), loading (7), full (8) } */ static int32_t ospf_snmp_neighbor_state(u_char nst) { switch (nst) { case NSM_Attempt: return 2; case NSM_Init: return 3; case NSM_TwoWay: return 4; case NSM_ExStart: return 5; case NSM_Exchange: return 6; case NSM_Loading: return 7; case NSM_Full: return 8; default: return 1; /* down */ } } static u_char * ospfNbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct in_addr nbr_addr; unsigned int ifindex; struct ospf_neighbor *nbr; struct ospf_interface *oi; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&nbr_addr, 0, sizeof (struct in_addr)); ifindex = 0; nbr = ospfNbrLookup (v, name, length, &nbr_addr, &ifindex, exact); if (! nbr) return NULL; oi = nbr->oi; if (! oi) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFNBRIPADDR: return SNMP_IPADDRESS (nbr_addr); break; case OSPFNBRADDRESSLESSINDEX: return SNMP_INTEGER (ifindex); break; case OSPFNBRRTRID: return SNMP_IPADDRESS (nbr->router_id); break; case OSPFNBROPTIONS: return SNMP_INTEGER (oi->nbr_self->options); break; case OSPFNBRPRIORITY: return SNMP_INTEGER (nbr->priority); break; case OSPFNBRSTATE: return SNMP_INTEGER (ospf_snmp_neighbor_state(nbr->state)); break; case OSPFNBREVENTS: return SNMP_INTEGER (nbr->state_change); break; case OSPFNBRLSRETRANSQLEN: return SNMP_INTEGER (ospf_ls_retransmit_count (nbr)); break; case OSPFNBMANBRSTATUS: return SNMP_INTEGER (SNMP_VALID); break; case OSPFNBMANBRPERMANENCE: return SNMP_INTEGER (2); break; case OSPFNBRHELLOSUPPRESSED: return SNMP_INTEGER (SNMP_FALSE); break; default: return NULL; break; } return NULL; } static u_char * ospfVirtNbrEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_vl_data *vl_data; struct in_addr area_id; struct in_addr neighbor; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&area_id, 0, sizeof (struct in_addr)); memset (&neighbor, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; vl_data = ospfVirtIfLookup (v, name, length, &area_id, &neighbor, exact); if (! vl_data) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFVIRTNBRAREA: return (u_char *) NULL; break; case OSPFVIRTNBRRTRID: return (u_char *) NULL; break; case OSPFVIRTNBRIPADDR: return (u_char *) NULL; break; case OSPFVIRTNBROPTIONS: return (u_char *) NULL; break; case OSPFVIRTNBRSTATE: return (u_char *) NULL; break; case OSPFVIRTNBREVENTS: return (u_char *) NULL; break; case OSPFVIRTNBRLSRETRANSQLEN: return (u_char *) NULL; break; case OSPFVIRTNBRHELLOSUPPRESSED: return (u_char *) NULL; break; default: return NULL; break; } return NULL; } static struct ospf_lsa * ospfExtLsdbLookup (struct variable *v, oid *name, size_t *length, u_char *type, struct in_addr *ls_id, struct in_addr *router_id, int exact) { int first; oid *offset; int offsetlen; u_char lsa_type; unsigned int len; struct ospf_lsa *lsa; struct ospf *ospf; ospf = ospf_lookup (); if (exact) { if (*length != v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE) return NULL; offset = name + v->namelen; /* Make it sure given value match to type. */ lsa_type = *offset; offset++; if (lsa_type != *type) return NULL; /* LS ID. */ oid2in_addr (offset, IN_ADDR_SIZE, ls_id); offset += IN_ADDR_SIZE; /* Router ID. */ oid2in_addr (offset, IN_ADDR_SIZE, router_id); return ospf_lsdb_lookup_by_id (ospf->lsdb, *type, *ls_id, *router_id); } else { /* Get variable length. */ first = 0; offset = name + v->namelen; offsetlen = *length - v->namelen; /* LSA type value. */ lsa_type = *offset; offset++; offsetlen--; if (offsetlen <= 0 || lsa_type < OSPF_AS_EXTERNAL_LSA) first = 1; /* LS ID. */ len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, ls_id); offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; /* Router ID. */ len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, router_id); lsa = ospf_lsdb_lookup_by_id_next (ospf->lsdb, *type, *ls_id, *router_id, first); if (lsa) { /* Fill in length. */ *length = v->namelen + 1 + IN_ADDR_SIZE + IN_ADDR_SIZE; /* Fill in value. */ offset = name + v->namelen; *offset = OSPF_AS_EXTERNAL_LSA; offset++; oid_copy_addr (offset, &lsa->data->id, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; oid_copy_addr (offset, &lsa->data->adv_router, IN_ADDR_SIZE); return lsa; } } return NULL; } static u_char * ospfExtLsdbEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct ospf_lsa *lsa; struct lsa_header *lsah; u_char type; struct in_addr ls_id; struct in_addr router_id; struct ospf *ospf; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; type = OSPF_AS_EXTERNAL_LSA; memset (&ls_id, 0, sizeof (struct in_addr)); memset (&router_id, 0, sizeof (struct in_addr)); /* Check OSPF instance. */ ospf = ospf_lookup (); if (ospf == NULL) return NULL; lsa = ospfExtLsdbLookup (v, name, length, &type, &ls_id, &router_id, exact); if (! lsa) return NULL; lsah = lsa->data; /* Return the current value of the variable */ switch (v->magic) { case OSPFEXTLSDBTYPE: return SNMP_INTEGER (OSPF_AS_EXTERNAL_LSA); break; case OSPFEXTLSDBLSID: return SNMP_IPADDRESS (lsah->id); break; case OSPFEXTLSDBROUTERID: return SNMP_IPADDRESS (lsah->adv_router); break; case OSPFEXTLSDBSEQUENCE: return SNMP_INTEGER (lsah->ls_seqnum); break; case OSPFEXTLSDBAGE: return SNMP_INTEGER (lsah->ls_age); break; case OSPFEXTLSDBCHECKSUM: return SNMP_INTEGER (lsah->checksum); break; case OSPFEXTLSDBADVERTISEMENT: *var_len = ntohs (lsah->length); return (u_char *) lsah; break; default: return NULL; break; } return NULL; } static u_char * ospfAreaAggregateEntry (struct variable *v, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Return the current value of the variable */ switch (v->magic) { case OSPFAREAAGGREGATEAREAID: return (u_char *) NULL; break; case OSPFAREAAGGREGATELSDBTYPE: return (u_char *) NULL; break; case OSPFAREAAGGREGATENET: return (u_char *) NULL; break; case OSPFAREAAGGREGATEMASK: return (u_char *) NULL; break; case OSPFAREAAGGREGATESTATUS: return (u_char *) NULL; break; case OSPFAREAAGGREGATEEFFECT: return (u_char *) NULL; break; default: return NULL; break; } return NULL; } /* OSPF Traps. */ #define IFSTATECHANGE 16 #define VIRTIFSTATECHANGE 1 #define NBRSTATECHANGE 2 #define VIRTNBRSTATECHANGE 3 struct trap_object ospfNbrTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {10, 1, OSPFNBRIPADDR}}, {3, {10, 1, OSPFNBRRTRID}}, {3, {10, 1, OSPFNBRSTATE}} }; struct trap_object ospfVirtNbrTrapList[] = { {-2, {1, 1}}, {3, {11, 1, OSPFVIRTNBRAREA}}, {3, {11, 1, OSPFVIRTNBRRTRID}}, {3, {11, 1, OSPFVIRTNBRSTATE}} }; struct trap_object ospfIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {7, 1, OSPFIFIPADDRESS}}, {3, {7, 1, OSPFADDRESSLESSIF}}, {3, {7, 1, OSPFIFSTATE}} }; struct trap_object ospfVirtIfTrapList[] = { {-2, {1, OSPFROUTERID}}, {3, {9, 1, OSPFVIRTIFAREAID}}, {3, {9, 1, OSPFVIRTIFNEIGHBOR}}, {3, {9, 1, OSPFVIRTIFSTATE}} }; void ospfTrapNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; char msgbuf[16]; ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf)); zlog (NULL, LOG_INFO, "ospfTrapNbrStateChange trap sent: %s now %s", inet_ntoa(on->address.u.prefix4), msgbuf); oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfNbrTrapList, sizeof ospfNbrTrapList / sizeof (struct trap_object), NBRSTATECHANGE); } void ospfTrapVirtNbrStateChange (struct ospf_neighbor *on) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapVirtNbrStateChange trap sent"); oid_copy_addr (index, &(on->address.u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtNbrTrapList, sizeof ospfVirtNbrTrapList / sizeof (struct trap_object), VIRTNBRSTATECHANGE); } void ospfTrapIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapIfStateChange trap sent: %s now %s", inet_ntoa(oi->address->u.prefix4), LOOKUP(ospf_ism_state_msg, oi->state)); oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfIfTrapList, sizeof ospfIfTrapList / sizeof (struct trap_object), IFSTATECHANGE); } void ospfTrapVirtIfStateChange (struct ospf_interface *oi) { oid index[sizeof (oid) * (IN_ADDR_SIZE + 1)]; zlog (NULL, LOG_INFO, "ospfTrapVirtIfStateChange trap sent"); oid_copy_addr (index, &(oi->address->u.prefix4), IN_ADDR_SIZE); index[IN_ADDR_SIZE] = 0; smux_trap (ospf_variables, sizeof ospf_variables / sizeof (struct variable), ospf_trap_oid, sizeof ospf_trap_oid / sizeof (oid), ospf_oid, sizeof ospf_oid / sizeof (oid), index, IN_ADDR_SIZE + 1, ospfVirtIfTrapList, sizeof ospfVirtIfTrapList / sizeof (struct trap_object), VIRTIFSTATECHANGE); } /* Register OSPF2-MIB. */ void ospf_snmp_init () { ospf_snmp_iflist = list_new (); ospf_snmp_vl_table = route_table_init (); smux_init (om->master); REGISTER_MIB("mibII/ospf", ospf_variables, variable, ospf_oid); } #endif /* HAVE_SNMP */ quagga-0.99.24.1/ospfd/ospf_routemap.c0000644000175000017500000005305612476520570014407 00000000000000/* * Route map function of ospfd. * Copyright (C) 2000 IP Infusion Inc. * * Written by Toshiaki Takada. * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "prefix.h" #include "table.h" #include "routemap.h" #include "command.h" #include "log.h" #include "plist.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" /* Hook function for updating route_map assignment. */ static void ospf_route_map_update (const char *name) { struct ospf *ospf; int type; /* If OSPF instatnce does not exist, return right now. */ ospf = ospf_lookup (); if (ospf == NULL) return; /* Update route-map */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (ROUTEMAP_NAME (ospf, type) && strcmp (ROUTEMAP_NAME (ospf, type), name) == 0) { /* Keep old route-map. */ struct route_map *old = ROUTEMAP (ospf, type); /* Update route-map. */ ROUTEMAP (ospf, type) = route_map_lookup_by_name (ROUTEMAP_NAME (ospf, type)); /* No update for this distribute type. */ if (old == NULL && ROUTEMAP (ospf, type) == NULL) continue; ospf_distribute_list_update (ospf, type); } } } static void ospf_route_map_event (route_map_event_t event, const char *name) { struct ospf *ospf; int type; /* If OSPF instatnce does not exist, return right now. */ ospf = ospf_lookup (); if (ospf == NULL) return; /* Update route-map. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (ROUTEMAP_NAME (ospf, type) && ROUTEMAP (ospf, type) && !strcmp (ROUTEMAP_NAME (ospf, type), name)) { ospf_distribute_list_update (ospf, type); } } } /* Delete rip route map rule. */ static int ospf_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ospf_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ospf_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int ospf_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match ip netxthop ' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_nexthop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; struct external_info *ei = object; struct prefix_ipv4 p; if (type == RMAP_OSPF) { p.family = AF_INET; p.prefix = ei->nexthop; p.prefixlen = IPV4_MAX_BITLEN; alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip next-hop' match statement. `arg' should be access-list name. */ static void * route_match_ip_nexthop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_nexthop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_ip_nexthop_cmd = { "ip next-hop", route_match_ip_nexthop, route_match_ip_nexthop_compile, route_match_ip_nexthop_free }; /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; struct external_info *ei = object; struct prefix_ipv4 p; if (type == RMAP_OSPF) { p.family = AF_INET; p.prefix = ei->nexthop; p.prefixlen = IPV4_MAX_BITLEN; plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, &p) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_address (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; /* struct prefix_ipv4 match; */ if (type == RMAP_OSPF) { alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, prefix) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip address' match statement. `arg' should be access-list name. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_ip_address_cmd = { "ip address", route_match_ip_address, route_match_ip_address_compile, route_match_ip_address_free }; /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type == RMAP_OSPF) { plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { "ip address prefix-list", route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; /* `match interface IFNAME' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct interface *ifp; struct external_info *ei; if (type == RMAP_OSPF) { ei = object; ifp = if_lookup_by_name ((char *)rule); if (ifp == NULL || ifp->ifindex != ei->ifindex) return RMAP_NOMATCH; return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `interface' match statement. `arg' should be interface name. */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `interface' value. */ static void route_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_interface_cmd = { "interface", route_match_interface, route_match_interface_compile, route_match_interface_free }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric; struct external_info *ei; if (type == RMAP_OSPF) { /* Fetch routemap's rule information. */ metric = rule; ei = object; /* Set metric out value. */ ei->route_map_set.metric = *metric; } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { u_int32_t *metric; int32_t ret; metric = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); ret = atoi (arg); if (ret >= 0) { *metric = (u_int32_t)ret; return metric; } XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); return NULL; } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free, }; /* `set metric-type TYPE' */ /* Set metric-type to attribute. */ static route_map_result_t route_set_metric_type (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric_type; struct external_info *ei; if (type == RMAP_OSPF) { /* Fetch routemap's rule information. */ metric_type = rule; ei = object; /* Set metric out value. */ ei->route_map_set.metric_type = *metric_type; } return RMAP_OKAY; } /* set metric-type compilation. */ static void * route_set_metric_type_compile (const char *arg) { u_int32_t *metric_type; metric_type = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (strcmp (arg, "type-1") == 0) *metric_type = EXTERNAL_METRIC_TYPE_1; else if (strcmp (arg, "type-2") == 0) *metric_type = EXTERNAL_METRIC_TYPE_2; if (*metric_type == EXTERNAL_METRIC_TYPE_1 || *metric_type == EXTERNAL_METRIC_TYPE_2) return metric_type; XFREE (MTYPE_ROUTE_MAP_COMPILED, metric_type); return NULL; } /* Free route map's compiled `set metric-type' value. */ static void route_set_metric_type_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_type_cmd = { "metric-type", route_set_metric_type, route_set_metric_type_compile, route_set_metric_type_free, }; DEFUN (match_ip_nexthop, match_ip_nexthop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") { return ospf_route_match_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_match_ip_nexthop, no_match_ip_nexthop_cmd, "no match ip next-hop", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip next-hop", NULL); return ospf_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_match_ip_nexthop, no_match_ip_nexthop_val_cmd, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD", MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return ospf_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); } DEFUN (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return ospf_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); } ALIAS (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") { return ospf_route_match_add (vty, vty->index, "ip address", argv[0]); } DEFUN (no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip address", NULL); return ospf_route_match_delete (vty, vty->index, "ip address", argv[0]); } ALIAS (no_match_ip_address, no_match_ip_address_val_cmd, "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD", MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return ospf_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); } DEFUN (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return ospf_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); } ALIAS (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return ospf_route_match_add (vty, vty->index, "interface", argv[0]); } DEFUN (no_match_interface, no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { if (argc == 0) return ospf_route_match_delete (vty, vty->index, "interface", NULL); return ospf_route_match_delete (vty, vty->index, "interface", argv[0]); } ALIAS (no_match_interface, no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", SET_STR "Metric value for destination routing protocol\n" "Metric value\n") { return ospf_route_set_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric value for destination routing protocol\n") { if (argc == 0) return ospf_route_set_delete (vty, vty->index, "metric", NULL); return ospf_route_set_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_set_metric, no_set_metric_val_cmd, "no set metric <0-4294967295>", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n") DEFUN (set_metric_type, set_metric_type_cmd, "set metric-type (type-1|type-2)", SET_STR "Type of metric for destination routing protocol\n" "OSPF[6] external type 1 metric\n" "OSPF[6] external type 2 metric\n") { if (strcmp (argv[0], "1") == 0) return ospf_route_set_add (vty, vty->index, "metric-type", "type-1"); if (strcmp (argv[0], "2") == 0) return ospf_route_set_add (vty, vty->index, "metric-type", "type-2"); return ospf_route_set_add (vty, vty->index, "metric-type", argv[0]); } DEFUN (no_set_metric_type, no_set_metric_type_cmd, "no set metric-type", NO_STR SET_STR "Type of metric for destination routing protocol\n") { if (argc == 0) return ospf_route_set_delete (vty, vty->index, "metric-type", NULL); return ospf_route_set_delete (vty, vty->index, "metric-type", argv[0]); } ALIAS (no_set_metric_type, no_set_metric_type_val_cmd, "no set metric-type (type-1|type-2)", NO_STR SET_STR "Type of metric for destination routing protocol\n" "OSPF[6] external type 1 metric\n" "OSPF[6] external type 2 metric\n") /* Route-map init */ void ospf_route_map_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (ospf_route_map_update); route_map_delete_hook (ospf_route_map_update); route_map_event_hook (ospf_route_map_event); route_map_install_match (&route_match_ip_nexthop_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_interface_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_metric_type_cmd); install_element (RMAP_NODE, &match_ip_nexthop_cmd); install_element (RMAP_NODE, &no_match_ip_nexthop_cmd); install_element (RMAP_NODE, &no_match_ip_nexthop_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_cmd); install_element (RMAP_NODE, &no_set_metric_type_val_cmd); } quagga-0.99.24.1/ospfd/ospf_asbr.c0000644000175000017500000001572212476520570013500 00000000000000/* * OSPF AS Boundary Router functions. * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "vty.h" #include "filter.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" /* Remove external route. */ void ospf_external_route_remove (struct ospf *ospf, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_route *or; rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); if (rn) if ((or = rn->info)) { zlog_info ("Route[%s/%d]: external path deleted", inet_ntoa (p->prefix), p->prefixlen); /* Remove route from zebra. */ if (or->type == OSPF_DESTINATION_NETWORK) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); ospf_route_free (or); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); return; } zlog_info ("Route[%s/%d]: no such external path", inet_ntoa (p->prefix), p->prefixlen); } /* Lookup external route. */ struct ospf_route * ospf_external_route_lookup (struct ospf *ospf, struct prefix_ipv4 *p) { struct route_node *rn; rn = route_node_lookup (ospf->old_external_route, (struct prefix *) p); if (rn) { route_unlock_node (rn); if (rn->info) return rn->info; } zlog_warn ("Route[%s/%d]: lookup, no such prefix", inet_ntoa (p->prefix), p->prefixlen); return NULL; } /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_new (u_char type) { struct external_info *new; new = (struct external_info *) XCALLOC (MTYPE_OSPF_EXTERNAL_INFO, sizeof (struct external_info)); new->type = type; ospf_reset_route_map_set_values (&new->route_map_set); return new; } static void ospf_external_info_free (struct external_info *ei) { XFREE (MTYPE_OSPF_EXTERNAL_INFO, ei); } void ospf_reset_route_map_set_values (struct route_map_set_values *values) { values->metric = -1; values->metric_type = -1; } int ospf_route_map_set_compare (struct route_map_set_values *values1, struct route_map_set_values *values2) { return values1->metric == values2->metric && values1->metric_type == values2->metric_type; } /* Add an External info for AS-external-LSA. */ struct external_info * ospf_external_info_add (u_char type, struct prefix_ipv4 p, unsigned int ifindex, struct in_addr nexthop) { struct external_info *new; struct route_node *rn; /* Initialize route table. */ if (EXTERNAL_INFO (type) == NULL) EXTERNAL_INFO (type) = route_table_init (); rn = route_node_get (EXTERNAL_INFO (type), (struct prefix *) &p); /* If old info exists, -- discard new one or overwrite with new one? */ if (rn) if (rn->info) { route_unlock_node (rn); zlog_warn ("Redistribute[%s]: %s/%d already exists, discard.", ospf_redist_string(type), inet_ntoa (p.prefix), p.prefixlen); /* XFREE (MTYPE_OSPF_TMP, rn->info); */ return rn->info; } /* Create new External info instance. */ new = ospf_external_info_new (type); new->p = p; new->ifindex = ifindex; new->nexthop = nexthop; new->tag = 0; if (rn) rn->info = new; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("Redistribute[%s]: %s/%d external info created.", ospf_redist_string(type), inet_ntoa (p.prefix), p.prefixlen); return new; } void ospf_external_info_delete (u_char type, struct prefix_ipv4 p) { struct route_node *rn; rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); if (rn) { ospf_external_info_free (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } struct external_info * ospf_external_info_lookup (u_char type, struct prefix_ipv4 *p) { struct route_node *rn; rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) p); if (rn) { route_unlock_node (rn); if (rn->info) return rn->info; } return NULL; } struct ospf_lsa * ospf_external_info_find_lsa (struct ospf *ospf, struct prefix_ipv4 *p) { struct ospf_lsa *lsa; struct as_external_lsa *al; struct in_addr mask, id; lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, p->prefix, ospf->router_id); if (!lsa) return NULL; al = (struct as_external_lsa *) lsa->data; masklen2ip (p->prefixlen, &mask); if (mask.s_addr != al->mask.s_addr) { id.s_addr = p->prefix.s_addr | (~mask.s_addr); lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, OSPF_AS_EXTERNAL_LSA, id, ospf->router_id); if (!lsa) return NULL; } return lsa; } /* Update ASBR status. */ void ospf_asbr_status_update (struct ospf *ospf, u_char status) { zlog_info ("ASBR[Status:%d]: Update", status); /* ASBR on. */ if (status) { /* Already ASBR. */ if (IS_OSPF_ASBR (ospf)) { zlog_info ("ASBR[Status:%d]: Already ASBR", status); return; } SET_FLAG (ospf->flags, OSPF_FLAG_ASBR); } else { /* Already non ASBR. */ if (! IS_OSPF_ASBR (ospf)) { zlog_info ("ASBR[Status:%d]: Already non ASBR", status); return; } UNSET_FLAG (ospf->flags, OSPF_FLAG_ASBR); } /* Transition from/to status ASBR, schedule timer. */ ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_STATUS_CHANGE); ospf_router_lsa_update (ospf); } void ospf_redistribute_withdraw (struct ospf *ospf, u_char type) { struct route_node *rn; struct external_info *ei; /* Delete external info for specified type. */ if (EXTERNAL_INFO (type)) for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) if ((ei = rn->info)) if (ospf_external_info_find_lsa (ospf, &ei->p)) { if (is_prefix_default (&ei->p) && ospf->default_originate != DEFAULT_ORIGINATE_NONE) continue; ospf_external_lsa_flush (ospf, type, &ei->p, ei->ifindex /*, ei->nexthop */); ospf_external_info_free (ei); route_unlock_node (rn); rn->info = NULL; } } quagga-0.99.24.1/ospfd/ospf_lsdb.c0000644000175000017500000001620312476520570013470 00000000000000/* * OSPF LSDB support. * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "table.h" #include "memory.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" struct ospf_lsdb * ospf_lsdb_new () { struct ospf_lsdb *new; new = XCALLOC (MTYPE_OSPF_LSDB, sizeof (struct ospf_lsdb)); ospf_lsdb_init (new); return new; } void ospf_lsdb_init (struct ospf_lsdb *lsdb) { int i; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) lsdb->type[i].db = route_table_init (); } void ospf_lsdb_free (struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup (lsdb); XFREE (MTYPE_OSPF_LSDB, lsdb); } void ospf_lsdb_cleanup (struct ospf_lsdb *lsdb) { int i; assert (lsdb); assert (lsdb->total == 0); ospf_lsdb_delete_all (lsdb); for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) route_table_finish (lsdb->type[i].db); } void ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa) { if (lp && lsa && lsa->data) { lp->family = 0; lp->prefixlen = 64; lp->id = lsa->data->id; lp->adv_router = lsa->data->adv_router; } } static void ospf_lsdb_delete_entry (struct ospf_lsdb *lsdb, struct route_node *rn) { struct ospf_lsa *lsa = rn->info; if (!lsa) return; assert (rn->table == lsdb->type[lsa->data->type].db); if (IS_LSA_SELF (lsa)) lsdb->type[lsa->data->type].count_self--; lsdb->type[lsa->data->type].count--; lsdb->type[lsa->data->type].checksum -= ntohs(lsa->data->checksum); lsdb->total--; rn->info = NULL; route_unlock_node (rn); #ifdef MONITOR_LSDB_CHANGE if (lsdb->del_lsa_hook != NULL) (* lsdb->del_lsa_hook)(lsa); #endif /* MONITOR_LSDB_CHANGE */ ospf_lsa_unlock (&lsa); /* lsdb */ return; } /* Add new LSA to lsdb. */ void ospf_lsdb_add (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; table = lsdb->type[lsa->data->type].db; ls_prefix_set (&lp, lsa); rn = route_node_get (table, (struct prefix *)&lp); /* nothing to do? */ if (rn->info && rn->info == lsa) { route_unlock_node (rn); return; } /* purge old entry? */ if (rn->info) ospf_lsdb_delete_entry (lsdb, rn); if (IS_LSA_SELF (lsa)) lsdb->type[lsa->data->type].count_self++; lsdb->type[lsa->data->type].count++; lsdb->total++; #ifdef MONITOR_LSDB_CHANGE if (lsdb->new_lsa_hook != NULL) (* lsdb->new_lsa_hook)(lsa); #endif /* MONITOR_LSDB_CHANGE */ lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum); rn->info = ospf_lsa_lock (lsa); /* lsdb */ } void ospf_lsdb_delete (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; if (!lsdb) { zlog_warn ("%s: Called with NULL LSDB", __func__); if (lsa) zlog_warn ("LSA[Type%d:%s]: LSA %p, lsa->lsdb %p", lsa->data->type, inet_ntoa (lsa->data->id), lsa, lsa->lsdb); return; } if (!lsa) { zlog_warn ("%s: Called with NULL LSA", __func__); return; } assert (lsa->data->type < OSPF_MAX_LSA); table = lsdb->type[lsa->data->type].db; ls_prefix_set (&lp, lsa); if ((rn = route_node_lookup (table, (struct prefix *) &lp))) { if (rn->info == lsa) ospf_lsdb_delete_entry (lsdb, rn); route_unlock_node (rn); /* route_node_lookup */ } } void ospf_lsdb_delete_all (struct ospf_lsdb *lsdb) { struct route_table *table; struct route_node *rn; int i; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { table = lsdb->type[i].db; for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info != NULL) ospf_lsdb_delete_entry (lsdb, rn); } } void ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb) { struct route_table *table; struct route_node *rn; struct ospf_lsa *lsa; int i; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { table = lsdb->type[i].db; for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = (rn->info)) != NULL) lsa->stat = LSA_SPF_NOT_EXPLORED; } } struct ospf_lsa * ospf_lsdb_lookup (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; struct ospf_lsa *find; table = lsdb->type[lsa->data->type].db; ls_prefix_set (&lp, lsa); rn = route_node_lookup (table, (struct prefix *) &lp); if (rn) { find = rn->info; route_unlock_node (rn); return find; } return NULL; } struct ospf_lsa * ospf_lsdb_lookup_by_id (struct ospf_lsdb *lsdb, u_char type, struct in_addr id, struct in_addr adv_router) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; struct ospf_lsa *find; table = lsdb->type[type].db; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = id; lp.adv_router = adv_router; rn = route_node_lookup (table, (struct prefix *) &lp); if (rn) { find = rn->info; route_unlock_node (rn); return find; } return NULL; } struct ospf_lsa * ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *lsdb, u_char type, struct in_addr id, struct in_addr adv_router, int first) { struct route_table *table; struct prefix_ls lp; struct route_node *rn; struct ospf_lsa *find; table = lsdb->type[type].db; memset (&lp, 0, sizeof (struct prefix_ls)); lp.family = 0; lp.prefixlen = 64; lp.id = id; lp.adv_router = adv_router; if (first) rn = route_top (table); else { if ((rn = route_node_lookup (table, (struct prefix *) &lp)) == NULL) return NULL; rn = route_next (rn); } for (; rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { find = rn->info; route_unlock_node (rn); return find; } return NULL; } unsigned long ospf_lsdb_count_all (struct ospf_lsdb *lsdb) { return lsdb->total; } unsigned long ospf_lsdb_count (struct ospf_lsdb *lsdb, int type) { return lsdb->type[type].count; } unsigned long ospf_lsdb_count_self (struct ospf_lsdb *lsdb, int type) { return lsdb->type[type].count_self; } unsigned int ospf_lsdb_checksum (struct ospf_lsdb *lsdb, int type) { return lsdb->type[type].checksum; } unsigned long ospf_lsdb_isempty (struct ospf_lsdb *lsdb) { return (lsdb->total == 0); } quagga-0.99.24.1/ospfd/ospf_flood.c0000644000175000017500000007711212476520570013655 00000000000000/* * OSPF Flooding -- RFC2328 Section 13. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "if.h" #include "command.h" #include "table.h" #include "thread.h" #include "memory.h" #include "log.h" #include "zclient.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" extern struct zclient *zclient; /* Do the LSA acking specified in table 19, Section 13.5, row 2 * This get called from ospf_flood_out_interface. Declared inline * for speed. */ static void ospf_flood_delayed_lsa_ack (struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state delayed acknowledgment sent only if advertisement received from Designated Router, otherwise do nothing See RFC 2328 Section 13.5 */ /* Whether LSA is more recent or not, and whether this is in response to the LSA being sent out recieving interface has been worked out previously */ /* Deal with router as BDR */ if (inbr->oi->state == ISM_Backup && ! NBR_IS_DR (inbr)) return; /* Schedule a delayed LSA Ack to be sent */ listnode_add (inbr->oi->ls_ack, ospf_lsa_lock (lsa)); /* delayed LSA Ack */ } /* Check LSA is related to external info. */ struct external_info * ospf_external_info_check (struct ospf_lsa *lsa) { struct as_external_lsa *al; struct prefix_ipv4 p; struct route_node *rn; int type; al = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen (al->mask); for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { int redist_type = is_prefix_default (&p) ? DEFAULT_ROUTE : type; if (ospf_is_type_redistributed (redist_type)) if (EXTERNAL_INFO (type)) { rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); if (rn) { route_unlock_node (rn); if (rn->info != NULL) return (struct external_info *) rn->info; } } } return NULL; } static void ospf_process_self_originated_lsa (struct ospf *ospf, struct ospf_lsa *new, struct ospf_area *area) { struct ospf_interface *oi; struct external_info *ei; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Process self-originated LSA seq 0x%x", new->data->type, inet_ntoa (new->data->id), ntohl(new->data->ls_seqnum)); /* If we're here, we installed a self-originated LSA that we received from a neighbor, i.e. it's more recent. We must see whether we want to originate it. If yes, we should use this LSA's sequence number and reoriginate a new instance. if not --- we must flush this LSA from the domain. */ switch (new->data->type) { case OSPF_ROUTER_LSA: /* Originate a new instance and schedule flooding */ if (area->router_lsa_self) area->router_lsa_self->data->ls_seqnum = new->data->ls_seqnum; ospf_router_lsa_update_area (area); return; case OSPF_NETWORK_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: #endif /* HAVE_OPAQUE_LSA */ /* We must find the interface the LSA could belong to. If the interface is no more a broadcast type or we are no more the DR, we flush the LSA otherwise -- create the new instance and schedule flooding. */ /* Look through all interfaces, not just area, since interface could be moved from one area to another. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) /* These are sanity check. */ if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &new->data->id)) { if (oi->area != area || oi->type != OSPF_IFTYPE_BROADCAST || !IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) { ospf_schedule_lsa_flush_area (area, new); return; } #ifdef HAVE_OPAQUE_LSA if (new->data->type == OSPF_OPAQUE_LINK_LSA) { ospf_opaque_lsa_refresh (new); return; } #endif /* HAVE_OPAQUE_LSA */ if (oi->network_lsa_self) oi->network_lsa_self->data->ls_seqnum = new->data->ls_seqnum; /* Schedule network-LSA origination. */ ospf_network_lsa_update (oi); return; } break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: ospf_schedule_abr_task (ospf); break; case OSPF_AS_EXTERNAL_LSA : case OSPF_AS_NSSA_LSA: if ( (new->data->type == OSPF_AS_EXTERNAL_LSA) && CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT)) { ospf_translated_nssa_refresh (ospf, NULL, new); return; } ei = ospf_external_info_check (new); if (ei) ospf_external_lsa_refresh (ospf, new, ei, LSA_REFRESH_FORCE); else ospf_lsa_flush_as (ospf, new); break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AREA_LSA: ospf_opaque_lsa_refresh (new); break; case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (new); /* Reconsideration may needed. *//* XXX */ break; #endif /* HAVE_OPAQUE_LSA */ default: break; } } /* OSPF LSA flooding -- RFC2328 Section 13.(5). */ /* Now Updated for NSSA operation, as follows: Type-5's have no change. Blocked to STUB or NSSA. Type-7's can be received, and if a DR they will also flood the local NSSA Area as Type-7's If a Self-Originated LSA (now an ASBR), The LSDB will be updated as Type-5's, (for continual re-fresh) If an NSSA-IR it is installed/flooded as Type-7, P-bit on. if an NSSA-ABR it is installed/flooded as Type-7, P-bit off. Later, during the ABR TASK, if the ABR is the Elected NSSA translator, then All Type-7s (with P-bit ON) are Translated to Type-5's and flooded to all non-NSSA/STUB areas. During ASE Calculations, non-ABRs calculate external routes from Type-7's ABRs calculate external routes from Type-5's and non-self Type-7s */ int ospf_flood (struct ospf *ospf, struct ospf_neighbor *nbr, struct ospf_lsa *current, struct ospf_lsa *new) { struct ospf_interface *oi; int lsa_ack_flag; /* Type-7 LSA's will be flooded throughout their native NSSA area, but will also be flooded as Type-5's into ABR capable links. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Flooding]: start, NBR %s (%s), cur(%p), New-LSA[%s]", inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), current, dump_lsa_key (new)); lsa_ack_flag = 0; oi = nbr->oi; /* If there is already a database copy, and if the database copy was received via flooding and installed less than MinLSArrival seconds ago, discard the new LSA (without acknowledging it). */ if (current != NULL) /* -- endo. */ { if (IS_LSA_SELF (current) && (ntohs (current->data->ls_age) == 0 && ntohl (current->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Flooding]: Got a self-originated LSA, " "while local one is initial instance."); ; /* Accept this LSA for quick LSDB resynchronization. */ } else if (tv_cmp (tv_sub (recent_relative_time (), current->tv_recv), int2tv (OSPF_MIN_LS_ARRIVAL)) < 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Flooding]: LSA is received recently."); return -1; } } /* Flood the new LSA out some subset of the router's interfaces. In some cases (e.g., the state of the receiving interface is DR and the LSA was received from a router other than the Backup DR) the LSA will be flooded back out the receiving interface. */ lsa_ack_flag = ospf_flood_through (ospf, nbr, new); #ifdef HAVE_OPAQUE_LSA /* Remove the current database copy from all neighbors' Link state retransmission lists. AS_EXTERNAL and AS_EXTERNAL_OPAQUE does ^^^^^^^^^^^^^^^^^^^^^^^ not have area ID. All other (even NSSA's) do have area ID. */ #else /* HAVE_OPAQUE_LSA */ /* Remove the current database copy from all neighbors' Link state retransmission lists. Only AS_EXTERNAL does not have area ID. All other (even NSSA's) do have area ID. */ #endif /* HAVE_OPAQUE_LSA */ if (current) { switch (current->data->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_ls_retransmit_delete_nbr_as (ospf, current); break; default: ospf_ls_retransmit_delete_nbr_area (nbr->oi->area, current); break; } } /* Do some internal house keeping that is needed here */ SET_FLAG (new->flags, OSPF_LSA_RECEIVED); ospf_lsa_is_self_originated (ospf, new); /* Let it set the flag */ /* Install the new LSA in the link state database (replacing the current database copy). This may cause the routing table calculation to be scheduled. In addition, timestamp the new LSA with the current time. The flooding procedure cannot overwrite the newly installed LSA until MinLSArrival seconds have elapsed. */ if (! (new = ospf_lsa_install (ospf, nbr->oi, new))) return -1; /* unknown LSA type or any other error condition */ /* Acknowledge the receipt of the LSA by sending a Link State Acknowledgment packet back out the receiving interface. */ if (lsa_ack_flag) ospf_flood_delayed_lsa_ack (nbr, new); /* If this new LSA indicates that it was originated by the receiving router itself, the router must take special action, either updating the LSA or in some cases flushing it from the routing domain. */ if (ospf_lsa_is_self_originated (ospf, new)) ospf_process_self_originated_lsa (ospf, new, oi->area); else /* Update statistics value for OSPF-MIB. */ ospf->rx_lsa_count++; return 0; } /* OSPF LSA flooding -- RFC2328 Section 13.3. */ static int ospf_flood_through_interface (struct ospf_interface *oi, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct ospf_neighbor *onbr; struct route_node *rn; int retx_flag; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_flood_through_interface(): " "considering int %s, INBR(%s), LSA[%s]", IF_NAME (oi), inbr ? inet_ntoa (inbr->router_id) : "NULL", dump_lsa_key (lsa)); if (!ospf_if_is_enable (oi)) return 0; /* Remember if new LSA is aded to a retransmit list. */ retx_flag = 0; /* Each of the neighbors attached to this interface are examined, to determine whether they must receive the new LSA. The following steps are executed for each neighbor: */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) { struct ospf_lsa *ls_req; if (rn->info == NULL) continue; onbr = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_flood_through_interface(): considering nbr %s (%s)", inet_ntoa (onbr->router_id), LOOKUP (ospf_nsm_state_msg, onbr->state)); /* If the neighbor is in a lesser state than Exchange, it does not participate in flooding, and the next neighbor should be examined. */ if (onbr->state < NSM_Exchange) continue; /* If the adjacency is not yet full (neighbor state is Exchange or Loading), examine the Link state request list associated with this adjacency. If there is an instance of the new LSA on the list, it indicates that the neighboring router has an instance of the LSA already. Compare the new LSA to the neighbor's copy: */ if (onbr->state < NSM_Full) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_flood_through_interface(): nbr adj is not Full"); ls_req = ospf_ls_request_lookup (onbr, lsa); if (ls_req != NULL) { int ret; ret = ospf_lsa_more_recent (ls_req, lsa); /* The new LSA is less recent. */ if (ret > 0) continue; /* The two copies are the same instance, then delete the LSA from the Link state request list. */ else if (ret == 0) { ospf_ls_request_delete (onbr, ls_req); ospf_check_nbr_loading (onbr); continue; } /* The new LSA is more recent. Delete the LSA from the Link state request list. */ else { ospf_ls_request_delete (onbr, ls_req); ospf_check_nbr_loading (onbr); } } } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type)) { if (! CHECK_FLAG (onbr->options, OSPF_OPTION_O)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: Not Opaque-capable."); continue; } if (IS_OPAQUE_LSA_ORIGINATION_BLOCKED (oi->ospf->opaque) && IS_LSA_SELF (lsa) && onbr->state == NSM_Full) { /* Small attempt to reduce unnecessary retransmission. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: Initial flushing done."); continue; } } #endif /* HAVE_OPAQUE_LSA */ /* If the new LSA was received from this neighbor, examine the next neighbor. */ #ifdef ORIGINAL_CODING if (inbr) if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) continue; #else /* ORIGINAL_CODING */ if (inbr) { /* * Triggered by LSUpd message parser "ospf_ls_upd ()". * E.g., all LSAs handling here is received via network. */ if (IPV4_ADDR_SAME (&inbr->router_id, &onbr->router_id)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: inbr == onbr"); continue; } } else { /* * Triggered by MaxAge remover, so far. * NULL "inbr" means flooding starts from this node. */ if (IPV4_ADDR_SAME (&lsa->data->adv_router, &onbr->router_id)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Skip this neighbor: lsah->adv_router == onbr"); continue; } } #endif /* ORIGINAL_CODING */ /* Add the new LSA to the Link state retransmission list for the adjacency. The LSA will be retransmitted at intervals until an acknowledgment is seen from the neighbor. */ ospf_ls_retransmit_add (onbr, lsa); retx_flag = 1; } /* If in the previous step, the LSA was NOT added to any of the Link state retransmission lists, there is no need to flood the LSA out the interface. */ if (retx_flag == 0) { return (inbr && inbr->oi == oi); } /* if we've received the lsa on this interface we need to perform additional checking */ if (inbr && (inbr->oi == oi)) { /* If the new LSA was received on this interface, and it was received from either the Designated Router or the Backup Designated Router, chances are that all the neighbors have received the LSA already. */ if (NBR_IS_DR (inbr) || NBR_IS_BDR (inbr)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "DR/BDR NOT SEND to int %s", IF_NAME (oi)); return 1; } /* If the new LSA was received on this interface, and the interface state is Backup, examine the next interface. The Designated Router will do the flooding on this interface. However, if the Designated Router fails the router will end up retransmitting the updates. */ if (oi->state == ISM_Backup) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "ISM_Backup NOT SEND to int %s", IF_NAME (oi)); return 1; } } /* The LSA must be flooded out the interface. Send a Link State Update packet (including the new LSA as contents) out the interface. The LSA's LS age must be incremented by InfTransDelay (which must be > 0) when it is copied into the outgoing Link State Update packet (until the LS age field reaches the maximum value of MaxAge). */ /* XXX HASSO: Is this IS_DEBUG_OSPF_NSSA really correct? */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through_interface(): " "DR/BDR sending upd to int %s", IF_NAME (oi)); /* RFC2328 Section 13.3 On non-broadcast networks, separate Link State Update packets must be sent, as unicasts, to each adjacent neighbor (i.e., those in state Exchange or greater). The destination IP addresses for these packets are the neighbors' IP addresses. */ if (oi->type == OSPF_IFTYPE_NBMA) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) ospf_ls_upd_send_lsa (nbr, lsa, OSPF_SEND_PACKET_DIRECT); } else ospf_ls_upd_send_lsa (oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT); return 0; } int ospf_flood_through_area (struct ospf_area *area, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_interface *oi; int lsa_ack_flag = 0; /* All other types are specific to a single area (Area A). The eligible interfaces are all those interfaces attaching to the Area A. If Area A is the backbone, this includes all the virtual links. */ for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) { if (area->area_id.s_addr != OSPF_AREA_BACKBONE && oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; #ifdef HAVE_OPAQUE_LSA if ((lsa->data->type == OSPF_OPAQUE_LINK_LSA) && (lsa->oi != oi)) { /* * Link local scoped Opaque-LSA should only be flooded * for the link on which the LSA has received. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("Type-9 Opaque-LSA: lsa->oi(%p) != oi(%p)", lsa->oi, oi); continue; } #endif /* HAVE_OPAQUE_LSA */ if (ospf_flood_through_interface (oi, inbr, lsa)) lsa_ack_flag = 1; } return (lsa_ack_flag); } int ospf_flood_through_as (struct ospf *ospf, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { struct listnode *node; struct ospf_area *area; int lsa_ack_flag; lsa_ack_flag = 0; /* The incoming LSA is type 5 or type 7 (AS-EXTERNAL or AS-NSSA ) Divert the Type-5 LSA's to all non-NSSA/STUB areas Divert the Type-7 LSA's to all NSSA areas AS-external-LSAs are flooded throughout the entire AS, with the exception of stub areas (see Section 3.6). The eligible interfaces are all the router's interfaces, excluding virtual links and those interfaces attaching to stub areas. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) /* Translated from 7 */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("Flood/AS: NSSA TRANSLATED LSA"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { int continue_flag = 0; struct listnode *if_node; struct ospf_interface *oi; switch (area->external_routing) { /* Don't send AS externals into stub areas. Various types of support for partial stub areas can be implemented here. NSSA's will receive Type-7's that have areas matching the originl LSA. */ case OSPF_AREA_NSSA: /* Sending Type 5 or 7 into NSSA area */ /* Type-7, flood NSSA area */ if (lsa->data->type == OSPF_AS_NSSA_LSA && area == lsa->area) /* We will send it. */ continue_flag = 0; else continue_flag = 1; /* Skip this NSSA area for Type-5's et al */ break; case OSPF_AREA_TYPE_MAX: case OSPF_AREA_STUB: continue_flag = 1; /* Skip this area. */ break; case OSPF_AREA_DEFAULT: default: /* No Type-7 into normal area */ if (lsa->data->type == OSPF_AS_NSSA_LSA) continue_flag = 1; /* skip Type-7 */ else continue_flag = 0; /* Do this area. */ break; } /* Do continue for above switch. Saves a big if then mess */ if (continue_flag) continue; /* main for-loop */ /* send to every interface in this area */ for (ALL_LIST_ELEMENTS_RO (area->oiflist, if_node, oi)) { /* Skip virtual links */ if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (ospf_flood_through_interface (oi, inbr, lsa)) /* lsa */ lsa_ack_flag = 1; } } /* main area for-loop */ return (lsa_ack_flag); } int ospf_flood_through (struct ospf *ospf, struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { int lsa_ack_flag = 0; /* Type-7 LSA's for NSSA are flooded throughout the AS here, and upon return are updated in the LSDB for Type-7's. Later, re-fresh will re-send them (and also, if ABR, packet code will translate to Type-5's) As usual, Type-5 LSA's (if not DISCARDED because we are STUB or NSSA) are flooded throughout the AS, and are updated in the global table. */ #ifdef ORIGINAL_CODING switch (lsa->data->type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: /* ospf_flood_through_interface ? */ case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ case OSPF_AS_NSSA_LSA: /* Any P-bit was installed with the Type-7. */ lsa_ack_flag = ospf_flood_through_area (inbr->oi->area, inbr, lsa); if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); break; default: break; } #else /* ORIGINAL_CODING */ /* * At the common sub-sub-function "ospf_flood_through_interface()", * a parameter "inbr" will be used to distinguish the called context * whether the given LSA was received from the neighbor, or the * flooding for the LSA starts from this node (e.g. the LSA was self- * originated, or the LSA is going to be flushed from routing domain). * * So, for consistency reasons, this function "ospf_flood_through()" * should also allow the usage that the given "inbr" parameter to be * NULL. If we do so, corresponding AREA parameter should be referred * by "lsa->area", instead of "inbr->oi->area". */ switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: /* Type-5 */ #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa_ack_flag = ospf_flood_through_as (ospf, inbr, lsa); break; /* Type-7 Only received within NSSA, then flooded */ case OSPF_AS_NSSA_LSA: /* Any P-bit was installed with the Type-7. */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_flood_through: LOCAL NSSA FLOOD of Type-7."); /* Fallthrough */ default: lsa_ack_flag = ospf_flood_through_area (lsa->area, inbr, lsa); break; } #endif /* ORIGINAL_CODING */ return (lsa_ack_flag); } /* Management functions for neighbor's Link State Request list. */ void ospf_ls_request_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { /* * We cannot make use of the newly introduced callback function * "lsdb->new_lsa_hook" to replace debug output below, just because * it seems no simple and smart way to pass neighbor information to * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("RqstL(%lu)++, NBR(%s), LSA[%s]", ospf_ls_request_count (nbr), inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); ospf_lsdb_add (&nbr->ls_req, lsa); } unsigned long ospf_ls_request_count (struct ospf_neighbor *nbr) { return ospf_lsdb_count_all (&nbr->ls_req); } int ospf_ls_request_isempty (struct ospf_neighbor *nbr) { return ospf_lsdb_isempty (&nbr->ls_req); } /* Remove LSA from neighbor's ls-request list. */ void ospf_ls_request_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { if (nbr->ls_req_last == lsa) { ospf_lsa_unlock (&nbr->ls_req_last); nbr->ls_req_last = NULL; } if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ zlog_debug ("RqstL(%lu)--, NBR(%s), LSA[%s]", ospf_ls_request_count (nbr), inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); ospf_lsdb_delete (&nbr->ls_req, lsa); } /* Remove all LSA from neighbor's ls-requenst list. */ void ospf_ls_request_delete_all (struct ospf_neighbor *nbr) { ospf_lsa_unlock (&nbr->ls_req_last); nbr->ls_req_last = NULL; ospf_lsdb_delete_all (&nbr->ls_req); } /* Lookup LSA from neighbor's ls-request list. */ struct ospf_lsa * ospf_ls_request_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { return ospf_lsdb_lookup (&nbr->ls_req, lsa); } struct ospf_lsa * ospf_ls_request_new (struct lsa_header *lsah) { struct ospf_lsa *new; new = ospf_lsa_new (); new->data = ospf_lsa_data_new (OSPF_LSA_HEADER_SIZE); memcpy (new->data, lsah, OSPF_LSA_HEADER_SIZE); return new; } /* Management functions for neighbor's ls-retransmit list. */ unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *nbr) { return ospf_lsdb_count_all (&nbr->ls_rxmt); } unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *nbr, int lsa_type) { return ospf_lsdb_count_self (&nbr->ls_rxmt, lsa_type); } int ospf_ls_retransmit_isempty (struct ospf_neighbor *nbr) { return ospf_lsdb_isempty (&nbr->ls_rxmt); } /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf_lsa *old; old = ospf_ls_retransmit_lookup (nbr, lsa); if (ospf_lsa_more_recent (old, lsa) < 0) { if (old) { old->retransmit_counter--; ospf_lsdb_delete (&nbr->ls_rxmt, old); } lsa->retransmit_counter++; /* * We cannot make use of the newly introduced callback function * "lsdb->new_lsa_hook" to replace debug output below, just because * it seems no simple and smart way to pass neighbor information to * the common function "ospf_lsdb_add()" -- endo. */ if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("RXmtL(%lu)++, NBR(%s), LSA[%s]", ospf_ls_retransmit_count (nbr), inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); ospf_lsdb_add (&nbr->ls_rxmt, lsa); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { if (ospf_ls_retransmit_lookup (nbr, lsa)) { lsa->retransmit_counter--; if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) /* -- endo. */ zlog_debug ("RXmtL(%lu)--, NBR(%s), LSA[%s]", ospf_ls_retransmit_count (nbr), inet_ntoa (nbr->router_id), dump_lsa_key (lsa)); ospf_lsdb_delete (&nbr->ls_rxmt, lsa); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear (struct ospf_neighbor *nbr) { struct ospf_lsdb *lsdb; int i; lsdb = &nbr->ls_rxmt; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { struct route_table *table = lsdb->type[i].db; struct route_node *rn; struct ospf_lsa *lsa; for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = rn->info) != NULL) ospf_ls_retransmit_delete (nbr, lsa); } ospf_lsa_unlock (&nbr->ls_req_last); nbr->ls_req_last = NULL; } /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa * ospf_ls_retransmit_lookup (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { return ospf_lsdb_lookup (&nbr->ls_rxmt, lsa); } static void ospf_ls_retransmit_delete_nbr_if (struct ospf_interface *oi, struct ospf_lsa *lsa) { struct route_node *rn; struct ospf_neighbor *nbr; struct ospf_lsa *lsr; if (ospf_if_is_enable (oi)) for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) /* If LSA find in LS-retransmit list, then remove it. */ if ((nbr = rn->info) != NULL) { lsr = ospf_ls_retransmit_lookup (nbr, lsa); /* If LSA find in ls-retransmit list, remove it. */ if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum) ospf_ls_retransmit_delete (nbr, lsr); } } void ospf_ls_retransmit_delete_nbr_area (struct ospf_area *area, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (area->oiflist, node, nnode, oi)) ospf_ls_retransmit_delete_nbr_if (oi, lsa); } void ospf_ls_retransmit_delete_nbr_as (struct ospf *ospf, struct ospf_lsa *lsa) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) ospf_ls_retransmit_delete_nbr_if (oi, lsa); } /* Sets ls_age to MaxAge and floods throu the area. When we implement ASE routing, there will be anothe function flushing an LSA from the whole domain. */ void ospf_lsa_flush_area (struct ospf_lsa *lsa, struct ospf_area *area) { /* Reset the lsa origination time such that it gives more time for the ACK to be received and avoid retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); lsa->tv_recv = recent_relative_time (); lsa->tv_orig = lsa->tv_recv; ospf_flood_through_area (area, NULL, lsa); ospf_lsa_maxage (area->ospf, lsa); } void ospf_lsa_flush_as (struct ospf *ospf, struct ospf_lsa *lsa) { /* Reset the lsa origination time such that it gives more time for the ACK to be received and avoid retransmissions */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); lsa->tv_recv = recent_relative_time (); lsa->tv_orig = lsa->tv_recv; ospf_flood_through_as (ospf, NULL, lsa); ospf_lsa_maxage (ospf, lsa); } void ospf_lsa_flush (struct ospf *ospf, struct ospf_lsa *lsa) { lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_area (lsa, lsa->area); break; case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ ospf_lsa_flush_as (ospf, lsa); break; default: zlog_info ("%s: Unknown LSA type %u", __func__, lsa->data->type); break; } } quagga-0.99.24.1/ospfd/ospf_ia.c0000644000175000017500000004704312476520570013143 00000000000000/* * OSPF inter-area routing. * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "hash.h" #include "linklist.h" #include "prefix.h" #include "table.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_ia.h" #include "ospfd/ospf_dump.h" static struct ospf_route * ospf_find_abr_route (struct route_table *rtrs, struct prefix_ipv4 *abr, struct ospf_area *area) { struct route_node *rn; struct ospf_route *or; struct listnode *node; if ((rn = route_node_lookup (rtrs, (struct prefix *) abr)) == NULL) return NULL; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id) && (or->u.std.flags & ROUTER_LSA_BORDER)) return or; return NULL; } static void ospf_ia_network_route (struct ospf *ospf, struct route_table *rt, struct prefix_ipv4 *p, struct ospf_route *new_or, struct ospf_route *abr_or) { struct route_node *rn1; struct ospf_route *or; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_network_route(): processing summary route to %s/%d", inet_ntoa (p->prefix), p->prefixlen); /* Find a route to the same dest */ if ((rn1 = route_node_lookup (rt, (struct prefix *) p))) { int res; route_unlock_node (rn1); if ((or = rn1->info)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_network_route(): " "Found a route to the same network"); /* Check the existing route. */ if ((res = ospf_route_cmp (ospf, new_or, or)) < 0) { /* New route is better, so replace old one. */ ospf_route_subst (rn1, new_or, abr_or); } else if (res == 0) { /* New and old route are equal, so next hops can be added. */ route_lock_node (rn1); ospf_route_copy_nexthops (or, abr_or->paths); route_unlock_node (rn1); /* new route can be deleted, because existing route has been updated. */ ospf_route_free (new_or); } else { /* New route is worse, so free it. */ ospf_route_free (new_or); return; } } /* if (or)*/ } /*if (rn1)*/ else { /* no route */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_network_route(): add new route to %s/%d", inet_ntoa (p->prefix), p->prefixlen); ospf_route_add (rt, p, new_or, abr_or); } } static void ospf_ia_router_route (struct ospf *ospf, struct route_table *rtrs, struct prefix_ipv4 *p, struct ospf_route *new_or, struct ospf_route *abr_or) { struct ospf_route *or = NULL; struct route_node *rn; int ret; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): considering %s/%d", inet_ntoa (p->prefix), p->prefixlen); /* Find a route to the same dest */ rn = route_node_get (rtrs, (struct prefix *) p); if (rn->info == NULL) /* This is a new route */ rn->info = list_new (); else { struct ospf_area *or_area; or_area = ospf_area_lookup_by_area_id (ospf, new_or->u.std.area_id); assert (or_area); /* This is an additional route */ route_unlock_node (rn); or = ospf_find_asbr_route_through_area (rtrs, p, or_area); } if (or) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): " "a route to the same ABR through the same area exists"); /* New route is better */ if ((ret = ospf_route_cmp (ospf, new_or, or)) < 0) { listnode_delete (rn->info, or); ospf_route_free (or); /* proceed down */ } /* Routes are the same */ else if (ret == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): merging the new route"); ospf_route_copy_nexthops (or, abr_or->paths); ospf_route_free (new_or); return; } /* New route is worse */ else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): skipping the new route"); ospf_route_free (new_or); return; } } ospf_route_copy_nexthops (new_or, abr_or->paths); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_router_route(): adding the new route"); listnode_add (rn->info, new_or); } static int process_summary_lsa (struct ospf_area *area, struct route_table *rt, struct route_table *rtrs, struct ospf_lsa *lsa) { struct ospf *ospf = area->ospf; struct ospf_area_range *range; struct ospf_route *abr_or, *new_or; struct summary_lsa *sl; struct prefix_ipv4 p, abr; u_int32_t metric; if (lsa == NULL) return 0; sl = (struct summary_lsa *) lsa->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_summary_lsa(): LS ID: %s", inet_ntoa (sl->header.id)); metric = GET_METRIC (sl->metric); if (metric == OSPF_LS_INFINITY) return 0; if (IS_LSA_MAXAGE (lsa)) return 0; if (ospf_lsa_is_self_originated (area->ospf, lsa)) return 0; p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen (sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&p); if (sl->header.type == OSPF_SUMMARY_LSA && (range = ospf_area_range_match_any (ospf, &p)) && ospf_area_range_active (range)) return 0; /* XXX: This check seems dubious to me. If an ABR has already decided * to consider summaries received in this area, then why would one wish * to exclude default? */ if (IS_OSPF_ABR(ospf) && ospf->abr_type != OSPF_ABR_STAND && area->external_routing != OSPF_AREA_DEFAULT && p.prefix.s_addr == OSPF_DEFAULT_DESTINATION && p.prefixlen == 0) return 0; /* Ignore summary default from a stub area */ abr.family = AF_INET; abr.prefix = sl->header.adv_router; abr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&abr); abr_or = ospf_find_abr_route (rtrs, &abr, area); if (abr_or == NULL) return 0; new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_NETWORK; new_or->id = sl->header.id; new_or->mask = sl->mask; new_or->u.std.options = sl->header.options; new_or->u.std.origin = (struct lsa_header *) sl; new_or->cost = abr_or->cost + metric; new_or->u.std.area_id = area->area_id; new_or->u.std.external_routing = area->external_routing; new_or->path_type = OSPF_PATH_INTER_AREA; if (sl->header.type == OSPF_SUMMARY_LSA) ospf_ia_network_route (ospf, rt, &p, new_or, abr_or); else { new_or->type = OSPF_DESTINATION_ROUTER; new_or->u.std.flags = ROUTER_LSA_EXTERNAL; ospf_ia_router_route (ospf, rtrs, &p, new_or, abr_or); } return 0; } static void ospf_examine_summaries (struct ospf_area *area, struct route_table *lsdb_rt, struct route_table *rt, struct route_table *rtrs) { struct ospf_lsa *lsa; struct route_node *rn; LSDB_LOOP (lsdb_rt, rn, lsa) process_summary_lsa (area, rt, rtrs, lsa); } int ospf_area_is_transit (struct ospf_area *area) { return (area->transit == OSPF_TRANSIT_TRUE) || ospf_full_virtual_nbrs(area); /* Cisco forgets to set the V-bit :( */ } static void ospf_update_network_route (struct ospf *ospf, struct route_table *rt, struct route_table *rtrs, struct summary_lsa *lsa, struct prefix_ipv4 *p, struct ospf_area *area) { struct route_node *rn; struct ospf_route *or, *abr_or, *new_or; struct prefix_ipv4 abr; u_int32_t cost; abr.family = AF_INET; abr.prefix =lsa->header.adv_router; abr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&abr); abr_or = ospf_find_abr_route (rtrs, &abr, area); if (abr_or == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): can't find a route to the ABR"); return; } cost = abr_or->cost + GET_METRIC (lsa->metric); rn = route_node_lookup (rt, (struct prefix *) p); if (! rn) { if (ospf->abr_type != OSPF_ABR_SHORTCUT) return; /* Standard ABR can update only already installed backbone paths */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "Allowing Shortcut ABR to add new route"); new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_NETWORK; new_or->id = lsa->header.id; new_or->mask = lsa->mask; new_or->u.std.options = lsa->header.options; new_or->u.std.origin = (struct lsa_header *) lsa; new_or->cost = cost; new_or->u.std.area_id = area->area_id; new_or->u.std.external_routing = area->external_routing; new_or->path_type = OSPF_PATH_INTER_AREA; ospf_route_add (rt, p, new_or, abr_or); return; } else { route_unlock_node (rn); if (rn->info == NULL) return; } or = rn->info; if (or->path_type != OSPF_PATH_INTRA_AREA && or->path_type != OSPF_PATH_INTER_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): ERR: path type is wrong"); return; } if (ospf->abr_type == OSPF_ABR_SHORTCUT) { if (or->path_type == OSPF_PATH_INTRA_AREA && !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): Shortcut: " "this intra-area path is not backbone"); return; } } else /* Not Shortcut ABR */ { if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "route is not BB-associated"); return; /* We can update only BB routes */ } } if (or->cost < cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): new route is worse"); return; } if (or->cost == cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "new route is same distance, adding nexthops"); ospf_route_copy_nexthops (or, abr_or->paths); } if (or->cost > cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_network_route(): " "new route is better, overriding nexthops"); ospf_route_subst_nexthops (or, abr_or->paths); or->cost = cost; if ((ospf->abr_type == OSPF_ABR_SHORTCUT) && !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) { or->path_type = OSPF_PATH_INTER_AREA; or->u.std.area_id = area->area_id; or->u.std.external_routing = area->external_routing; /* Note that we can do this only in Shortcut ABR mode, because standard ABR must leave the route type and area unchanged */ } } } static void ospf_update_router_route (struct ospf *ospf, struct route_table *rtrs, struct summary_lsa *lsa, struct prefix_ipv4 *p, struct ospf_area *area) { struct ospf_route *or, *abr_or, *new_or; struct prefix_ipv4 abr; u_int32_t cost; abr.family = AF_INET; abr.prefix = lsa->header.adv_router; abr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&abr); abr_or = ospf_find_abr_route (rtrs, &abr, area); if (abr_or == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_update_router_route(): can't find a route to the ABR"); return; } cost = abr_or->cost + GET_METRIC (lsa->metric); /* First try to find a backbone path, because standard ABR can update only BB-associated paths */ if ((ospf->backbone == NULL) && (ospf->abr_type != OSPF_ABR_SHORTCUT)) return; /* no BB area, not Shortcut ABR, exiting */ /* find the backbone route, if possible */ if ((ospf->backbone == NULL) || !(or = ospf_find_asbr_route_through_area (rtrs, p, ospf->backbone))) { if (ospf->abr_type != OSPF_ABR_SHORTCUT) /* route to ASBR through the BB not found the router is not Shortcut ABR, exiting */ return; else /* We're a Shortcut ABR*/ { /* Let it either add a new router or update the route through the same (non-BB) area. */ new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_ROUTER; new_or->id = lsa->header.id; new_or->mask = lsa->mask; new_or->u.std.options = lsa->header.options; new_or->u.std.origin = (struct lsa_header *)lsa; new_or->cost = cost; new_or->u.std.area_id = area->area_id; new_or->u.std.external_routing = area->external_routing; new_or->path_type = OSPF_PATH_INTER_AREA; new_or->u.std.flags = ROUTER_LSA_EXTERNAL; ospf_ia_router_route (ospf, rtrs, p, new_or, abr_or); return; } } /* At this point the "or" is always bb-associated */ if (!(or->u.std.flags & ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_upd_router_route(): the remote router is not an ASBR"); return; } if (or->path_type != OSPF_PATH_INTRA_AREA && or->path_type != OSPF_PATH_INTER_AREA) return; if (or->cost < cost) return; else if (or->cost == cost) ospf_route_copy_nexthops (or, abr_or->paths); else if (or->cost > cost) { ospf_route_subst_nexthops (or, abr_or->paths); or->cost = cost; /* Even if the ABR runs in Shortcut mode, we can't change the path type and area, because the "or" is always bb-associated at this point and even Shortcut ABR can't change these attributes */ } } static int process_transit_summary_lsa (struct ospf_area *area, struct route_table *rt, struct route_table *rtrs, struct ospf_lsa *lsa) { struct ospf *ospf = area->ospf; struct summary_lsa *sl; struct prefix_ipv4 p; u_int32_t metric; if (lsa == NULL) return 0; sl = (struct summary_lsa *) lsa->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_transit_summaries(): LS ID: %s", inet_ntoa (lsa->data->id)); metric = GET_METRIC (sl->metric); if (metric == OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_transit_summaries(): metric is infinity, skip"); return 0; } if (IS_LSA_MAXAGE (lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_transit_summaries(): This LSA is too old"); return 0; } if (ospf_lsa_is_self_originated (area->ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("process_transit_summaries(): This LSA is mine, skip"); return 0; } p.family = AF_INET; p.prefix = sl->header.id; if (sl->header.type == OSPF_SUMMARY_LSA) p.prefixlen = ip_masklen (sl->mask); else p.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&p); if (sl->header.type == OSPF_SUMMARY_LSA) ospf_update_network_route (ospf, rt, rtrs, sl, &p, area); else ospf_update_router_route (ospf, rtrs, sl, &p, area); return 0; } static void ospf_examine_transit_summaries (struct ospf_area *area, struct route_table *lsdb_rt, struct route_table *rt, struct route_table *rtrs) { struct ospf_lsa *lsa; struct route_node *rn; LSDB_LOOP (lsdb_rt, rn, lsa) process_transit_summary_lsa (area, rt, rtrs, lsa); } void ospf_ia_routing (struct ospf *ospf, struct route_table *rt, struct route_table *rtrs) { struct ospf_area * area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():start"); if (IS_OSPF_ABR (ospf)) { struct listnode *node; struct ospf_area *area; switch (ospf->abr_type) { case OSPF_ABR_STAND: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():Standard ABR"); if ((area = ospf->backbone)) { struct listnode *node; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_ia_routing():backbone area found"); zlog_debug ("ospf_ia_routing():examining summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if (area != ospf->backbone) if (ospf_area_is_transit (area)) OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); } else if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():backbone area NOT found"); break; case OSPF_ABR_IBM: case OSPF_ABR_CISCO: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():Alternative Cisco/IBM ABR"); area = ospf->backbone; /* Find the BB */ /* If we have an active BB connection */ if (area && ospf_act_bb_connection (ospf)) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_ia_routing(): backbone area found"); zlog_debug ("ospf_ia_routing(): examining BB summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if (area != ospf->backbone) if (ospf_area_is_transit (area)) OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); } else { /* No active BB connection--consider all areas */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing(): " "Active BB connection not found"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } break; case OSPF_ABR_SHORTCUT: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():Alternative Shortcut"); area = ospf->backbone; /* Find the BB */ /* If we have an active BB connection */ if (area && ospf_act_bb_connection (ospf)) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_ia_routing(): backbone area found"); zlog_debug ("ospf_ia_routing(): examining BB summaries"); } OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if (area != ospf->backbone) if (ospf_area_is_transit (area) || ((area->shortcut_configured != OSPF_SHORTCUT_DISABLE) && ((ospf->backbone == NULL) || ((area->shortcut_configured == OSPF_SHORTCUT_ENABLE) && area->shortcut_capability)))) OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL (area, rt, rtrs); break; default: break; } } else { struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ia_routing():not ABR, considering all areas"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) OSPF_EXAMINE_SUMMARIES_ALL (area, rt, rtrs); } } quagga-0.99.24.1/ospfd/ospf_abr.c0000644000175000017500000014535012476520570013316 00000000000000/* * OSPF ABR functions. * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "vty.h" #include "filter.h" #include "plist.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ia.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" static struct ospf_area_range * ospf_area_range_new (struct prefix_ipv4 *p) { struct ospf_area_range *range; range = XCALLOC (MTYPE_OSPF_AREA_RANGE, sizeof (struct ospf_area_range)); range->addr = p->prefix; range->masklen = p->prefixlen; range->cost_config = OSPF_AREA_RANGE_COST_UNSPEC; return range; } static void ospf_area_range_free (struct ospf_area_range *range) { XFREE (MTYPE_OSPF_AREA_RANGE, range); } static void ospf_area_range_add (struct ospf_area *area, struct ospf_area_range *range) { struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefixlen = range->masklen; p.prefix = range->addr; rn = route_node_get (area->ranges, (struct prefix *)&p); if (rn->info) route_unlock_node (rn); else rn->info = range; } static void ospf_area_range_delete (struct ospf_area *area, struct route_node *rn) { struct ospf_area_range *range = rn->info; if (range->specifics != 0) ospf_delete_discard_route (area->ospf->new_table, (struct prefix_ipv4 *) &rn->p); ospf_area_range_free (range); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } struct ospf_area_range * ospf_area_range_lookup (struct ospf_area *area, struct prefix_ipv4 *p) { struct route_node *rn; rn = route_node_lookup (area->ranges, (struct prefix *)p); if (rn) { route_unlock_node (rn); return rn->info; } return NULL; } struct ospf_area_range * ospf_area_range_lookup_next (struct ospf_area *area, struct in_addr *range_net, int first) { struct route_node *rn; struct prefix_ipv4 p; struct ospf_area_range *find; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.prefix = *range_net; if (first) rn = route_top (area->ranges); else { rn = route_node_get (area->ranges, (struct prefix *) &p); rn = route_next (rn); } for (; rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { find = rn->info; *range_net = rn->p.u.prefix4; route_unlock_node (rn); return find; } return NULL; } static struct ospf_area_range * ospf_area_range_match (struct ospf_area *area, struct prefix_ipv4 *p) { struct route_node *node; node = route_node_match (area->ranges, (struct prefix *) p); if (node) { route_unlock_node (node); return node->info; } return NULL; } struct ospf_area_range * ospf_area_range_match_any (struct ospf *ospf, struct prefix_ipv4 *p) { struct ospf_area_range *range; struct ospf_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if ((range = ospf_area_range_match (area, p))) return range; return NULL; } int ospf_area_range_active (struct ospf_area_range *range) { return range->specifics; } static int ospf_area_actively_attached (struct ospf_area *area) { return area->act_ints; } int ospf_area_range_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, int advertise) { struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range != NULL) { if ((CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) && !CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) || (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) && CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE))) ospf_schedule_abr_task (ospf); } else { range = ospf_area_range_new (p); ospf_area_range_add (area, range); ospf_schedule_abr_task (ospf); } if (CHECK_FLAG (advertise, OSPF_AREA_RANGE_ADVERTISE)) SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); else UNSET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); return 1; } int ospf_area_range_cost_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, u_int32_t cost) { struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range == NULL) return 0; if (range->cost_config != cost) { range->cost_config = cost; if (ospf_area_range_active (range)) ospf_schedule_abr_task (ospf); } return 1; } int ospf_area_range_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p) { struct ospf_area *area; struct route_node *rn; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; rn = route_node_lookup (area->ranges, (struct prefix*)p); if (rn == NULL) return 0; if (ospf_area_range_active (rn->info)) ospf_schedule_abr_task (ospf); ospf_area_range_delete (area, rn); return 1; } int ospf_area_range_substitute_set (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p, struct prefix_ipv4 *s) { struct ospf_area *area; struct ospf_area_range *range; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, ret); range = ospf_area_range_lookup (area, p); if (range != NULL) { if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE) || !CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) ospf_schedule_abr_task (ospf); } else { range = ospf_area_range_new (p); ospf_area_range_add (area, range); ospf_schedule_abr_task (ospf); } SET_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE); SET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); range->subst_addr = s->prefix; range->subst_masklen = s->prefixlen; return 1; } int ospf_area_range_substitute_unset (struct ospf *ospf, struct in_addr area_id, struct prefix_ipv4 *p) { struct ospf_area *area; struct ospf_area_range *range; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; range = ospf_area_range_lookup (area, p); if (range == NULL) return 0; if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) if (ospf_area_range_active (range)) ospf_schedule_abr_task (ospf); UNSET_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE); range->subst_addr.s_addr = 0; range->subst_masklen = 0; return 1; } int ospf_act_bb_connection (struct ospf *ospf) { if (ospf->backbone == NULL) return 0; return ospf->backbone->full_nbrs; } /* Determine whether this router is elected translator or not for area */ static int ospf_abr_nssa_am_elected (struct ospf_area *area) { struct route_node *rn; struct ospf_lsa *lsa; struct router_lsa *rlsa; struct in_addr *best = NULL; LSDB_LOOP ( ROUTER_LSDB (area), rn, lsa) { /* sanity checks */ if (!lsa || (lsa->data->type != OSPF_ROUTER_LSA) || IS_LSA_SELF (lsa)) continue; rlsa = (struct router_lsa *) lsa->data; /* ignore non-ABR routers */ if (!IS_ROUTER_LSA_BORDER (rlsa)) continue; /* Router has Nt flag - always translate */ if (IS_ROUTER_LSA_NT (rlsa)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_am_elected: " "router %s asserts Nt", inet_ntoa (lsa->data->id) ); return 0; } if (best == NULL) best = &lsa->data->id; else if (IPV4_ADDR_CMP (&best->s_addr, &lsa->data->id.s_addr) < 0) best = &lsa->data->id; } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_am_elected: best electable ABR is: %s", (best) ? inet_ntoa (*best) : "" ); if (best == NULL) return 1; if (IPV4_ADDR_CMP (&best->s_addr, &area->ospf->router_id.s_addr) < 0) return 1; else return 0; } /* Check NSSA ABR status * assumes there are nssa areas */ static void ospf_abr_nssa_check_status (struct ospf *ospf) { struct ospf_area *area; struct listnode *lnode, *nnode; for (ALL_LIST_ELEMENTS (ospf->areas, lnode, nnode, area)) { u_char old_state = area->NSSATranslatorState; if (area->external_routing != OSPF_AREA_NSSA) continue; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "checking area %s", inet_ntoa (area->area_id)); if (!IS_OSPF_ABR (area->ospf)) { if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "not ABR"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; } else { switch (area->NSSATranslatorRole) { case OSPF_NSSA_ROLE_NEVER: /* We never Translate Type-7 LSA. */ /* TODO: check previous state and flush? */ if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "never translate"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; break; case OSPF_NSSA_ROLE_ALWAYS: /* We always translate if we are an ABR * TODO: originate new LSAs if state change? * or let the nssa abr task take care of it? */ if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "translate always"); area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED; break; case OSPF_NSSA_ROLE_CANDIDATE: /* We are a candidate for Translation */ if (ospf_abr_nssa_am_elected (area) > 0) { area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_ENABLED; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "elected translator"); } else { area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; if (IS_DEBUG_OSPF (nssa, NSSA)) zlog_debug ("ospf_abr_nssa_check_status: " "not elected"); } break; } } /* RFC3101, 3.1: * All NSSA border routers must set the E-bit in the Type-1 router-LSAs * of their directly attached non-stub areas, even when they are not * translating. */ if (old_state != area->NSSATranslatorState) { if (old_state == OSPF_NSSA_TRANSLATE_DISABLED) ospf_asbr_status_update (ospf, ++ospf->redistribute); else if (area->NSSATranslatorState == OSPF_NSSA_TRANSLATE_DISABLED) ospf_asbr_status_update (ospf, --ospf->redistribute); } } } /* Check area border router status. */ void ospf_check_abr_status (struct ospf *ospf) { struct ospf_area *area; struct listnode *node, *nnode; int bb_configured = 0; int bb_act_attached = 0; int areas_configured = 0; int areas_act_attached = 0; u_char new_flags = ospf->flags; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_check_abr_status(): Start"); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if (listcount (area->oiflist)) { areas_configured++; if (OSPF_IS_AREA_BACKBONE (area)) bb_configured = 1; } if (ospf_area_actively_attached (area)) { areas_act_attached++; if (OSPF_IS_AREA_BACKBONE (area)) bb_act_attached = 1; } } if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_check_abr_status(): looked through areas"); zlog_debug ("ospf_check_abr_status(): bb_configured: %d", bb_configured); zlog_debug ("ospf_check_abr_status(): bb_act_attached: %d", bb_act_attached); zlog_debug ("ospf_check_abr_status(): areas_configured: %d", areas_configured); zlog_debug ("ospf_check_abr_status(): areas_act_attached: %d", areas_act_attached); } switch (ospf->abr_type) { case OSPF_ABR_SHORTCUT: case OSPF_ABR_STAND: if (areas_act_attached > 1) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; case OSPF_ABR_IBM: if ((areas_act_attached > 1) && bb_configured) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; case OSPF_ABR_CISCO: if ((areas_configured > 1) && bb_act_attached) SET_FLAG (new_flags, OSPF_FLAG_ABR); else UNSET_FLAG (new_flags, OSPF_FLAG_ABR); break; default: break; } if (new_flags != ospf->flags) { ospf_spf_calculate_schedule (ospf, SPF_FLAG_ABR_STATUS_CHANGE); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_check_abr_status(): new router flags: %x",new_flags); ospf->flags = new_flags; ospf_router_lsa_update (ospf); } } static void ospf_abr_update_aggregate (struct ospf_area_range *range, struct ospf_route *or, struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): Start"); if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED) && (range->cost != OSPF_STUB_MAX_METRIC_SUMMARY_COST)) { range->cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use summary max-metric 0x%08x", range->cost); } else if (range->cost_config != OSPF_AREA_RANGE_COST_UNSPEC) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use configured cost %d", range->cost_config); range->cost = range->cost_config; } else { if (range->specifics == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): use or->cost %d", or->cost); range->cost = or->cost; /* 1st time get 1st cost */ } if (or->cost > range->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_update_aggregate(): update to %d", or->cost); range->cost = or->cost; } } range->specifics++; } static void set_metric (struct ospf_lsa *lsa, u_int32_t metric) { struct summary_lsa *header; u_char *mp; metric = htonl (metric); mp = (u_char *) &metric; mp++; header = (struct summary_lsa *) lsa->data; memcpy(header->metric, mp, 3); } /* ospf_abr_translate_nssa */ static int ospf_abr_translate_nssa (struct ospf_area *area, struct ospf_lsa *lsa) { /* Incoming Type-7 or later aggregated Type-7 * * LSA is skipped if P-bit is off. * LSA is aggregated if within range. * * The Type-7 is translated, Installed/Approved as a Type-5 into * global LSDB, then Flooded through AS * * Later, any Unapproved Translated Type-5's are flushed/discarded */ struct ospf_lsa *old = NULL, *new = NULL; struct as_external_lsa *ext7; struct prefix_ipv4 p; if (! CHECK_FLAG (lsa->data->options, OSPF_OPTION_NP)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, P-bit off, NO Translation", inet_ntoa (lsa->data->id)); return 1; } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, TRANSLATING 7 to 5", inet_ntoa (lsa->data->id)); ext7 = (struct as_external_lsa *)(lsa->data); p.prefix = lsa->data->id; p.prefixlen = ip_masklen (ext7->mask); if (ext7->e[0].fwd_addr.s_addr == OSPF_DEFAULT_DESTINATION) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): LSA Id %s, " "Forward address is 0, NO Translation", inet_ntoa (lsa->data->id)); return 1; } /* try find existing AS-External LSA for this prefix */ old = ospf_external_info_find_lsa (area->ospf, &p); if (old) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): " "found old translated LSA Id %s, refreshing", inet_ntoa (old->data->id)); /* refresh */ new = ospf_translated_nssa_refresh (area->ospf, lsa, old); if (!new) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): " "could not refresh translated LSA Id %s", inet_ntoa (old->data->id)); } } else { /* no existing external route for this LSA Id * originate translated LSA */ if ((new = ospf_translated_nssa_originate (area->ospf, lsa)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_translate_nssa(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (lsa->data->id)); return 1; } } /* Area where Aggregate testing will be inserted, just like summary advertisements */ /* ospf_abr_check_nssa_range (p_arg, lsa-> cost, lsa -> area); */ return 0; } static void ospf_abr_translate_nssa_range (struct prefix_ipv4 *p, u_int32_t cost) { /* The Type-7 is created from the aggregated prefix and forwarded for lsa installation and flooding... to be added... */ } void ospf_abr_announce_network_to_area (struct prefix_ipv4 *p, u_int32_t cost, struct ospf_area *area) { struct ospf_lsa *lsa, *old = NULL; struct summary_lsa *sl = NULL; u_int32_t full_cost; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): Start"); if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) full_cost = OSPF_STUB_MAX_METRIC_SUMMARY_COST; else full_cost = cost; old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_SUMMARY_LSA, (struct prefix_ipv4 *) p, area->ospf->router_id); if (old) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): old summary found"); sl = (struct summary_lsa *) old->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (sl->metric), cost); if ((GET_METRIC (sl->metric) == full_cost) && ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { /* unchanged. simply reapprove it */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old summary approved"); SET_FLAG (old->flags, OSPF_LSA_APPROVED); } else { /* LSA is changed, refresh it */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "refreshing summary"); set_metric (old, full_cost); lsa = ospf_lsa_refresh (area->ospf, old); if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *) p, buf, sizeof(buf)); zlog_warn ("%s: Could not refresh %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); /* This will flood through area. */ } } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "creating new summary"); lsa = ospf_summary_lsa_originate ( (struct prefix_ipv4 *)p, full_cost, area); /* This will flood through area. */ if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *)p, buf, sizeof(buf)); zlog_warn ("%s: Could not originate %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "flooding new version of summary"); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): Stop"); } static int ospf_abr_nexthops_belong_to_area (struct ospf_route *or, struct ospf_area *area) { struct listnode *node, *nnode; struct ospf_path *path; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) for (ALL_LIST_ELEMENTS_RO (area->oiflist, nnode, oi)) if (oi->ifp && oi->ifp->ifindex == path->ifindex) return 1; return 0; } static int ospf_abr_should_accept (struct prefix_ipv4 *p, struct ospf_area *area) { if (IMPORT_NAME (area)) { if (IMPORT_LIST (area) == NULL) IMPORT_LIST (area) = access_list_lookup (AFI_IP, IMPORT_NAME (area)); if (IMPORT_LIST (area)) if (access_list_apply (IMPORT_LIST (area), p) == FILTER_DENY) return 0; } return 1; } static int ospf_abr_plist_in_check (struct ospf_area *area, struct ospf_route *or, struct prefix_ipv4 *p) { if (PREFIX_NAME_IN (area)) { if (PREFIX_LIST_IN (area) == NULL) PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); if (PREFIX_LIST_IN (area)) if (prefix_list_apply (PREFIX_LIST_IN (area), p) != PREFIX_PERMIT) return 0; } return 1; } static int ospf_abr_plist_out_check (struct ospf_area *area, struct ospf_route *or, struct prefix_ipv4 *p) { if (PREFIX_NAME_OUT (area)) { if (PREFIX_LIST_OUT (area) == NULL) PREFIX_LIST_OUT (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); if (PREFIX_LIST_OUT (area)) if (prefix_list_apply (PREFIX_LIST_OUT (area), p) != PREFIX_PERMIT) return 0; } return 1; } static void ospf_abr_announce_network (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_route *or) { struct ospf_area_range *range; struct ospf_area *area, *or_area; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): Start"); or_area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id); assert (or_area); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): looking at area %s", inet_ntoa (area->area_id)); if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) continue; if (ospf_abr_nexthops_belong_to_area (or, area)) continue; if (!ospf_abr_should_accept (p, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): " "prefix %s/%d was denied by import-list", inet_ntoa (p->prefix), p->prefixlen); continue; } if (!ospf_abr_plist_in_check (area, or, p)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): " "prefix %s/%d was denied by prefix-list", inet_ntoa (p->prefix), p->prefixlen); continue; } if (area->external_routing != OSPF_AREA_DEFAULT && area->no_summary) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): " "area %s is stub and no_summary", inet_ntoa (area->area_id)); continue; } if (or->path_type == OSPF_PATH_INTER_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): this is " "inter-area route to %s/%d", inet_ntoa (p->prefix), p->prefixlen); if (!OSPF_IS_AREA_BACKBONE (area)) ospf_abr_announce_network_to_area (p, or->cost, area); } if (or->path_type == OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network(): " "this is intra-area route to %s/%d", inet_ntoa (p->prefix), p->prefixlen); if ((range = ospf_area_range_match (or_area, p)) && !ospf_area_is_transit (area)) ospf_abr_update_aggregate (range, or, area); else ospf_abr_announce_network_to_area (p, or->cost, area); } } } static int ospf_abr_should_announce (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_route *or) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id); assert (area); if (EXPORT_NAME (area)) { if (EXPORT_LIST (area) == NULL) EXPORT_LIST (area) = access_list_lookup (AFI_IP, EXPORT_NAME (area)); if (EXPORT_LIST (area)) if (access_list_apply (EXPORT_LIST (area), p) == FILTER_DENY) return 0; } return 1; } static void ospf_abr_process_nssa_translates (struct ospf *ospf) { /* Scan through all NSSA_LSDB records for all areas; If P-bit is on, translate all Type-7's to 5's and aggregate or flood install as approved in Type-5 LSDB with XLATE Flag on later, do same for all aggregates... At end, DISCARD all remaining UNAPPROVED Type-5's (Aggregate is for future ) */ struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_process_nssa_translates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (! area->NSSATranslatorState) continue; /* skip if not translator */ if (area->external_routing != OSPF_AREA_NSSA) continue; /* skip if not Nssa Area */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_process_nssa_translates(): " "looking at area %s", inet_ntoa (area->area_id)); LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_abr_translate_nssa (area, lsa); } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_process_nssa_translates(): Stop"); } static void ospf_abr_process_network_rt (struct ospf *ospf, struct route_table *rt) { struct ospf_area *area; struct ospf_route *or; struct route_node *rn; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): Start"); for (rn = route_top (rt); rn; rn = route_next (rn)) { if ((or = rn->info) == NULL) continue; if (!(area = ospf_area_lookup_by_area_id (ospf, or->u.std.area_id))) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): area %s no longer exists", inet_ntoa (or->u.std.area_id)); continue; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): this is a route to %s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); if (or->path_type >= OSPF_PATH_TYPE1_EXTERNAL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): " "this is an External router, skipping"); continue; } if (or->cost >= OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt():" " this route's cost is infinity, skipping"); continue; } if (or->type == OSPF_DESTINATION_DISCARD) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt():" " this is a discard entry, skipping"); continue; } if (or->path_type == OSPF_PATH_INTRA_AREA && !ospf_abr_should_announce (ospf, (struct prefix_ipv4 *) &rn->p, or)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_abr_process_network_rt(): denied by export-list"); continue; } if (or->path_type == OSPF_PATH_INTRA_AREA && !ospf_abr_plist_out_check (area, or, (struct prefix_ipv4 *) &rn->p)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_abr_process_network_rt(): denied by prefix-list"); continue; } if ((or->path_type == OSPF_PATH_INTER_AREA) && !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt():" " this is route is not backbone one, skipping"); continue; } if ((ospf->abr_type == OSPF_ABR_CISCO) || (ospf->abr_type == OSPF_ABR_IBM)) if (!ospf_act_bb_connection (ospf) && or->path_type != OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): ALT ABR: " "No BB connection, skip not intra-area routes"); continue; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): announcing"); ospf_abr_announce_network (ospf, (struct prefix_ipv4 *)&rn->p, or); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_network_rt(): Stop"); } static void ospf_abr_announce_rtr_to_area (struct prefix_ipv4 *p, u_int32_t cost, struct ospf_area *area) { struct ospf_lsa *lsa, *old = NULL; struct summary_lsa *slsa = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): Start"); old = ospf_lsa_lookup_by_prefix (area->lsdb, OSPF_ASBR_SUMMARY_LSA, p, area->ospf->router_id); if (old) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): old summary found"); slsa = (struct summary_lsa *) old->data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_network_to_area(): " "old metric: %d, new metric: %d", GET_METRIC (slsa->metric), cost); } if (old && (GET_METRIC (slsa->metric) == cost) && ((old->flags & OSPF_LSA_IN_MAXAGE) == 0)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): old summary approved"); SET_FLAG (old->flags, OSPF_LSA_APPROVED); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): 2.2"); if (old) { set_metric (old, cost); lsa = ospf_lsa_refresh (area->ospf, old); } else lsa = ospf_summary_asbr_lsa_originate (p, cost, area); if (!lsa) { char buf[INET_ADDRSTRLEN + 3]; /* ipv4 and /XX */ prefix2str ((struct prefix *)p, buf, sizeof(buf)); zlog_warn ("%s: Could not refresh/originate %s to %s", __func__, buf, inet_ntoa (area->area_id)); return; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): " "flooding new version of summary"); /* zlog_info ("ospf_abr_announce_rtr_to_area(): creating new summary"); lsa = ospf_summary_asbr_lsa (p, cost, area, old); */ SET_FLAG (lsa->flags, OSPF_LSA_APPROVED); /* ospf_flood_through_area (area, NULL, lsa);*/ } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr_to_area(): Stop"); } static void ospf_abr_announce_rtr (struct ospf *ospf, struct prefix_ipv4 *p, struct ospf_route *or) { struct listnode *node; struct ospf_area *area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): looking at area %s", inet_ntoa (area->area_id)); if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) continue; if (ospf_abr_nexthops_belong_to_area (or, area)) continue; if (area->external_routing != OSPF_AREA_DEFAULT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): " "area %s doesn't support external routing", inet_ntoa(area->area_id)); continue; } if (or->path_type == OSPF_PATH_INTER_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): " "this is inter-area route to %s", inet_ntoa (p->prefix)); if (!OSPF_IS_AREA_BACKBONE (area)) ospf_abr_announce_rtr_to_area (p, or->cost, area); } if (or->path_type == OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): " "this is intra-area route to %s", inet_ntoa (p->prefix)); ospf_abr_announce_rtr_to_area (p, or->cost, area); } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_rtr(): Stop"); } static void ospf_abr_process_router_rt (struct ospf *ospf, struct route_table *rt) { struct ospf_route *or; struct route_node *rn; struct list *l; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): Start"); for (rn = route_top (rt); rn; rn = route_next (rn)) { struct listnode *node, *nnode; char flag = 0; struct ospf_route *best = NULL; if (rn->info == NULL) continue; l = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): this is a route to %s", inet_ntoa (rn->p.u.prefix4)); for (ALL_LIST_ELEMENTS (l, node, nnode, or)) { if (!ospf_area_lookup_by_area_id (ospf, or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): area %s no longer exists", inet_ntoa (or->u.std.area_id)); continue; } if (!CHECK_FLAG (or->u.std.flags, ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): " "This is not an ASBR, skipping"); continue; } if (!flag) { best = ospf_find_asbr_route (ospf, rt, (struct prefix_ipv4 *) &rn->p); flag = 1; } if (best == NULL) continue; if (or != best) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): " "This route is not the best among possible, skipping"); continue; } if (or->path_type == OSPF_PATH_INTER_AREA && !OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): " "This route is not a backbone one, skipping"); continue; } if (or->cost >= OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): " "This route has LS_INFINITY metric, skipping"); continue; } if (ospf->abr_type == OSPF_ABR_CISCO || ospf->abr_type == OSPF_ABR_IBM) if (!ospf_act_bb_connection (ospf) && or->path_type != OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_abr_process_network_rt(): ALT ABR: " "No BB connection, skip not intra-area routes"); continue; } ospf_abr_announce_rtr (ospf, (struct prefix_ipv4 *) &rn->p, or); } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_process_router_rt(): Stop"); } static void ospf_abr_unapprove_translates (struct ospf *ospf) /* For NSSA Translations */ { struct ospf_lsa *lsa; struct route_node *rn; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_unapprove_translates(): Start"); /* NSSA Translator is not checked, because it may have gone away, and we would want to flush any residuals anyway */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) { UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_unapprove_translates(): " "approved unset on link id %s", inet_ntoa (lsa->data->id)); } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_unapprove_translates(): Stop"); } static void ospf_abr_unapprove_summaries (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "considering area %s", inet_ntoa (area->area_id)); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "approved unset on summary link id %s", inet_ntoa (lsa->data->id)); UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); } LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): " "approved unset on asbr-summary link id %s", inet_ntoa (lsa->data->id)); UNSET_FLAG (lsa->flags, OSPF_LSA_APPROVED); } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_unapprove_summaries(): Stop"); } static void ospf_abr_prepare_aggregates (struct ospf *ospf) { struct listnode *node; struct route_node *rn; struct ospf_area_range *range; struct ospf_area *area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_prepare_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { for (rn = route_top (area->ranges); rn; rn = route_next (rn)) if ((range = rn->info) != NULL) { range->cost = 0; range->specifics = 0; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_prepare_aggregates(): Stop"); } static void ospf_abr_announce_aggregates (struct ospf *ospf) { struct ospf_area *area, *ar; struct ospf_area_range *range; struct route_node *rn; struct prefix p; struct listnode *node, *n; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): looking at area %s", inet_ntoa (area->area_id)); for (rn = route_top (area->ranges); rn; rn = route_next (rn)) if ((range = rn->info)) { if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates():" " discarding suppress-ranges"); continue; } p.family = AF_INET; p.u.prefix4 = range->addr; p.prefixlen = range->masklen; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates():" " this is range: %s/%d", inet_ntoa (p.u.prefix4), p.prefixlen); if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) { p.family = AF_INET; p.u.prefix4 = range->subst_addr; p.prefixlen = range->subst_masklen; } if (range->specifics) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): active range"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, n, ar)) { if (ar == area) continue; /* We do not check nexthops here, because intra-area routes can be associated with one area only */ /* backbone routes are not summarized when announced into transit areas */ if (ospf_area_is_transit (ar) && OSPF_IS_AREA_BACKBONE (area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): Skipping " "announcement of BB aggregate into" " a transit area"); continue; } ospf_abr_announce_network_to_area ((struct prefix_ipv4 *)&p, range->cost, ar); } } } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_aggregates(): Stop"); } static void ospf_abr_send_nssa_aggregates (struct ospf *ospf) /* temporarily turned off */ { struct listnode *node; /*, n; */ struct ospf_area *area; /*, *ar; */ struct route_node *rn; struct ospf_area_range *range; struct prefix_ipv4 p; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (! area->NSSATranslatorState) continue; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates(): looking at area %s", inet_ntoa (area->area_id)); for (rn = route_top (area->ranges); rn; rn = route_next (rn)) { if (rn->info == NULL) continue; range = rn->info; if (!CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates():" " discarding suppress-ranges"); continue; } p.family = AF_INET; p.prefix = range->addr; p.prefixlen = range->masklen; if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates():" " this is range: %s/%d", inet_ntoa (p.prefix), p.prefixlen); if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_SUBSTITUTE)) { p.family = AF_INET; p.prefix = range->subst_addr; p.prefixlen = range->subst_masklen; } if (range->specifics) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates(): active range"); /* Fetch LSA-Type-7 from aggregate prefix, and then * translate, Install (as Type-5), Approve, and Flood */ ospf_abr_translate_nssa_range (&p, range->cost); } } /* all area ranges*/ } /* all areas */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_send_nssa_aggregates(): Stop"); } static void ospf_abr_announce_stub_defaults (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct prefix_ipv4 p; if (! IS_OSPF_ABR (ospf)) return; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): Start"); p.family = AF_INET; p.prefix.s_addr = OSPF_DEFAULT_DESTINATION; p.prefixlen = 0; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): looking at area %s", inet_ntoa (area->area_id)); if ( (area->external_routing != OSPF_AREA_STUB) && (area->external_routing != OSPF_AREA_NSSA) ) continue; if (OSPF_IS_AREA_BACKBONE (area)) continue; /* Sanity Check */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): " "announcing 0.0.0.0/0 to area %s", inet_ntoa (area->area_id)); ospf_abr_announce_network_to_area (&p, area->default_cost, area); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_announce_stub_defaults(): Stop"); } static int ospf_abr_remove_unapproved_translates_apply (struct ospf *ospf, struct ospf_lsa *lsa) { if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT) && ! CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) { zlog_info ("ospf_abr_remove_unapproved_translates(): " "removing unapproved translates, ID: %s", inet_ntoa (lsa->data->id)); /* FLUSH THROUGHOUT AS */ ospf_lsa_flush_as (ospf, lsa); /* DISCARD from LSDB */ } return 0; } static void ospf_abr_remove_unapproved_translates (struct ospf *ospf) { struct route_node *rn; struct ospf_lsa *lsa; /* All AREA PROCESS should have APPROVED necessary LSAs */ /* Remove any left over and not APPROVED */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_remove_unapproved_translates(): Start"); LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_abr_remove_unapproved_translates_apply (ospf, lsa); if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_remove_unapproved_translates(): Stop"); } static void ospf_abr_remove_unapproved_summaries (struct ospf *ospf) { struct listnode *node; struct ospf_area *area; struct route_node *rn; struct ospf_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_remove_unapproved_summaries(): Start"); for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_remove_unapproved_summaries(): " "looking at area %s", inet_ntoa (area->area_id)); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) if (!CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) ospf_lsa_flush_area (lsa, area); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) if (ospf_lsa_is_self_originated (ospf, lsa)) if (!CHECK_FLAG (lsa->flags, OSPF_LSA_APPROVED)) ospf_lsa_flush_area (lsa, area); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_remove_unapproved_summaries(): Stop"); } static void ospf_abr_manage_discard_routes (struct ospf *ospf) { struct listnode *node, *nnode; struct route_node *rn; struct ospf_area *area; struct ospf_area_range *range; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) for (rn = route_top (area->ranges); rn; rn = route_next (rn)) if ((range = rn->info) != NULL) if (CHECK_FLAG (range->flags, OSPF_AREA_RANGE_ADVERTISE)) { if (range->specifics) ospf_add_discard_route (ospf->new_table, area, (struct prefix_ipv4 *) &rn->p); else ospf_delete_discard_route (ospf->new_table, (struct prefix_ipv4 *) &rn->p); } } /* This is the function taking care about ABR NSSA, i.e. NSSA Translator, -LSA aggregation and flooding. For all NSSAs Any SELF-AS-LSA is in the Type-5 LSDB and Type-7 LSDB. These LSA's are refreshed from the Type-5 LSDB, installed into the Type-7 LSDB with the P-bit set. Any received Type-5s are legal for an ABR, else illegal for IR. Received Type-7s are installed, by area, with incoming P-bit. They are flooded; if the Elected NSSA Translator, then P-bit off. Additionally, this ABR will place "translated type-7's" into the Type-5 LSDB in order to keep track of APPROVAL or not. It will scan through every area, looking for Type-7 LSAs with P-Bit SET. The Type-7's are either AS-FLOODED & 5-INSTALLED or AGGREGATED. Later, the AGGREGATED LSAs are AS-FLOODED & 5-INSTALLED. 5-INSTALLED is into the Type-5 LSDB; Any UNAPPROVED Type-5 LSAs left over are FLUSHED and DISCARDED. For External Calculations, any NSSA areas use the Type-7 AREA-LSDB, any ABR-non-NSSA areas use the Type-5 GLOBAL-LSDB. */ static void ospf_abr_nssa_task (struct ospf *ospf) /* called only if any_nssa */ { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("Check for NSSA-ABR Tasks():"); if (! IS_OSPF_ABR (ospf)) return; if (! ospf->anyNSSA) return; /* Each area must confirm TranslatorRole */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): Start"); /* For all Global Entries flagged "local-translate", unset APPROVED */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): unapprove translates"); ospf_abr_unapprove_translates (ospf); /* RESET all Ranges in every Area, same as summaries */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): NSSA initialize aggregates"); ospf_abr_prepare_aggregates (ospf); /*TURNED OFF just for now */ /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or * Aggregate as Type-7 * Install or Approve in Type-5 Global LSDB */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): process translates"); ospf_abr_process_nssa_translates (ospf); /* Translate/Send any "ranged" aggregates, and also 5-Install and * Approve * Scan Type-7's for aggregates, translate to Type-5's, * Install/Flood/Approve */ if (IS_DEBUG_OSPF_NSSA) zlog_debug("ospf_abr_nssa_task(): send NSSA aggregates"); ospf_abr_send_nssa_aggregates (ospf); /*TURNED OFF FOR NOW */ /* Send any NSSA defaults as Type-5 *if (IS_DEBUG_OSPF_NSSA) * zlog_debug ("ospf_abr_nssa_task(): announce nssa defaults"); *ospf_abr_announce_nssa_defaults (ospf); * havnt a clue what above is supposed to do. */ /* Flush any unapproved previous translates from Global Data Base */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): remove unapproved translates"); ospf_abr_remove_unapproved_translates (ospf); ospf_abr_manage_discard_routes (ospf); /* same as normal...discard */ if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_abr_nssa_task(): Stop"); } /* This is the function taking care about ABR stuff, i.e. summary-LSA origination and flooding. */ void ospf_abr_task (struct ospf *ospf) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): Start"); if (ospf->new_table == NULL || ospf->new_rtrs == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): Routing tables are not yet ready"); return; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): unapprove summaries"); ospf_abr_unapprove_summaries (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): prepare aggregates"); ospf_abr_prepare_aggregates (ospf); if (IS_OSPF_ABR (ospf)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): process network RT"); ospf_abr_process_network_rt (ospf, ospf->new_table); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): process router RT"); ospf_abr_process_router_rt (ospf, ospf->new_rtrs); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): announce aggregates"); ospf_abr_announce_aggregates (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): announce stub defaults"); ospf_abr_announce_stub_defaults (ospf); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): remove unapproved summaries"); ospf_abr_remove_unapproved_summaries (ospf); ospf_abr_manage_discard_routes (ospf); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_abr_task(): Stop"); } static int ospf_abr_task_timer (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); ospf->t_abr_task = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Running ABR task on timer"); ospf_check_abr_status (ospf); ospf_abr_nssa_check_status (ospf); ospf_abr_task (ospf); ospf_abr_nssa_task (ospf); /* if nssa-abr, then scan Type-7 LSDB */ return 0; } void ospf_schedule_abr_task (struct ospf *ospf) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Scheduling ABR task"); if (ospf->t_abr_task == NULL) ospf->t_abr_task = thread_add_timer (master, ospf_abr_task_timer, ospf, OSPF_ABR_TASK_DELAY); } quagga-0.99.24.1/ospfd/ospf_ase.c0000644000175000017500000005737112476520570013327 00000000000000/* * OSPF AS external route calculation. * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "hash.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "vty.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" struct ospf_route * ospf_find_asbr_route (struct ospf *ospf, struct route_table *rtrs, struct prefix_ipv4 *asbr) { struct route_node *rn; struct ospf_route *or, *best = NULL; struct listnode *node; struct list *chosen; /* Sanity check. */ if (rtrs == NULL) return NULL; rn = route_node_lookup (rtrs, (struct prefix *) asbr); if (! rn) return NULL; route_unlock_node (rn); chosen = list_new (); /* First try to find intra-area non-bb paths. */ if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) if (or->cost < OSPF_LS_INFINITY) if (!OSPF_IS_AREA_ID_BACKBONE (or->u.std.area_id) && or->path_type == OSPF_PATH_INTRA_AREA) listnode_add (chosen, or); /* If none is found -- look through all. */ if (listcount (chosen) == 0) { list_free (chosen); chosen = rn->info; } /* Now find the route with least cost. */ for (ALL_LIST_ELEMENTS_RO (chosen, node, or)) if (or->cost < OSPF_LS_INFINITY) { if (best == NULL) best = or; else if (best->cost > or->cost) best = or; else if (best->cost == or->cost && IPV4_ADDR_CMP (&best->u.std.area_id, &or->u.std.area_id) < 0) best = or; } if (chosen != rn->info) list_delete (chosen); return best; } struct ospf_route * ospf_find_asbr_route_through_area (struct route_table *rtrs, struct prefix_ipv4 *asbr, struct ospf_area *area) { struct route_node *rn; /* Sanity check. */ if (rtrs == NULL) return NULL; rn = route_node_lookup (rtrs, (struct prefix *) asbr); if (rn) { struct listnode *node; struct ospf_route *or; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO ((struct list *) rn->info, node, or)) if (IPV4_ADDR_SAME (&or->u.std.area_id, &area->area_id)) return or; } return NULL; } static void ospf_ase_complete_direct_routes (struct ospf_route *ro, struct in_addr nexthop) { struct listnode *node; struct ospf_path *op; for (ALL_LIST_ELEMENTS_RO (ro->paths, node, op)) if (op->nexthop.s_addr == 0) op->nexthop.s_addr = nexthop.s_addr; } static int ospf_ase_forward_address_check (struct ospf *ospf, struct in_addr fwd_addr) { struct listnode *ifn; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, ifn, oi)) if (if_is_operative (oi->ifp)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &fwd_addr)) return 0; return 1; } #if 0 /* Calculate ASBR route. */ static struct ospf_route * ospf_ase_calculate_asbr_route (struct ospf *ospf, struct route_table *rt_network, struct route_table *rt_router, struct as_external_lsa *al) { struct prefix_ipv4 asbr; struct ospf_route *asbr_route; struct route_node *rn; /* Find ASBR route from Router routing table. */ asbr.family = AF_INET; asbr.prefix = al->header.adv_router; asbr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&asbr); asbr_route = ospf_find_asbr_route (ospf, rt_router, &asbr); if (asbr_route == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): Route to ASBR %s not found", inet_ntoa (asbr.prefix)); return NULL; } if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): Originating router is not an ASBR"); return NULL; } if (al->e[0].fwd_addr.s_addr != 0) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Forwarding address is not 0.0.0.0."); if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Forwarding address is one of our addresses, Ignore."); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Looking up in the Network Routing Table."); /* Looking up the path to the fwd_addr from Network route. */ asbr.family = AF_INET; asbr.prefix = al->e[0].fwd_addr; asbr.prefixlen = IPV4_MAX_BITLEN; rn = route_node_match (rt_network, (struct prefix *) &asbr); if (rn == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Couldn't find a route to the forwarding address."); return NULL; } route_unlock_node (rn); if ((asbr_route = rn->info) == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("ospf_ase_calculate(): " "Somehow OSPF route to ASBR is lost"); return NULL; } } return asbr_route; } #endif static struct ospf_route * ospf_ase_calculate_new_route (struct ospf_lsa *lsa, struct ospf_route *asbr_route, u_int32_t metric) { struct as_external_lsa *al; struct ospf_route *new; al = (struct as_external_lsa *) lsa->data; new = ospf_route_new (); /* Set redistributed type -- does make sense? */ /* new->type = type; */ new->id = al->header.id; new->mask = al->mask; if (!IS_EXTERNAL_METRIC (al->e[0].tos)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: type-1 created."); new->path_type = OSPF_PATH_TYPE1_EXTERNAL; new->cost = asbr_route->cost + metric; /* X + Y */ } else { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: type-2 created."); new->path_type = OSPF_PATH_TYPE2_EXTERNAL; new->cost = asbr_route->cost; /* X */ new->u.ext.type2_cost = metric; /* Y */ } new->type = OSPF_DESTINATION_NETWORK; new->u.ext.origin = lsa; new->u.ext.tag = ntohl (al->e[0].route_tag); new->u.ext.asbr = asbr_route; assert (new != asbr_route); return new; } #define OSPF_ASE_CALC_INTERVAL 1 int ospf_ase_calculate_route (struct ospf *ospf, struct ospf_lsa * lsa) { u_int32_t metric; struct as_external_lsa *al; struct ospf_route *asbr_route; struct prefix_ipv4 asbr, p; struct route_node *rn; struct ospf_route *new, *or; int ret; assert (lsa); al = (struct as_external_lsa *) lsa->data; if (lsa->data->type == OSPF_AS_NSSA_LSA) if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_ase_calc(): Processing Type-7"); /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_ase_calc(): Rejecting Local Xlt'd"); return 0; } if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Calculate AS-external-LSA to %s/%d", inet_ntoa (al->header.id), ip_masklen (al->mask)); /* (1) If the cost specified by the LSA is LSInfinity, or if the LSA's LS age is equal to MaxAge, then examine the next LSA. */ if ((metric = GET_METRIC (al->e[0].metric)) >= OSPF_LS_INFINITY) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Metric is OSPF_LS_INFINITY"); return 0; } if (IS_LSA_MAXAGE (lsa)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: AS-external-LSA is MAXAGE"); return 0; } /* (2) If the LSA was originated by the calculating router itself, examine the next LSA. */ if (IS_LSA_SELF (lsa)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: AS-external-LSA is self originated"); return 0; } /* (3) Call the destination described by the LSA N. N's address is obtained by masking the LSA's Link State ID with the network/subnet mask contained in the body of the LSA. Look up the routing table entries (potentially one per attached area) for the AS boundary router (ASBR) that originated the LSA. If no entries exist for router ASBR (i.e., ASBR is unreachable), do nothing with this LSA and consider the next in the list. */ asbr.family = AF_INET; asbr.prefix = al->header.adv_router; asbr.prefixlen = IPV4_MAX_BITLEN; apply_mask_ipv4 (&asbr); asbr_route = ospf_find_asbr_route (ospf, ospf->new_rtrs, &asbr); if (asbr_route == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Can't find originating ASBR route"); return 0; } if (!(asbr_route->u.std.flags & ROUTER_LSA_EXTERNAL)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Originating router is not an ASBR"); return 0; } /* Else, this LSA describes an AS external path to destination N. Examine the forwarding address specified in the AS- external-LSA. This indicates the IP address to which packets for the destination should be forwarded. */ if (al->e[0].fwd_addr.s_addr == 0) { /* If the forwarding address is set to 0.0.0.0, packets should be sent to the ASBR itself. Among the multiple routing table entries for the ASBR, select the preferred entry as follows. If RFC1583Compatibility is set to "disabled", prune the set of routing table entries for the ASBR as described in Section 16.4.1. In any case, among the remaining routing table entries, select the routing table entry with the least cost; when there are multiple least cost routing table entries the entry whose associated area has the largest OSPF Area ID (when considered as an unsigned 32-bit integer) is chosen. */ /* asbr_route already contains the requested route */ } else { /* If the forwarding address is non-zero, look up the forwarding address in the routing table.[24] The matching routing table entry must specify an intra-area or inter-area path; if no such path exists, do nothing with the LSA and consider the next in the list. */ if (! ospf_ase_forward_address_check (ospf, al->e[0].fwd_addr)) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Forwarding address is our router " "address"); return 0; } asbr.family = AF_INET; asbr.prefix = al->e[0].fwd_addr; asbr.prefixlen = IPV4_MAX_BITLEN; rn = route_node_match (ospf->new_table, (struct prefix *) &asbr); if (rn == NULL || (asbr_route = rn->info) == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Can't find route to forwarding " "address"); if (rn) route_unlock_node (rn); return 0; } route_unlock_node (rn); } /* (4) Let X be the cost specified by the preferred routing table entry for the ASBR/forwarding address, and Y the cost specified in the LSA. X is in terms of the link state metric, and Y is a type 1 or 2 external metric. */ /* (5) Look up the routing table entry for the destination N. If no entry exists for N, install the AS external path to N, with next hop equal to the list of next hops to the forwarding address, and advertising router equal to ASBR. If the external metric type is 1, then the path-type is set to type 1 external and the cost is equal to X+Y. If the external metric type is 2, the path-type is set to type 2 external, the link state component of the route's cost is X, and the type 2 cost is Y. */ new = ospf_ase_calculate_new_route (lsa, asbr_route, metric); /* (6) Compare the AS external path described by the LSA with the existing paths in N's routing table entry, as follows. If the new path is preferred, it replaces the present paths in N's routing table entry. If the new path is of equal preference, it is added to N's routing table entry's list of paths. */ /* Set prefix. */ p.family = AF_INET; p.prefix = al->header.id; p.prefixlen = ip_masklen (al->mask); /* if there is a Intra/Inter area route to the N do not install external route */ if ((rn = route_node_lookup (ospf->new_table, (struct prefix *) &p))) { route_unlock_node(rn); if (rn->info == NULL) zlog_info ("Route[External]: rn->info NULL"); if (new) ospf_route_free (new); return 0; } /* Find a route to the same dest */ /* If there is no route, create new one. */ if ((rn = route_node_lookup (ospf->new_external_route, (struct prefix *) &p))) route_unlock_node(rn); if (!rn || (or = rn->info) == NULL) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Adding a new route %s/%d", inet_ntoa (p.prefix), p.prefixlen); ospf_route_add (ospf->new_external_route, &p, new, asbr_route); if (al->e[0].fwd_addr.s_addr) ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); return 0; } else { /* (a) Intra-area and inter-area paths are always preferred over AS external paths. (b) Type 1 external paths are always preferred over type 2 external paths. When all paths are type 2 external paths, the paths with the smallest advertised type 2 metric are always preferred. */ ret = ospf_route_cmp (ospf, new, or); /* (c) If the new AS external path is still indistinguishable from the current paths in the N's routing table entry, and RFC1583Compatibility is set to "disabled", select the preferred paths based on the intra-AS paths to the ASBR/forwarding addresses, as specified in Section 16.4.1. (d) If the new AS external path is still indistinguishable from the current paths in the N's routing table entry, select the preferred path based on a least cost comparison. Type 1 external paths are compared by looking at the sum of the distance to the forwarding address and the advertised type 1 metric (X+Y). Type 2 external paths advertising equal type 2 metrics are compared by looking at the distance to the forwarding addresses. */ /* New route is better */ if (ret < 0) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: New route is better"); ospf_route_subst (rn, new, asbr_route); if (al->e[0].fwd_addr.s_addr) ospf_ase_complete_direct_routes (new, al->e[0].fwd_addr); or = new; new = NULL; } /* Old route is better */ else if (ret > 0) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Old route is better"); /* do nothing */ } /* Routes are equal */ else { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("Route[External]: Routes are equal"); ospf_route_copy_nexthops (or, asbr_route->paths); if (al->e[0].fwd_addr.s_addr) ospf_ase_complete_direct_routes (or, al->e[0].fwd_addr); } } /* Make sure setting newly calculated ASBR route.*/ or->u.ext.asbr = asbr_route; if (new) ospf_route_free (new); lsa->route = or; return 0; } static int ospf_ase_route_match_same (struct route_table *rt, struct prefix *prefix, struct ospf_route *newor) { struct route_node *rn; struct ospf_route *or; struct ospf_path *op; struct ospf_path *newop; struct listnode *n1; struct listnode *n2; if (! rt || ! prefix) return 0; rn = route_node_lookup (rt, prefix); if (! rn) return 0; route_unlock_node (rn); or = rn->info; if (or->path_type != newor->path_type) return 0; switch (or->path_type) { case OSPF_PATH_TYPE1_EXTERNAL: if (or->cost != newor->cost) return 0; break; case OSPF_PATH_TYPE2_EXTERNAL: if ((or->cost != newor->cost) || (or->u.ext.type2_cost != newor->u.ext.type2_cost)) return 0; break; default: assert (0); return 0; } if (or->paths->count != newor->paths->count) return 0; /* Check each path. */ for (n1 = listhead (or->paths), n2 = listhead (newor->paths); n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2)) { op = listgetdata (n1); newop = listgetdata (n2); if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) return 0; if (op->ifindex != newop->ifindex) return 0; } return 1; } static int ospf_ase_compare_tables (struct route_table *new_external_route, struct route_table *old_external_route) { struct route_node *rn, *new_rn; struct ospf_route *or; /* Remove deleted routes */ for (rn = route_top (old_external_route); rn; rn = route_next (rn)) if ((or = rn->info)) { if (! (new_rn = route_node_lookup (new_external_route, &rn->p))) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); else route_unlock_node (new_rn); } /* Install new routes */ for (rn = route_top (new_external_route); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) if (! ospf_ase_route_match_same (old_external_route, &rn->p, or)) ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); return 0; } static int ospf_ase_calculate_timer (struct thread *t) { struct ospf *ospf; struct ospf_lsa *lsa; struct route_node *rn; struct listnode *node; struct ospf_area *area; struct timeval start_time, stop_time; ospf = THREAD_ARG (t); ospf->t_ase_calc = NULL; if (ospf->ase_calc) { ospf->ase_calc = 0; quagga_gettime(QUAGGA_CLK_MONOTONIC, &start_time); /* Calculate external route for each AS-external-LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_ase_calculate_route (ospf, lsa); /* This version simple adds to the table all NSSA areas */ if (ospf->anyNSSA) for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_ase_calculate_timer(): looking at area %s", inet_ntoa (area->area_id)); if (area->external_routing == OSPF_AREA_NSSA) LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_ase_calculate_route (ospf, lsa); } /* kevinm: And add the NSSA routes in ospf_top */ LSDB_LOOP (NSSA_LSDB (ospf),rn,lsa) ospf_ase_calculate_route(ospf,lsa); /* Compare old and new external routing table and install the difference info zebra/kernel */ ospf_ase_compare_tables (ospf->new_external_route, ospf->old_external_route); /* Delete old external routing table */ ospf_route_table_free (ospf->old_external_route); ospf->old_external_route = ospf->new_external_route; ospf->new_external_route = route_table_init (); quagga_gettime(QUAGGA_CLK_MONOTONIC, &stop_time); zlog_info ("SPF Processing Time(usecs): External Routes: %ld\n", (stop_time.tv_sec - start_time.tv_sec)*1000000L+ (stop_time.tv_usec - start_time.tv_usec)); } return 0; } void ospf_ase_calculate_schedule (struct ospf *ospf) { if (ospf == NULL) return; ospf->ase_calc = 1; } void ospf_ase_calculate_timer_add (struct ospf *ospf) { if (ospf == NULL) return; if (! ospf->t_ase_calc) ospf->t_ase_calc = thread_add_timer (master, ospf_ase_calculate_timer, ospf, OSPF_ASE_CALC_INTERVAL); } void ospf_ase_register_external_lsa (struct ospf_lsa *lsa, struct ospf *top) { struct route_node *rn; struct prefix_ipv4 p; struct list *lst; struct as_external_lsa *al; al = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen (al->mask); apply_mask_ipv4 (&p); rn = route_node_get (top->external_lsas, (struct prefix *) &p); if ((lst = rn->info) == NULL) rn->info = lst = list_new(); /* We assume that if LSA is deleted from DB is is also deleted from this RT */ listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */ } void ospf_ase_unregister_external_lsa (struct ospf_lsa *lsa, struct ospf *top) { struct route_node *rn; struct prefix_ipv4 p; struct list *lst; struct as_external_lsa *al; al = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen (al->mask); apply_mask_ipv4 (&p); rn = route_node_get (top->external_lsas, (struct prefix *) &p); lst = rn->info; /* XXX lst can be NULL */ if (lst) { listnode_delete (lst, lsa); ospf_lsa_unlock (&lsa); /* external_lsas list */ } } void ospf_ase_external_lsas_finish (struct route_table *rt) { struct route_node *rn; struct ospf_lsa *lsa; struct list *lst; struct listnode *node, *nnode; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((lst = rn->info) != NULL) { for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* external_lsas lst */ list_delete (lst); } route_table_finish (rt); } void ospf_ase_incremental_update (struct ospf *ospf, struct ospf_lsa *lsa) { struct list *lsas; struct listnode *node; struct route_node *rn, *rn2; struct prefix_ipv4 p; struct route_table *tmp_old; struct as_external_lsa *al; al = (struct as_external_lsa *) lsa->data; p.family = AF_INET; p.prefix = lsa->data->id; p.prefixlen = ip_masklen (al->mask); apply_mask_ipv4 (&p); /* if new_table is NULL, there was no spf calculation, thus incremental update is unneeded */ if (!ospf->new_table) return; /* If there is already an intra-area or inter-area route to the destination, no recalculation is necessary (internal routes take precedence). */ rn = route_node_lookup (ospf->new_table, (struct prefix *) &p); if (rn) { route_unlock_node (rn); if (rn->info) return; } rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p); assert (rn); assert (rn->info); lsas = rn->info; route_unlock_node (rn); for (ALL_LIST_ELEMENTS_RO (lsas, node, lsa)) ospf_ase_calculate_route (ospf, lsa); /* prepare temporary old routing table for compare */ tmp_old = route_table_init (); rn = route_node_lookup (ospf->old_external_route, (struct prefix *) &p); if (rn && rn->info) { rn2 = route_node_get (tmp_old, (struct prefix *) &p); rn2->info = rn->info; } /* install changes to zebra */ ospf_ase_compare_tables (ospf->new_external_route, tmp_old); /* update ospf->old_external_route table */ if (rn && rn->info) ospf_route_free ((struct ospf_route *) rn->info); rn2 = route_node_lookup (ospf->new_external_route, (struct prefix *) &p); /* if new route exists, install it to ospf->old_external_route */ if (rn2 && rn2->info) { if (!rn) rn = route_node_get (ospf->old_external_route, (struct prefix *) &p); rn->info = rn2->info; } else { /* remove route node from ospf->old_external_route */ if (rn) { rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } if (rn2) { /* rn2->info is stored in route node of ospf->old_external_route */ rn2->info = NULL; route_unlock_node (rn2); route_unlock_node (rn2); } route_table_finish (tmp_old); } quagga-0.99.24.1/ospfd/ospf_route.c0000644000175000017500000006574612476520570013722 00000000000000/* * OSPF routing table. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "table.h" #include "memory.h" #include "linklist.h" #include "log.h" #include "if.h" #include "command.h" #include "sockunion.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_dump.h" struct ospf_route * ospf_route_new () { struct ospf_route *new; new = XCALLOC (MTYPE_OSPF_ROUTE, sizeof (struct ospf_route)); new->ctime = quagga_time (NULL); new->mtime = new->ctime; new->paths = list_new (); new->paths->del = (void (*) (void *))ospf_path_free; return new; } void ospf_route_free (struct ospf_route *or) { if (or->paths) list_delete (or->paths); XFREE (MTYPE_OSPF_ROUTE, or); } struct ospf_path * ospf_path_new () { struct ospf_path *new; new = XCALLOC (MTYPE_OSPF_PATH, sizeof (struct ospf_path)); return new; } static struct ospf_path * ospf_path_dup (struct ospf_path *path) { struct ospf_path *new; new = ospf_path_new (); memcpy (new, path, sizeof (struct ospf_path)); return new; } void ospf_path_free (struct ospf_path *op) { XFREE (MTYPE_OSPF_PATH, op); } void ospf_route_delete (struct route_table *rt) { struct route_node *rn; struct ospf_route *or; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) { if (or->type == OSPF_DESTINATION_NETWORK) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); else if (or->type == OSPF_DESTINATION_DISCARD) ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); } } void ospf_route_table_free (struct route_table *rt) { struct route_node *rn; struct ospf_route *or; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) { ospf_route_free (or); rn->info = NULL; route_unlock_node (rn); } route_table_finish (rt); } /* If a prefix exists in the new routing table, then return 1, otherwise return 0. Since the ZEBRA-RIB does an implicit withdraw, it is not necessary to send a delete, an add later will act like an implicit delete. */ static int ospf_route_exist_new_table (struct route_table *rt, struct prefix_ipv4 *prefix) { struct route_node *rn; assert (rt); assert (prefix); rn = route_node_lookup (rt, (struct prefix *) prefix); if (!rn) { return 0; } route_unlock_node (rn); if (!rn->info) { return 0; } return 1; } /* If a prefix and a nexthop match any route in the routing table, then return 1, otherwise return 0. */ int ospf_route_match_same (struct route_table *rt, struct prefix_ipv4 *prefix, struct ospf_route *newor) { struct route_node *rn; struct ospf_route *or; struct ospf_path *op; struct ospf_path *newop; struct listnode *n1; struct listnode *n2; if (! rt || ! prefix) return 0; rn = route_node_lookup (rt, (struct prefix *) prefix); if (! rn || ! rn->info) return 0; route_unlock_node (rn); or = rn->info; if (or->type == newor->type && or->cost == newor->cost) { if (or->type == OSPF_DESTINATION_NETWORK) { if (or->paths->count != newor->paths->count) return 0; /* Check each path. */ for (n1 = listhead (or->paths), n2 = listhead (newor->paths); n1 && n2; n1 = listnextnode (n1), n2 = listnextnode (n2)) { op = listgetdata (n1); newop = listgetdata (n2); if (! IPV4_ADDR_SAME (&op->nexthop, &newop->nexthop)) return 0; if (op->ifindex != newop->ifindex) return 0; } return 1; } else if (prefix_same (&rn->p, (struct prefix *) prefix)) return 1; } return 0; } /* delete routes generated from AS-External routes if there is a inter/intra * area route */ static void ospf_route_delete_same_ext(struct route_table *external_routes, struct route_table *routes) { struct route_node *rn, *ext_rn; if ( (external_routes == NULL) || (routes == NULL) ) return; /* Remove deleted routes */ for ( rn = route_top (routes); rn; rn = route_next (rn) ) { if (rn && rn->info) { struct prefix_ipv4 *p = (struct prefix_ipv4 *)(&rn->p); if ( (ext_rn = route_node_lookup (external_routes, (struct prefix *)p)) ) { if (ext_rn->info) { ospf_zebra_delete (p, ext_rn->info); ospf_route_free( ext_rn->info); ext_rn->info = NULL; } route_unlock_node (ext_rn); } } } } /* rt: Old, cmprt: New */ static void ospf_route_delete_uniq (struct route_table *rt, struct route_table *cmprt) { struct route_node *rn; struct ospf_route *or; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) if (or->path_type == OSPF_PATH_INTRA_AREA || or->path_type == OSPF_PATH_INTER_AREA) { if (or->type == OSPF_DESTINATION_NETWORK) { if (! ospf_route_exist_new_table (cmprt, (struct prefix_ipv4 *) &rn->p)) ospf_zebra_delete ((struct prefix_ipv4 *) &rn->p, or); } else if (or->type == OSPF_DESTINATION_DISCARD) if (! ospf_route_exist_new_table (cmprt, (struct prefix_ipv4 *) &rn->p)) ospf_zebra_delete_discard ((struct prefix_ipv4 *) &rn->p); } } /* Install routes to table. */ void ospf_route_install (struct ospf *ospf, struct route_table *rt) { struct route_node *rn; struct ospf_route *or; /* rt contains new routing table, new_table contains an old one. updating pointers */ if (ospf->old_table) ospf_route_table_free (ospf->old_table); ospf->old_table = ospf->new_table; ospf->new_table = rt; /* Delete old routes. */ if (ospf->old_table) ospf_route_delete_uniq (ospf->old_table, rt); if (ospf->old_external_route) ospf_route_delete_same_ext (ospf->old_external_route, rt); /* Install new routes. */ for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) { if (or->type == OSPF_DESTINATION_NETWORK) { if (! ospf_route_match_same (ospf->old_table, (struct prefix_ipv4 *)&rn->p, or)) ospf_zebra_add ((struct prefix_ipv4 *) &rn->p, or); } else if (or->type == OSPF_DESTINATION_DISCARD) if (! ospf_route_match_same (ospf->old_table, (struct prefix_ipv4 *) &rn->p, or)) ospf_zebra_add_discard ((struct prefix_ipv4 *) &rn->p); } } /* RFC2328 16.1. (4). For "router". */ void ospf_intra_add_router (struct route_table *rt, struct vertex *v, struct ospf_area *area) { struct route_node *rn; struct ospf_route *or; struct prefix_ipv4 p; struct router_lsa *lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: Start"); lsa = (struct router_lsa *) v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: LS ID: %s", inet_ntoa (lsa->header.id)); if (!OSPF_IS_AREA_BACKBONE(area)) ospf_vl_up_check (area, lsa->header.id, v); if (!CHECK_FLAG (lsa->flags, ROUTER_LSA_SHORTCUT)) area->shortcut_capability = 0; /* If the newly added vertex is an area border router or AS boundary router, a routing table entry is added whose destination type is "router". */ if (! IS_ROUTER_LSA_BORDER (lsa) && ! IS_ROUTER_LSA_EXTERNAL (lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: " "this router is neither ASBR nor ABR, skipping it"); return; } /* Update ABR and ASBR count in this area. */ if (IS_ROUTER_LSA_BORDER (lsa)) area->abr_count++; if (IS_ROUTER_LSA_EXTERNAL (lsa)) area->asbr_count++; /* The Options field found in the associated router-LSA is copied into the routing table entry's Optional capabilities field. Call the newly added vertex Router X. */ or = ospf_route_new (); or->id = v->id; or->u.std.area_id = area->area_id; or->u.std.external_routing = area->external_routing; or->path_type = OSPF_PATH_INTRA_AREA; or->cost = v->distance; or->type = OSPF_DESTINATION_ROUTER; or->u.std.origin = (struct lsa_header *) lsa; or->u.std.options = lsa->header.options; or->u.std.flags = lsa->flags; /* If Router X is the endpoint of one of the calculating router's virtual links, and the virtual link uses Area A as Transit area: the virtual link is declared up, the IP address of the virtual interface is set to the IP address of the outgoing interface calculated above for Router X, and the virtual neighbor's IP address is set to Router X's interface address (contained in Router X's router-LSA) that points back to the root of the shortest- path tree; equivalently, this is the interface that points back to Router X's parent vertex on the shortest-path tree (similar to the calculation in Section 16.1.1). */ p.family = AF_INET; p.prefix = v->id; p.prefixlen = IPV4_MAX_BITLEN; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: talking about %s/%d", inet_ntoa (p.prefix), p.prefixlen); rn = route_node_get (rt, (struct prefix *) &p); /* Note that we keep all routes to ABRs and ASBRs, not only the best */ if (rn->info == NULL) rn->info = list_new (); else route_unlock_node (rn); ospf_route_copy_nexthops_from_vertex (or, v); listnode_add (rn->info, or); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_router: Stop"); } /* RFC2328 16.1. (4). For transit network. */ void ospf_intra_add_transit (struct route_table *rt, struct vertex *v, struct ospf_area *area) { struct route_node *rn; struct ospf_route *or; struct prefix_ipv4 p; struct network_lsa *lsa; lsa = (struct network_lsa*) v->lsa; /* If the newly added vertex is a transit network, the routing table entry for the network is located. The entry's Destination ID is the IP network number, which can be obtained by masking the Vertex ID (Link State ID) with its associated subnet mask (found in the body of the associated network-LSA). */ p.family = AF_INET; p.prefix = v->id; p.prefixlen = ip_masklen (lsa->mask); apply_mask_ipv4 (&p); rn = route_node_get (rt, (struct prefix *) &p); /* If the routing table entry already exists (i.e., there is already an intra-area route to the destination installed in the routing table), multiple vertices have mapped to the same IP network. For example, this can occur when a new Designated Router is being established. In this case, the current routing table entry should be overwritten if and only if the newly found path is just as short and the current routing table entry's Link State Origin has a smaller Link State ID than the newly added vertex' LSA. */ if (rn->info) { struct ospf_route *cur_or; route_unlock_node (rn); cur_or = rn->info; if (v->distance > cur_or->cost || IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) > 0) return; ospf_route_free (rn->info); } or = ospf_route_new (); or->id = v->id; or->u.std.area_id = area->area_id; or->u.std.external_routing = area->external_routing; or->path_type = OSPF_PATH_INTRA_AREA; or->cost = v->distance; or->type = OSPF_DESTINATION_NETWORK; or->u.std.origin = (struct lsa_header *) lsa; ospf_route_copy_nexthops_from_vertex (or, v); rn->info = or; } /* RFC2328 16.1. second stage. */ void ospf_intra_add_stub (struct route_table *rt, struct router_lsa_link *link, struct vertex *v, struct ospf_area *area, int parent_is_root, int lsa_pos) { u_int32_t cost; struct route_node *rn; struct ospf_route *or; struct prefix_ipv4 p; struct router_lsa *lsa; struct ospf_interface *oi; struct ospf_path *path; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): Start"); lsa = (struct router_lsa *) v->lsa; p.family = AF_INET; p.prefix = link->link_id; p.prefixlen = ip_masklen (link->link_data); apply_mask_ipv4 (&p); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): processing route to %s/%d", inet_ntoa (p.prefix), p.prefixlen); /* (1) Calculate the distance D of stub network from the root. D is equal to the distance from the root to the router vertex (calculated in stage 1), plus the stub network link's advertised cost. */ cost = v->distance + ntohs (link->m[0].metric); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): calculated cost is %d + %d = %d", v->distance, ntohs(link->m[0].metric), cost); /* PtP links with /32 masks adds host routes to remote, directly * connected hosts, see RFC 2328, 12.4.1.1, Option 1. * Such routes can just be ignored for the sake of tidyness. */ if (parent_is_root && link->link_data.s_addr == 0xffffffff && ospf_if_lookup_by_local_addr (area->ospf, NULL, link->link_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: ignoring host route %s/32 to self.", __func__, inet_ntoa (link->link_id)); return; } rn = route_node_get (rt, (struct prefix *) &p); /* Lookup current routing table. */ if (rn->info) { struct ospf_route *cur_or; route_unlock_node (rn); cur_or = rn->info; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): " "another route to the same prefix found with cost %u", cur_or->cost); /* Compare this distance to the current best cost to the stub network. This is done by looking up the stub network's current routing table entry. If the calculated distance D is larger, go on to examine the next stub network link in the LSA. */ if (cost > cur_or->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): old route is better, exit"); return; } /* (2) If this step is reached, the stub network's routing table entry must be updated. Calculate the set of next hops that would result from using the stub network link. This calculation is shown in Section 16.1.1; input to this calculation is the destination (the stub network) and the parent vertex (the router vertex). If the distance D is the same as the current routing table cost, simply add this set of next hops to the routing table entry's list of next hops. In this case, the routing table already has a Link State Origin. If this Link State Origin is a router-LSA whose Link State ID is smaller than V's Router ID, reset the Link State Origin to V's router-LSA. */ if (cost == cur_or->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): routes are equal, merge"); ospf_route_copy_nexthops_from_vertex (cur_or, v); if (IPV4_ADDR_CMP (&cur_or->u.std.origin->id, &lsa->header.id) < 0) cur_or->u.std.origin = (struct lsa_header *) lsa; return; } /* Otherwise D is smaller than the routing table cost. Overwrite the current routing table entry by setting the routing table entry's cost to D, and by setting the entry's list of next hops to the newly calculated set. Set the routing table entry's Link State Origin to V's router-LSA. Then go on to examine the next stub network link. */ if (cost < cur_or->cost) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): new route is better, set it"); cur_or->cost = cost; list_delete_all_node (cur_or->paths); ospf_route_copy_nexthops_from_vertex (cur_or, v); cur_or->u.std.origin = (struct lsa_header *) lsa; return; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): installing new route"); or = ospf_route_new (); or->id = v->id; or->u.std.area_id = area->area_id; or->u.std.external_routing = area->external_routing; or->path_type = OSPF_PATH_INTRA_AREA; or->cost = cost; or->type = OSPF_DESTINATION_NETWORK; or->u.std.origin = (struct lsa_header *) lsa; /* Nexthop is depend on connection type. */ if (v != area->spf) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): this network is on remote router"); ospf_route_copy_nexthops_from_vertex (or, v); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): this network is on this router"); if ((oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos))) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): the interface is %s", IF_NAME (oi)); path = ospf_path_new (); path->nexthop.s_addr = 0; path->ifindex = oi->ifp->ifindex; listnode_add (or->paths, path); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_intra_add_stub(): where's the interface ?"); } } rn->info = or; if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_intra_add_stub(): Stop"); } const char *ospf_path_type_str[] = { "unknown-type", "intra-area", "inter-area", "type1-external", "type2-external" }; void ospf_route_table_dump (struct route_table *rt) { struct route_node *rn; struct ospf_route *or; char buf1[BUFSIZ]; char buf2[BUFSIZ]; struct listnode *pnode; struct ospf_path *path; #if 0 zlog_debug ("Type Dest Area Path Type Cost Next Adv."); zlog_debug (" Hop(s) Router(s)"); #endif /* 0 */ zlog_debug ("========== OSPF routing table =========="); for (rn = route_top (rt); rn; rn = route_next (rn)) if ((or = rn->info) != NULL) { if (or->type == OSPF_DESTINATION_NETWORK) { zlog_debug ("N %s/%d\t%s\t%s\t%d", inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), rn->p.prefixlen, inet_ntop (AF_INET, &or->u.std.area_id, buf2, BUFSIZ), ospf_path_type_str[or->path_type], or->cost); for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) zlog_debug (" -> %s", inet_ntoa (path->nexthop)); } else zlog_debug ("R %s\t%s\t%s\t%d", inet_ntop (AF_INET, &rn->p.u.prefix4, buf1, BUFSIZ), inet_ntop (AF_INET, &or->u.std.area_id, buf2, BUFSIZ), ospf_path_type_str[or->path_type], or->cost); } zlog_debug ("========================================"); } /* This is 16.4.1 implementation. o Intra-area paths using non-backbone areas are always the most preferred. o The other paths, intra-area backbone paths and inter-area paths, are of equal preference. */ static int ospf_asbr_route_cmp (struct ospf *ospf, struct ospf_route *r1, struct ospf_route *r2) { u_char r1_type, r2_type; r1_type = r1->path_type; r2_type = r2->path_type; /* r1/r2 itself is backbone, and it's Inter-area path. */ if (OSPF_IS_AREA_ID_BACKBONE (r1->u.std.area_id)) r1_type = OSPF_PATH_INTER_AREA; if (OSPF_IS_AREA_ID_BACKBONE (r2->u.std.area_id)) r2_type = OSPF_PATH_INTER_AREA; return (r1_type - r2_type); } /* Compare two routes. ret < 0 -- r1 is better. ret == 0 -- r1 and r2 are the same. ret > 0 -- r2 is better. */ int ospf_route_cmp (struct ospf *ospf, struct ospf_route *r1, struct ospf_route *r2) { int ret = 0; /* Path types of r1 and r2 are not the same. */ if ((ret = (r1->path_type - r2->path_type))) return ret; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Route[Compare]: Path types are the same."); /* Path types are the same, compare any cost. */ switch (r1->path_type) { case OSPF_PATH_INTRA_AREA: case OSPF_PATH_INTER_AREA: break; case OSPF_PATH_TYPE1_EXTERNAL: if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr); if (ret != 0) return ret; } break; case OSPF_PATH_TYPE2_EXTERNAL: if ((ret = (r1->u.ext.type2_cost - r2->u.ext.type2_cost))) return ret; if (!CHECK_FLAG (ospf->config, OSPF_RFC1583_COMPATIBLE)) { ret = ospf_asbr_route_cmp (ospf, r1->u.ext.asbr, r2->u.ext.asbr); if (ret != 0) return ret; } break; } /* Anyway, compare the costs. */ return (r1->cost - r2->cost); } static int ospf_path_exist (struct list *plist, struct in_addr nexthop, struct ospf_interface *oi) { struct listnode *node, *nnode; struct ospf_path *path; for (ALL_LIST_ELEMENTS (plist, node, nnode, path)) if (IPV4_ADDR_SAME (&path->nexthop, &nexthop) && path->ifindex == oi->ifp->ifindex) return 1; return 0; } void ospf_route_copy_nexthops_from_vertex (struct ospf_route *to, struct vertex *v) { struct listnode *node; struct ospf_path *path; struct vertex_nexthop *nexthop; struct vertex_parent *vp; assert (to->paths); for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { nexthop = vp->nexthop; if (nexthop->oi != NULL) { if (! ospf_path_exist (to->paths, nexthop->router, nexthop->oi)) { path = ospf_path_new (); path->nexthop = nexthop->router; path->ifindex = nexthop->oi->ifp->ifindex; listnode_add (to->paths, path); } } } } struct ospf_path * ospf_path_lookup (struct list *plist, struct ospf_path *path) { struct listnode *node; struct ospf_path *op; for (ALL_LIST_ELEMENTS_RO (plist, node, op)) { if (!IPV4_ADDR_SAME (&op->nexthop, &path->nexthop)) continue; if (!IPV4_ADDR_SAME (&op->adv_router, &path->adv_router)) continue; if (op->ifindex != path->ifindex) continue; return op; } return NULL; } void ospf_route_copy_nexthops (struct ospf_route *to, struct list *from) { struct listnode *node, *nnode; struct ospf_path *path; assert (to->paths); for (ALL_LIST_ELEMENTS (from, node, nnode, path)) /* The same routes are just discarded. */ if (!ospf_path_lookup (to->paths, path)) listnode_add (to->paths, ospf_path_dup (path)); } void ospf_route_subst_nexthops (struct ospf_route *to, struct list *from) { list_delete_all_node (to->paths); ospf_route_copy_nexthops (to, from); } void ospf_route_subst (struct route_node *rn, struct ospf_route *new_or, struct ospf_route *over) { route_lock_node (rn); ospf_route_free (rn->info); ospf_route_copy_nexthops (new_or, over->paths); rn->info = new_or; route_unlock_node (rn); } void ospf_route_add (struct route_table *rt, struct prefix_ipv4 *p, struct ospf_route *new_or, struct ospf_route *over) { struct route_node *rn; rn = route_node_get (rt, (struct prefix *) p); ospf_route_copy_nexthops (new_or, over->paths); if (rn->info) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_route_add(): something's wrong !"); route_unlock_node (rn); return; } rn->info = new_or; } void ospf_prune_unreachable_networks (struct route_table *rt) { struct route_node *rn, *next; struct ospf_route *or; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Pruning unreachable networks"); for (rn = route_top (rt); rn; rn = next) { next = route_next (rn); if (rn->info != NULL) { or = rn->info; if (listcount (or->paths) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Pruning route to %s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); ospf_route_free (or); rn->info = NULL; route_unlock_node (rn); } } } } void ospf_prune_unreachable_routers (struct route_table *rtrs) { struct route_node *rn, *next; struct ospf_route *or; struct listnode *node, *nnode; struct list *paths; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Pruning unreachable routers"); for (rn = route_top (rtrs); rn; rn = next) { next = route_next (rn); if ((paths = rn->info) == NULL) continue; for (ALL_LIST_ELEMENTS (paths, node, nnode, or)) { if (listcount (or->paths) == 0) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("Pruning route to rtr %s", inet_ntoa (rn->p.u.prefix4)); zlog_debug (" via area %s", inet_ntoa (or->u.std.area_id)); } listnode_delete (paths, or); ospf_route_free (or); } } if (listcount (paths) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Pruning router node %s", inet_ntoa (rn->p.u.prefix4)); list_delete (paths); rn->info = NULL; route_unlock_node (rn); } } } int ospf_add_discard_route (struct route_table *rt, struct ospf_area *area, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_route *or, *new_or; rn = route_node_get (rt, (struct prefix *) p); if (rn == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): router installation error"); return 0; } if (rn->info) /* If the route to the same destination is found */ { route_unlock_node (rn); or = rn->info; if (or->path_type == OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): " "an intra-area route exists"); return 0; } if (or->type == OSPF_DESTINATION_DISCARD) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): " "discard entry already installed"); return 0; } ospf_route_free (rn->info); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_add_discard_route(): " "adding %s/%d", inet_ntoa (p->prefix), p->prefixlen); new_or = ospf_route_new (); new_or->type = OSPF_DESTINATION_DISCARD; new_or->id.s_addr = 0; new_or->cost = 0; new_or->u.std.area_id = area->area_id; new_or->u.std.external_routing = area->external_routing; new_or->path_type = OSPF_PATH_INTER_AREA; rn->info = new_or; ospf_zebra_add_discard (p); return 1; } void ospf_delete_discard_route (struct route_table *rt, struct prefix_ipv4 *p) { struct route_node *rn; struct ospf_route *or; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "deleting %s/%d", inet_ntoa (p->prefix), p->prefixlen); rn = route_node_lookup (rt, (struct prefix*)p); if (rn == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug("ospf_delete_discard_route(): no route found"); return; } or = rn->info; if (or->path_type == OSPF_PATH_INTRA_AREA) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "an intra-area route exists"); return; } if (or->type != OSPF_DESTINATION_DISCARD) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_delete_discard_route(): " "not a discard entry"); return; } /* free the route entry and the route node */ ospf_route_free (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); /* remove the discard entry from the rib */ ospf_zebra_delete_discard(p); return; } quagga-0.99.24.1/ospfd/ospf_spf.c0000644000175000017500000013151012476520570013333 00000000000000/* OSPF SPF calculation. Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "hash.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "log.h" #include "sockunion.h" /* for inet_ntop () */ #include "pqueue.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ia.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_dump.h" /* Variables to ensure a SPF scheduled log message is printed only once */ static unsigned int spf_reason_flags = 0; static void ospf_clear_spf_reason_flags () { spf_reason_flags = 0; } static void ospf_spf_set_reason (ospf_spf_reason_t reason) { spf_reason_flags |= 1 << reason; } static void ospf_get_spf_reason_str (char *buf) { if (!buf) return; buf[0] = '\0'; if (spf_reason_flags) { if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL) strcat (buf, "R, "); if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL) strcat (buf, "N, "); if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL) strcat (buf, "S, "); if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL) strcat (buf, "AS, "); if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE) strcat (buf, "ABR, "); if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE) strcat (buf, "ASBR, "); if (spf_reason_flags & SPF_FLAG_MAXAGE) strcat (buf, "M, "); buf[strlen(buf)-2] = '\0'; /* skip the last ", " */ } } static void ospf_vertex_free (void *); /* List of allocated vertices, to simplify cleanup of SPF. * Not thread-safe obviously. If it ever needs to be, it'd have to be * dynamically allocated at begin of ospf_spf_calculate */ static struct list vertex_list = { .del = ospf_vertex_free }; /* Heap related functions, for the managment of the candidates, to * be used with pqueue. */ static int cmp (void * node1 , void * node2) { struct vertex * v1 = (struct vertex *) node1; struct vertex * v2 = (struct vertex *) node2; if (v1 != NULL && v2 != NULL ) { /* network vertices must be chosen before router vertices of same * cost in order to find all shortest paths */ if ( ((v1->distance - v2->distance) == 0) && (v1->type != v2->type)) { switch (v1->type) { case OSPF_VERTEX_NETWORK: return -1; case OSPF_VERTEX_ROUTER: return 1; } } else return (v1->distance - v2->distance); } return 0; } static void update_stat (void *node , int position) { struct vertex *v = node; /* Set the status of the vertex, when its position changes. */ *(v->stat) = position; } static struct vertex_nexthop * vertex_nexthop_new (void) { return XCALLOC (MTYPE_OSPF_NEXTHOP, sizeof (struct vertex_nexthop)); } static void vertex_nexthop_free (struct vertex_nexthop *nh) { XFREE (MTYPE_OSPF_NEXTHOP, nh); } /* Free the canonical nexthop objects for an area, ie the nexthop objects * attached to the first-hop router vertices, and any intervening network * vertices. */ static void ospf_canonical_nexthops_free (struct vertex *root) { struct listnode *node, *nnode; struct vertex *child; for (ALL_LIST_ELEMENTS (root->children, node, nnode, child)) { struct listnode *n2, *nn2; struct vertex_parent *vp; /* router vertices through an attached network each * have a distinct (canonical / not inherited) nexthop * which must be freed. * * A network vertex can only have router vertices as its * children, so only one level of recursion is possible. */ if (child->type == OSPF_VERTEX_NETWORK) ospf_canonical_nexthops_free (child); /* Free child nexthops pointing back to this root vertex */ for (ALL_LIST_ELEMENTS (child->parents, n2, nn2, vp)) if (vp->parent == root && vp->nexthop) vertex_nexthop_free (vp->nexthop); } } /* TODO: Parent list should be excised, in favour of maintaining only * vertex_nexthop, with refcounts. */ static struct vertex_parent * vertex_parent_new (struct vertex *v, int backlink, struct vertex_nexthop *hop) { struct vertex_parent *new; new = XMALLOC (MTYPE_OSPF_VERTEX_PARENT, sizeof (struct vertex_parent)); if (new == NULL) return NULL; new->parent = v; new->backlink = backlink; new->nexthop = hop; return new; } static void vertex_parent_free (void *p) { XFREE (MTYPE_OSPF_VERTEX_PARENT, p); } static struct vertex * ospf_vertex_new (struct ospf_lsa *lsa) { struct vertex *new; new = XCALLOC (MTYPE_OSPF_VERTEX, sizeof (struct vertex)); new->flags = 0; new->stat = &(lsa->stat); new->type = lsa->data->type; new->id = lsa->data->id; new->lsa = lsa->data; new->children = list_new (); new->parents = list_new (); new->parents->del = vertex_parent_free; listnode_add (&vertex_list, new); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Created %s vertex %s", __func__, new->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa (new->lsa->id)); return new; } static void ospf_vertex_free (void *data) { struct vertex *v = data; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Free %s vertex %s", __func__, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa (v->lsa->id)); /* There should be no parents potentially holding references to this vertex * Children however may still be there, but presumably referenced by other * vertices */ //assert (listcount (v->parents) == 0); if (v->children) list_delete (v->children); v->children = NULL; if (v->parents) list_delete (v->parents); v->parents = NULL; v->lsa = NULL; XFREE (MTYPE_OSPF_VERTEX, v); } static void ospf_vertex_dump(const char *msg, struct vertex *v, int print_parents, int print_children) { if ( ! IS_DEBUG_OSPF_EVENT) return; zlog_debug("%s %s vertex %s distance %u flags %u", msg, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa(v->lsa->id), v->distance, (unsigned int)v->flags); if (print_parents) { struct listnode *node; struct vertex_parent *vp; for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { char buf1[BUFSIZ]; if (vp) { zlog_debug ("parent %s backlink %d nexthop %s interface %s", inet_ntoa(vp->parent->lsa->id), vp->backlink, inet_ntop(AF_INET, &vp->nexthop->router, buf1, BUFSIZ), vp->nexthop->oi ? IF_NAME(vp->nexthop->oi) : "NULL"); } } } if (print_children) { struct listnode *cnode; struct vertex *cv; for (ALL_LIST_ELEMENTS_RO (v->children, cnode, cv)) ospf_vertex_dump(" child:", cv, 0, 0); } } /* Add a vertex to the list of children in each of its parents. */ static void ospf_vertex_add_parent (struct vertex *v) { struct vertex_parent *vp; struct listnode *node; assert (v && v->parents); for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { assert (vp->parent && vp->parent->children); /* No need to add two links from the same parent. */ if (listnode_lookup (vp->parent->children, v) == NULL) listnode_add (vp->parent->children, v); } } static void ospf_spf_init (struct ospf_area *area) { struct vertex *v; /* Create root node. */ v = ospf_vertex_new (area->router_lsa_self); area->spf = v; /* Reset ABR and ASBR router counts. */ area->abr_count = 0; area->asbr_count = 0; } /* return index of link back to V from W, or -1 if no link found */ static int ospf_lsa_has_link (struct lsa_header *w, struct lsa_header *v) { unsigned int i, length; struct router_lsa *rl; struct network_lsa *nl; /* In case of W is Network LSA. */ if (w->type == OSPF_NETWORK_LSA) { if (v->type == OSPF_NETWORK_LSA) return -1; nl = (struct network_lsa *) w; length = (ntohs (w->length) - OSPF_LSA_HEADER_SIZE - 4) / 4; for (i = 0; i < length; i++) if (IPV4_ADDR_SAME (&nl->routers[i], &v->id)) return i; return -1; } /* In case of W is Router LSA. */ if (w->type == OSPF_ROUTER_LSA) { rl = (struct router_lsa *) w; length = ntohs (w->length); for (i = 0; i < ntohs (rl->links) && length >= sizeof (struct router_lsa); i++, length -= 12) { switch (rl->link[i].type) { case LSA_LINK_TYPE_POINTOPOINT: case LSA_LINK_TYPE_VIRTUALLINK: /* Router LSA ID. */ if (v->type == OSPF_ROUTER_LSA && IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) { return i; } break; case LSA_LINK_TYPE_TRANSIT: /* Network LSA ID. */ if (v->type == OSPF_NETWORK_LSA && IPV4_ADDR_SAME (&rl->link[i].link_id, &v->id)) { return i; } break; case LSA_LINK_TYPE_STUB: /* Stub can't lead anywhere, carry on */ continue; default: break; } } } return -1; } /* Find the next link after prev_link from v to w. If prev_link is * NULL, return the first link from v to w. Ignore stub and virtual links; * these link types will never be returned. */ static struct router_lsa_link * ospf_get_next_link (struct vertex *v, struct vertex *w, struct router_lsa_link *prev_link) { u_char *p; u_char *lim; u_char lsa_type = LSA_LINK_TYPE_TRANSIT; struct router_lsa_link *l; if (w->type == OSPF_VERTEX_ROUTER) lsa_type = LSA_LINK_TYPE_POINTOPOINT; if (prev_link == NULL) p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; else { p = (u_char *) prev_link; p += (OSPF_ROUTER_LSA_LINK_SIZE + (prev_link->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); } lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { l = (struct router_lsa_link *) p; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type != lsa_type) continue; if (IPV4_ADDR_SAME (&l->link_id, &w->id)) return l; } return NULL; } static void ospf_spf_flush_parents (struct vertex *w) { struct vertex_parent *vp; struct listnode *ln, *nn; /* delete the existing nexthops */ for (ALL_LIST_ELEMENTS (w->parents, ln, nn, vp)) { list_delete_node (w->parents, ln); vertex_parent_free (vp); } } /* * Consider supplied next-hop for inclusion to the supplied list of * equal-cost next-hops, adjust list as neccessary. */ static void ospf_spf_add_parent (struct vertex *v, struct vertex *w, struct vertex_nexthop *newhop, unsigned int distance) { struct vertex_parent *vp, *wp; struct listnode *node; /* we must have a newhop, and a distance */ assert (v && w && newhop); assert (distance); /* IFF w has already been assigned a distance, then we shouldn't get here * unless callers have determined V(l)->W is shortest / equal-shortest * path (0 is a special case distance (no distance yet assigned)). */ if (w->distance) assert (distance <= w->distance); else w->distance = distance; if (IS_DEBUG_OSPF_EVENT) { char buf[2][INET_ADDRSTRLEN]; zlog_debug ("%s: Adding %s as parent of %s", __func__, inet_ntop(AF_INET, &v->lsa->id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &w->lsa->id, buf[1], sizeof(buf[1]))); } /* Adding parent for a new, better path: flush existing parents from W. */ if (distance < w->distance) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: distance %d better than %d, flushing existing parents", __func__, distance, w->distance); ospf_spf_flush_parents (w); w->distance = distance; } /* new parent is <= existing parents, add it to parent list (if nexthop * not on parent list) */ for (ALL_LIST_ELEMENTS_RO(w->parents, node, wp)) { if (memcmp(newhop, wp->nexthop, sizeof(*newhop)) == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: ... nexthop already on parent list, skipping add", __func__); return; } } vp = vertex_parent_new (v, ospf_lsa_has_link (w->lsa, v->lsa), newhop); listnode_add (w->parents, vp); return; } /* 16.1.1. Calculate nexthop from root through V (parent) to * vertex W (destination), with given distance from root->W. * * The link must be supplied if V is the root vertex. In all other cases * it may be NULL. * * Note that this function may fail, hence the state of the destination * vertex, W, should /not/ be modified in a dependent manner until * this function returns. This function will update the W vertex with the * provided distance as appropriate. */ static unsigned int ospf_nexthop_calculation (struct ospf_area *area, struct vertex *v, struct vertex *w, struct router_lsa_link *l, unsigned int distance, int lsa_pos) { struct listnode *node, *nnode; struct vertex_nexthop *nh; struct vertex_parent *vp; struct ospf_interface *oi = NULL; unsigned int added = 0; char buf1[BUFSIZ]; char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_nexthop_calculation(): Start"); ospf_vertex_dump("V (parent):", v, 1, 1); ospf_vertex_dump("W (dest) :", w, 1, 1); zlog_debug ("V->W distance: %d", distance); } if (v == area->spf) { /* 16.1.1 para 4. In the first case, the parent vertex (V) is the root (the calculating router itself). This means that the destination is either a directly connected network or directly connected router. The outgoing interface in this case is simply the OSPF interface connecting to the destination network/router. */ /* we *must* be supplied with the link data */ assert (l != NULL); oi = ospf_if_lookup_by_lsa_pos (area, lsa_pos); if (!oi) { zlog_debug("%s: OI not found in LSA: lsa_pos:%d link_id:%s link_data:%s", __func__, lsa_pos, inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); return 0; } if (IS_DEBUG_OSPF_EVENT) { zlog_debug("%s: considering link:%s " "type:%d link_id:%s link_data:%s", __func__, oi->ifp->name, l->m[0].type, inet_ntop (AF_INET, &l->link_id, buf1, BUFSIZ), inet_ntop (AF_INET, &l->link_data, buf2, BUFSIZ)); } if (w->type == OSPF_VERTEX_ROUTER) { /* l is a link from v to w * l2 will be link from w to v */ struct router_lsa_link *l2 = NULL; if (l->m[0].type == LSA_LINK_TYPE_POINTOPOINT) { struct in_addr nexthop; /* If the destination is a router which connects to the calculating router via a Point-to-MultiPoint network, the destination's next hop IP address(es) can be determined by examining the destination's router-LSA: each link pointing back to the calculating router and having a Link Data field belonging to the Point-to-MultiPoint network provides an IP address of the next hop router. At this point l is a link from V to W, and V is the root ("us"). If it is a point-to-multipoint interface, then look through the links in the opposite direction (W to V). If any of them have an address that lands within the subnet declared by the PtMP link, then that link is a constituent of the PtMP link, and its address is a nexthop address for V. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) { /* Having nexthop = 0 is tempting, but NOT acceptable. It breaks AS-External routes with a forwarding address, since ospf_ase_complete_direct_routes() will mistakenly assume we've reached the last hop and should place the forwarding address as nexthop. Also, users may configure multi-access links in p2p mode, so we need the IP to ARP the nexthop. */ struct ospf_neighbor *nbr_w; nbr_w = ospf_nbr_lookup_by_routerid (oi->nbrs, &l->link_id); if (nbr_w != NULL) { added = 1; nexthop = nbr_w->src; } } else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { struct prefix_ipv4 la; la.family = AF_INET; la.prefixlen = oi->address->prefixlen; /* V links to W on PtMP interface - find the interface address on W */ while ((l2 = ospf_get_next_link (w, v, l2))) { la.prefix = l2->link_data; if (prefix_cmp ((struct prefix *) &la, oi->address) != 0) continue; /* link_data is on our PtMP network */ added = 1; nexthop = l2->link_data; break; } } if (added) { /* found all necessary info to build nexthop */ nh = vertex_nexthop_new (); nh->oi = oi; nh->router = nexthop; ospf_spf_add_parent (v, w, nh, distance); return 1; } else zlog_info("%s: could not determine nexthop for link %s", __func__, oi->ifp->name); } /* end point-to-point link from V to W */ else if (l->m[0].type == LSA_LINK_TYPE_VIRTUALLINK) { struct ospf_vl_data *vl_data; /* VLink implementation limitations: * a) vl_data can only reference one nexthop, so no ECMP * to backbone through VLinks. Though transit-area * summaries may be considered, and those can be ECMP. * b) We can only use /one/ VLink, even if multiple ones * exist this router through multiple transit-areas. */ vl_data = ospf_vl_lookup (area->ospf, NULL, l->link_id); if (vl_data && CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) { nh = vertex_nexthop_new (); nh->oi = vl_data->nexthop.oi; nh->router = vl_data->nexthop.router; ospf_spf_add_parent (v, w, nh, distance); return 1; } else zlog_info("ospf_nexthop_calculation(): " "vl_data for VL link not found"); } /* end virtual-link from V to W */ return 0; } /* end W is a Router vertex */ else { assert(w->type == OSPF_VERTEX_NETWORK); nh = vertex_nexthop_new (); nh->oi = oi; nh->router.s_addr = 0; /* Nexthop not required */ ospf_spf_add_parent (v, w, nh, distance); return 1; } } /* end V is the root */ /* Check if W's parent is a network connected to root. */ else if (v->type == OSPF_VERTEX_NETWORK) { /* See if any of V's parents are the root. */ for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) { if (vp->parent == area->spf) /* connects to root? */ { /* 16.1.1 para 5. ...the parent vertex is a network that * directly connects the calculating router to the destination * router. The list of next hops is then determined by * examining the destination's router-LSA... */ assert(w->type == OSPF_VERTEX_ROUTER); while ((l = ospf_get_next_link (w, v, l))) { /* ...For each link in the router-LSA that points back to the * parent network, the link's Link Data field provides the IP * address of a next hop router. The outgoing interface to * use can then be derived from the next hop IP address (or * it can be inherited from the parent network). */ nh = vertex_nexthop_new (); nh->oi = vp->nexthop->oi; nh->router = l->link_data; added = 1; ospf_spf_add_parent (v, w, nh, distance); } /* Note lack of return is deliberate. See next comment. */ } } /* NB: This code is non-trivial. * * E.g. it is not enough to know that V connects to the root. It is * also important that the while above, looping through all links from * W->V found at least one link, so that we know there is * bi-directional connectivity between V and W (which need not be the * case, e.g. when OSPF has not yet converged fully). Otherwise, if * we /always/ return here, without having checked that root->V->-W * actually resulted in a valid nexthop being created, then we we will * prevent SPF from finding/using higher cost paths. * * It is important, if root->V->W has not been added, that we continue * through to the intervening-router nexthop code below. So as to * ensure other paths to V may be used. This avoids unnecessary * blackholes while OSPF is convergening. * * I.e. we may have arrived at this function, examining V -> W, via * workable paths other than root -> V, and it's important to avoid * getting "confused" by non-working root->V->W path - it's important * to *not* lose the working non-root paths, just because of a * non-viable root->V->W. * * See also bug #330 (required reading!), and: * * http://blogs.oracle.com/paulj/entry/the_difference_a_line_makes */ if (added) return added; } /* 16.1.1 para 4. If there is at least one intervening router in the * current shortest path between the destination and the root, the * destination simply inherits the set of next hops from the * parent. */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Intervening routers, adding parent(s)", __func__); for (ALL_LIST_ELEMENTS (v->parents, node, nnode, vp)) { added = 1; ospf_spf_add_parent (v, w, vp->nexthop, distance); } return added; } /* RFC2328 Section 16.1 (2). * v is on the SPF tree. Examine the links in v's LSA. Update the list * of candidates with any vertices not already on the list. If a lower-cost * path is found to a vertex already on the candidate list, store the new cost. */ static void ospf_spf_next (struct vertex *v, struct ospf_area *area, struct pqueue * candidate) { struct ospf_lsa *w_lsa = NULL; u_char *p; u_char *lim; struct router_lsa_link *l = NULL; struct in_addr *r; int type = 0, lsa_pos=-1, lsa_pos_next=0; /* If this is a router-LSA, and bit V of the router-LSA (see Section A.4.2:RFC2328) is set, set Area A's TransitCapability to TRUE. */ if (v->type == OSPF_VERTEX_ROUTER) { if (IS_ROUTER_LSA_VIRTUAL ((struct router_lsa *) v->lsa)) area->transit = OSPF_TRANSIT_TRUE; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: Next vertex of %s vertex %s", __func__, v->type == OSPF_VERTEX_ROUTER ? "Router" : "Network", inet_ntoa(v->lsa->id)); p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { struct vertex *w; unsigned int distance; /* In case of V is Router-LSA. */ if (v->lsa->type == OSPF_ROUTER_LSA) { l = (struct router_lsa_link *) p; lsa_pos = lsa_pos_next; /* LSA link position */ lsa_pos_next++; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); /* (a) If this is a link to a stub network, examine the next link in V's LSA. Links to stub networks will be considered in the second stage of the shortest path calculation. */ if ((type = l->m[0].type) == LSA_LINK_TYPE_STUB) continue; /* Infinite distance links shouldn't be followed, except * for local links (a stub-routed router still wants to * calculate tree, so must follow its own links). */ if ((v != area->spf) && l->m[0].metric >= OSPF_OUTPUT_COST_INFINITE) continue; /* (b) Otherwise, W is a transit vertex (router or transit network). Look up the vertex W's LSA (router-LSA or network-LSA) in Area A's link state database. */ switch (type) { case LSA_LINK_TYPE_POINTOPOINT: case LSA_LINK_TYPE_VIRTUALLINK: if (type == LSA_LINK_TYPE_VIRTUALLINK) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("looking up LSA through VL: %s", inet_ntoa (l->link_id)); } w_lsa = ospf_lsa_lookup (area, OSPF_ROUTER_LSA, l->link_id, l->link_id); if (w_lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found Router LSA %s", inet_ntoa (l->link_id)); } break; case LSA_LINK_TYPE_TRANSIT: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Looking up Network LSA, ID: %s", inet_ntoa (l->link_id)); w_lsa = ospf_lsa_lookup_by_id (area, OSPF_NETWORK_LSA, l->link_id); if (w_lsa) if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found the LSA"); break; default: zlog_warn ("Invalid LSA link type %d", type); continue; } } else { /* In case of V is Network-LSA. */ r = (struct in_addr *) p; p += sizeof (struct in_addr); /* Lookup the vertex W's LSA. */ w_lsa = ospf_lsa_lookup_by_id (area, OSPF_ROUTER_LSA, *r); if (w_lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found Router LSA %s", inet_ntoa (w_lsa->data->id)); } } /* (b cont.) If the LSA does not exist, or its LS age is equal to MaxAge, or it does not have a link back to vertex V, examine the next link in V's LSA.[23] */ if (w_lsa == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("No LSA found"); continue; } if (IS_LSA_MAXAGE (w_lsa)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA is MaxAge"); continue; } if (ospf_lsa_has_link (w_lsa->data, v->lsa) < 0 ) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("The LSA doesn't have a link back"); continue; } /* (c) If vertex W is already on the shortest-path tree, examine the next link in the LSA. */ if (w_lsa->stat == LSA_SPF_IN_SPFTREE) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("The LSA is already in SPF"); continue; } /* (d) Calculate the link state cost D of the resulting path from the root to vertex W. D is equal to the sum of the link state cost of the (already calculated) shortest path to vertex V and the advertised cost of the link between vertices V and W. If D is: */ /* calculate link cost D. */ if (v->lsa->type == OSPF_ROUTER_LSA) distance = v->distance + ntohs (l->m[0].metric); else /* v is not a Router-LSA */ distance = v->distance; /* Is there already vertex W in candidate list? */ if (w_lsa->stat == LSA_SPF_NOT_EXPLORED) { /* prepare vertex W. */ w = ospf_vertex_new (w_lsa); /* Calculate nexthop to W. */ if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) pqueue_enqueue (w, candidate); else if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Nexthop Calc failed"); } else if (w_lsa->stat >= 0) { /* Get the vertex from candidates. */ w = candidate->array[w_lsa->stat]; /* if D is greater than. */ if (w->distance < distance) { continue; } /* equal to. */ else if (w->distance == distance) { /* Found an equal-cost path to W. * Calculate nexthop of to W from V. */ ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos); } /* less than. */ else { /* Found a lower-cost path to W. * nexthop_calculation is conditional, if it finds * valid nexthop it will call spf_add_parents, which * will flush the old parents */ if (ospf_nexthop_calculation (area, v, w, l, distance, lsa_pos)) /* Decrease the key of the node in the heap. * trickle-sort it up towards root, just in case this * node should now be the new root due the cost change. * (next pqueu_{de,en}queue will fully re-heap the queue). */ trickle_up (w_lsa->stat, candidate); } } /* end W is already on the candidate list */ } /* end loop over the links in V's LSA */ } static void ospf_spf_dump (struct vertex *v, int i) { struct listnode *cnode; struct listnode *nnode; struct vertex_parent *parent; if (v->type == OSPF_VERTEX_ROUTER) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF Result: %d [R] %s", i, inet_ntoa (v->lsa->id)); } else { struct network_lsa *lsa = (struct network_lsa *) v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF Result: %d [N] %s/%d", i, inet_ntoa (v->lsa->id), ip_masklen (lsa->mask)); } if (IS_DEBUG_OSPF_EVENT) for (ALL_LIST_ELEMENTS_RO (v->parents, nnode, parent)) { zlog_debug (" nexthop %p %s %s", parent->nexthop, inet_ntoa (parent->nexthop->router), parent->nexthop->oi ? IF_NAME(parent->nexthop->oi) : "NULL"); } i++; for (ALL_LIST_ELEMENTS_RO (v->children, cnode, v)) ospf_spf_dump (v, i); } /* Second stage of SPF calculation. */ static void ospf_spf_process_stubs (struct ospf_area *area, struct vertex *v, struct route_table *rt, int parent_is_root) { struct listnode *cnode, *cnnode; struct vertex *child; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stub():processing stubs for area %s", inet_ntoa (area->area_id)); if (v->type == OSPF_VERTEX_ROUTER) { u_char *p; u_char *lim; struct router_lsa_link *l; struct router_lsa *rlsa; int lsa_pos = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stubs():processing router LSA, id: %s", inet_ntoa (v->lsa->id)); rlsa = (struct router_lsa *) v->lsa; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_process_stubs(): we have %d links to process", ntohs (rlsa->links)); p = ((u_char *) v->lsa) + OSPF_LSA_HEADER_SIZE + 4; lim = ((u_char *) v->lsa) + ntohs (v->lsa->length); while (p < lim) { l = (struct router_lsa_link *) p; p += (OSPF_ROUTER_LSA_LINK_SIZE + (l->m[0].tos_count * OSPF_ROUTER_LSA_TOS_SIZE)); if (l->m[0].type == LSA_LINK_TYPE_STUB) ospf_intra_add_stub (rt, l, v, area, parent_is_root, lsa_pos); lsa_pos++; } } ospf_vertex_dump("ospf_process_stubs(): after examining links: ", v, 1, 1); for (ALL_LIST_ELEMENTS (v->children, cnode, cnnode, child)) { if (CHECK_FLAG (child->flags, OSPF_VERTEX_PROCESSED)) continue; /* the first level of routers connected to the root * should have 'parent_is_root' set, including those * connected via a network vertex. */ if (area->spf == v) parent_is_root = 1; else if (v->type == OSPF_VERTEX_ROUTER) parent_is_root = 0; ospf_spf_process_stubs (area, child, rt, parent_is_root); SET_FLAG (child->flags, OSPF_VERTEX_PROCESSED); } } void ospf_rtrs_free (struct route_table *rtrs) { struct route_node *rn; struct list *or_list; struct ospf_route *or; struct listnode *node, *nnode; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Route: Router Routing Table free"); for (rn = route_top (rtrs); rn; rn = route_next (rn)) if ((or_list = rn->info) != NULL) { for (ALL_LIST_ELEMENTS (or_list, node, nnode, or)) ospf_route_free (or); list_delete (or_list); /* Unlock the node. */ rn->info = NULL; route_unlock_node (rn); } route_table_finish (rtrs); } #if 0 static void ospf_rtrs_print (struct route_table *rtrs) { struct route_node *rn; struct list *or_list; struct listnode *ln; struct listnode *pnode; struct ospf_route *or; struct ospf_path *path; char buf1[BUFSIZ]; char buf2[BUFSIZ]; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_rtrs_print() start"); for (rn = route_top (rtrs); rn; rn = route_next (rn)) if ((or_list = rn->info) != NULL) for (ALL_LIST_ELEMENTS_RO (or_list, ln, or)) { switch (or->path_type) { case OSPF_PATH_INTRA_AREA: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s [%d] area: %s", inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, inet_ntop (AF_INET, &or->u.std.area_id, buf2, BUFSIZ)); break; case OSPF_PATH_INTER_AREA: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s IA [%d] area: %s", inet_ntop (AF_INET, &or->id, buf1, BUFSIZ), or->cost, inet_ntop (AF_INET, &or->u.std.area_id, buf2, BUFSIZ)); break; default: break; } for (ALL_LIST_ELEMENTS_RO (or->paths, pnode, path)) { if (path->nexthop.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug (" directly attached to %s\r\n", ifindex2ifname (path->ifindex)); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug (" via %s, %s\r\n", inet_ntoa (path->nexthop), ifindex2ifname (path->ifindex)); } } } zlog_debug ("ospf_rtrs_print() end"); } #endif /* Calculating the shortest-path tree for an area. */ static void ospf_spf_calculate (struct ospf_area *area, struct route_table *new_table, struct route_table *new_rtrs) { struct pqueue *candidate; struct vertex *v; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_spf_calculate: Start"); zlog_debug ("ospf_spf_calculate: running Dijkstra for area %s", inet_ntoa (area->area_id)); } /* Check router-lsa-self. If self-router-lsa is not yet allocated, return this area's calculation. */ if (!area->router_lsa_self) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: " "Skip area %s's calculation due to empty router_lsa_self", inet_ntoa (area->area_id)); return; } /* RFC2328 16.1. (1). */ /* Initialize the algorithm's data structures. */ /* This function scans all the LSA database and set the stat field to * LSA_SPF_NOT_EXPLORED. */ ospf_lsdb_clean_stat (area->lsdb); /* Create a new heap for the candidates. */ candidate = pqueue_create(); candidate->cmp = cmp; candidate->update = update_stat; /* Initialize the shortest-path tree to only the root (which is the router doing the calculation). */ ospf_spf_init (area); v = area->spf; /* Set LSA position to LSA_SPF_IN_SPFTREE. This vertex is the root of the * spanning tree. */ *(v->stat) = LSA_SPF_IN_SPFTREE; /* Set Area A's TransitCapability to FALSE. */ area->transit = OSPF_TRANSIT_FALSE; area->shortcut_capability = 1; for (;;) { /* RFC2328 16.1. (2). */ ospf_spf_next (v, area, candidate); /* RFC2328 16.1. (3). */ /* If at this step the candidate list is empty, the shortest- path tree (of transit vertices) has been completely built and this stage of the procedure terminates. */ if (candidate->size == 0) break; /* Otherwise, choose the vertex belonging to the candidate list that is closest to the root, and add it to the shortest-path tree (removing it from the candidate list in the process). */ /* Extract from the candidates the node with the lower key. */ v = (struct vertex *) pqueue_dequeue (candidate); /* Update stat field in vertex. */ *(v->stat) = LSA_SPF_IN_SPFTREE; ospf_vertex_add_parent (v); /* RFC2328 16.1. (4). */ if (v->type == OSPF_VERTEX_ROUTER) ospf_intra_add_router (new_rtrs, v, area); else ospf_intra_add_transit (new_table, v, area); /* RFC2328 16.1. (5). */ /* Iterate the algorithm by returning to Step 2. */ } /* end loop until no more candidate vertices */ if (IS_DEBUG_OSPF_EVENT) { ospf_spf_dump (area->spf, 0); ospf_route_table_dump (new_table); } /* Second stage of SPF calculation procedure's */ ospf_spf_process_stubs (area, area->spf, new_table, 0); /* Free candidate queue. */ pqueue_delete (candidate); ospf_vertex_dump (__func__, area->spf, 0, 1); /* Free nexthop information, canonical versions of which are attached * the first level of router vertices attached to the root vertex, see * ospf_nexthop_calculation. */ ospf_canonical_nexthops_free (area->spf); /* Increment SPF Calculation Counter. */ area->spf_calculation++; quagga_gettime (QUAGGA_CLK_MONOTONIC, &area->ospf->ts_spf); area->ts_spf = area->ospf->ts_spf; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_spf_calculate: Stop. %ld vertices", mtype_stats_alloc(MTYPE_OSPF_VERTEX)); /* Free SPF vertices, but not the list. List has ospf_vertex_free * as deconstructor. */ list_delete_all_node (&vertex_list); } /* Timer for SPF calculation. */ static int ospf_spf_calculate_timer (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct route_table *new_table, *new_rtrs; struct ospf_area *area; struct listnode *node, *nnode; struct timeval start_time, stop_time, spf_start_time; int areas_processed = 0; unsigned long ia_time, prune_time, rt_time; unsigned long abr_time, total_spf_time, spf_time; char rbuf[32]; /* reason_buf */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: Timer (SPF calculation expire)"); ospf->t_spf_calc = NULL; quagga_gettime (QUAGGA_CLK_MONOTONIC, &spf_start_time); /* Allocate new table tree. */ new_table = route_table_init (); new_rtrs = route_table_init (); ospf_vl_unapprove (ospf); /* Calculate SPF for each area. */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { /* Do backbone last, so as to first discover intra-area paths * for any back-bone virtual-links */ if (ospf->backbone && ospf->backbone == area) continue; ospf_spf_calculate (area, new_table, new_rtrs); areas_processed++; } /* SPF for backbone, if required */ if (ospf->backbone) { ospf_spf_calculate (ospf->backbone, new_table, new_rtrs); areas_processed++; } quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); spf_time = timeval_elapsed (stop_time, spf_start_time); ospf_vl_shut_unapproved (ospf); start_time = stop_time; /* saving a call */ ospf_ia_routing (ospf, new_table, new_rtrs); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); ia_time = timeval_elapsed (stop_time, start_time); quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); ospf_prune_unreachable_networks (new_table); ospf_prune_unreachable_routers (new_rtrs); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); prune_time = timeval_elapsed (stop_time, start_time); /* AS-external-LSA calculation should not be performed here. */ /* If new Router Route is installed, then schedule re-calculate External routes. */ if (1) ospf_ase_calculate_schedule (ospf); ospf_ase_calculate_timer_add (ospf); quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); /* Update routing table. */ ospf_route_install (ospf, new_table); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); rt_time = timeval_elapsed (stop_time, start_time); /* Update ABR/ASBR routing table */ if (ospf->old_rtrs) { /* old_rtrs's node holds linked list of ospf_route. --kunihiro. */ /* ospf_route_delete (ospf->old_rtrs); */ ospf_rtrs_free (ospf->old_rtrs); } ospf->old_rtrs = ospf->new_rtrs; ospf->new_rtrs = new_rtrs; quagga_gettime (QUAGGA_CLK_MONOTONIC, &start_time); if (IS_OSPF_ABR (ospf)) ospf_abr_task (ospf); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); abr_time = timeval_elapsed (stop_time, start_time); quagga_gettime (QUAGGA_CLK_MONOTONIC, &stop_time); total_spf_time = timeval_elapsed (stop_time, spf_start_time); ospf->ts_spf_duration.tv_sec = total_spf_time/1000000; ospf->ts_spf_duration.tv_usec = total_spf_time % 1000000; ospf_get_spf_reason_str (rbuf); if (IS_DEBUG_OSPF_EVENT) { zlog_info ("SPF Processing Time(usecs): %ld", total_spf_time); zlog_info ("\t SPF Time: %ld", spf_time); zlog_info ("\t InterArea: %ld", ia_time); zlog_info ("\t Prune: %ld", prune_time); zlog_info ("\tRouteInstall: %ld", rt_time); if (IS_OSPF_ABR (ospf)) zlog_info ("\t ABR: %ld (%d areas)", abr_time, areas_processed); zlog_info ("Reason(s) for SPF: %s", rbuf); } ospf_clear_spf_reason_flags (); return 0; } /* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer for SPF calc. */ void ospf_spf_calculate_schedule (struct ospf *ospf, ospf_spf_reason_t reason) { unsigned long delay, elapsed, ht; struct timeval result; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer scheduled"); /* OSPF instance does not exist. */ if (ospf == NULL) return; ospf_spf_set_reason (reason); /* SPF calculation timer is already scheduled. */ if (ospf->t_spf_calc) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer is already scheduled: %p", ospf->t_spf_calc); return; } /* XXX Monotic timers: we only care about relative time here. */ result = tv_sub (recent_relative_time (), ospf->ts_spf); elapsed = (result.tv_sec * 1000) + (result.tv_usec / 1000); ht = ospf->spf_holdtime * ospf->spf_hold_multiplier; if (ht > ospf->spf_max_holdtime) ht = ospf->spf_max_holdtime; /* Get SPF calculation delay time. */ if (elapsed < ht) { /* Got an event within the hold time of last SPF. We need to * increase the hold_multiplier, if it's not already at/past * maximum value, and wasn't already increased.. */ if (ht < ospf->spf_max_holdtime) ospf->spf_hold_multiplier++; /* always honour the SPF initial delay */ if ( (ht - elapsed) < ospf->spf_delay) delay = ospf->spf_delay; else delay = ht - elapsed; } else { /* Event is past required hold-time of last SPF */ delay = ospf->spf_delay; ospf->spf_hold_multiplier = 1; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("SPF: calculation timer delay = %ld", delay); zlog_info ("SPF: Scheduled in %ld msec", delay); ospf->t_spf_calc = thread_add_timer_msec (master, ospf_spf_calculate_timer, ospf, delay); } quagga-0.99.24.1/ospfd/ospf_lsa.c0000644000175000017500000031404612476520570013331 00000000000000/* * OSPF Link State Advertisement * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "stream.h" #include "log.h" #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ #include "checksum.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" u_int32_t get_metric (u_char *metric) { u_int32_t m; m = metric[0]; m = (m << 8) + metric[1]; m = (m << 8) + metric[2]; return m; } struct timeval tv_adjust (struct timeval a) { while (a.tv_usec >= 1000000) { a.tv_usec -= 1000000; a.tv_sec++; } while (a.tv_usec < 0) { a.tv_usec += 1000000; a.tv_sec--; } return a; } int tv_ceil (struct timeval a) { a = tv_adjust (a); return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec); } int tv_floor (struct timeval a) { a = tv_adjust (a); return a.tv_sec; } struct timeval int2tv (int a) { struct timeval ret; ret.tv_sec = a; ret.tv_usec = 0; return ret; } struct timeval tv_add (struct timeval a, struct timeval b) { struct timeval ret; ret.tv_sec = a.tv_sec + b.tv_sec; ret.tv_usec = a.tv_usec + b.tv_usec; return tv_adjust (ret); } struct timeval tv_sub (struct timeval a, struct timeval b) { struct timeval ret; ret.tv_sec = a.tv_sec - b.tv_sec; ret.tv_usec = a.tv_usec - b.tv_usec; return tv_adjust (ret); } int tv_cmp (struct timeval a, struct timeval b) { return (a.tv_sec == b.tv_sec ? a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec); } int ospf_lsa_refresh_delay (struct ospf_lsa *lsa) { struct timeval delta, now; int delay = 0; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); delta = tv_sub (now, lsa->tv_orig); if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0) { delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta)); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Refresh timer delay %d seconds", lsa->data->type, inet_ntoa (lsa->data->id), delay); assert (delay > 0); } return delay; } int get_age (struct ospf_lsa *lsa) { int age; age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (recent_relative_time (), lsa->tv_recv)); return age; } /* Fletcher Checksum -- Refer to RFC1008. */ /* All the offsets are zero-based. The offsets in the RFC1008 are one-based. */ u_int16_t ospf_lsa_checksum (struct lsa_header *lsa) { u_char *buffer = (u_char *) &lsa->options; int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa->length) - options_offset; /* Checksum offset starts from "options" field, not the beginning of the lsa_header struct. The offset is 14, rather than 16. */ int checksum_offset = (u_char *) &lsa->checksum - buffer; return fletcher_checksum(buffer, len, checksum_offset); } int ospf_lsa_checksum_valid (struct lsa_header *lsa) { u_char *buffer = (u_char *) &lsa->options; int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */ /* Skip the AGE field */ u_int16_t len = ntohs(lsa->length) - options_offset; return(fletcher_checksum(buffer, len, FLETCHER_CHECKSUM_VALIDATE) == 0); } /* Create OSPF LSA. */ struct ospf_lsa * ospf_lsa_new () { struct ospf_lsa *new; new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); new->flags = 0; new->lock = 1; new->retransmit_counter = 0; new->tv_recv = recent_relative_time (); new->tv_orig = new->tv_recv; new->refresh_list = -1; return new; } /* Duplicate OSPF LSA. */ struct ospf_lsa * ospf_lsa_dup (struct ospf_lsa *lsa) { struct ospf_lsa *new; if (lsa == NULL) return NULL; new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa)); memcpy (new, lsa, sizeof (struct ospf_lsa)); UNSET_FLAG (new->flags, OSPF_LSA_DISCARD); new->lock = 1; new->retransmit_counter = 0; new->data = ospf_lsa_data_dup (lsa->data); /* kevinm: Clear the refresh_list, otherwise there are going to be problems when we try to remove the LSA from the queue (which it's not a member of.) XXX: Should we add the LSA to the refresh_list queue? */ new->refresh_list = -1; if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("LSA: duplicated %p (new: %p)", lsa, new); return new; } /* Free OSPF LSA. */ void ospf_lsa_free (struct ospf_lsa *lsa) { assert (lsa->lock == 0); if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("LSA: freed %p", lsa); /* Delete LSA data. */ if (lsa->data != NULL) ospf_lsa_data_free (lsa->data); assert (lsa->refresh_list < 0); memset (lsa, 0, sizeof (struct ospf_lsa)); XFREE (MTYPE_OSPF_LSA, lsa); } /* Lock LSA. */ struct ospf_lsa * ospf_lsa_lock (struct ospf_lsa *lsa) { lsa->lock++; return lsa; } /* Unlock LSA. */ void ospf_lsa_unlock (struct ospf_lsa **lsa) { /* This is sanity check. */ if (!lsa || !*lsa) return; (*lsa)->lock--; assert ((*lsa)->lock >= 0); if ((*lsa)->lock == 0) { assert (CHECK_FLAG ((*lsa)->flags, OSPF_LSA_DISCARD)); ospf_lsa_free (*lsa); *lsa = NULL; } } /* Check discard flag. */ void ospf_lsa_discard (struct ospf_lsa *lsa) { if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) { SET_FLAG (lsa->flags, OSPF_LSA_DISCARD); ospf_lsa_unlock (&lsa); } } /* Create LSA data. */ struct lsa_header * ospf_lsa_data_new (size_t size) { return XCALLOC (MTYPE_OSPF_LSA_DATA, size); } /* Duplicate LSA data. */ struct lsa_header * ospf_lsa_data_dup (struct lsa_header *lsah) { struct lsa_header *new; new = ospf_lsa_data_new (ntohs (lsah->length)); memcpy (new, lsah, ntohs (lsah->length)); return new; } /* Free LSA data. */ void ospf_lsa_data_free (struct lsa_header *lsah) { if (IS_DEBUG_OSPF (lsa, LSA)) zlog_debug ("LSA[Type%d:%s]: data freed %p", lsah->type, inet_ntoa (lsah->id), lsah); XFREE (MTYPE_OSPF_LSA_DATA, lsah); } /* LSA general functions. */ const char * dump_lsa_key (struct ospf_lsa *lsa) { static char buf[] = { "Type255,id(255.255.255.255),ar(255.255.255.255)" }; struct lsa_header *lsah; if (lsa != NULL && (lsah = lsa->data) != NULL) { char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN]; strcpy (id, inet_ntoa (lsah->id)); strcpy (ar, inet_ntoa (lsah->adv_router)); sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar); } else strcpy (buf, "NULL"); return buf; } u_int32_t lsa_seqnum_increment (struct ospf_lsa *lsa) { u_int32_t seqnum; seqnum = ntohl (lsa->data->ls_seqnum) + 1; return htonl (seqnum); } void lsa_header_set (struct stream *s, u_char options, u_char type, struct in_addr id, struct in_addr router_id) { struct lsa_header *lsah; lsah = (struct lsa_header *) STREAM_DATA (s); lsah->ls_age = htons (OSPF_LSA_INITIAL_AGE); lsah->options = options; lsah->type = type; lsah->id = id; lsah->adv_router = router_id; lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER); stream_forward_endp (s, OSPF_LSA_HEADER_SIZE); } /* router-LSA related functions. */ /* Get router-LSA flags. */ static u_char router_lsa_flags (struct ospf_area *area) { u_char flags; flags = area->ospf->flags; /* Set virtual link flag. */ if (ospf_full_virtual_nbrs (area)) SET_FLAG (flags, ROUTER_LSA_VIRTUAL); else /* Just sanity check */ UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL); /* Set Shortcut ABR behabiour flag. */ UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT); if (area->ospf->abr_type == OSPF_ABR_SHORTCUT) if (!OSPF_IS_AREA_BACKBONE (area)) if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && area->ospf->backbone == NULL) || area->shortcut_configured == OSPF_SHORTCUT_ENABLE) SET_FLAG (flags, ROUTER_LSA_SHORTCUT); /* ASBR can't exit in stub area. */ if (area->external_routing == OSPF_AREA_STUB) UNSET_FLAG (flags, ROUTER_LSA_EXTERNAL); /* If ASBR set External flag */ else if (IS_OSPF_ASBR (area->ospf)) SET_FLAG (flags, ROUTER_LSA_EXTERNAL); /* Set ABR dependent flags */ if (IS_OSPF_ABR (area->ospf)) { SET_FLAG (flags, ROUTER_LSA_BORDER); /* If Area is NSSA and we are both ABR and unconditional translator, * set Nt bit to inform other routers. */ if ( (area->external_routing == OSPF_AREA_NSSA) && (area->NSSATranslatorRole == OSPF_NSSA_ROLE_ALWAYS)) SET_FLAG (flags, ROUTER_LSA_NT); } return flags; } /* Lookup neighbor other than myself. And check neighbor count, Point-to-Point link must have only 1 neighbor. */ struct ospf_neighbor * ospf_nbr_lookup_ptop (struct ospf_interface *oi) { struct ospf_neighbor *nbr = NULL; struct route_node *rn; /* Search neighbor, there must be one of two nbrs. */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) if (nbr->state == NSM_Full) { route_unlock_node (rn); break; } /* PtoP link must have only 1 neighbor. */ if (ospf_nbr_count (oi, 0) > 1) zlog_warn ("Point-to-Point link has more than 1 neighobrs."); return nbr; } /* Determine cost of link, taking RFC3137 stub-router support into * consideration */ static u_int16_t ospf_link_cost (struct ospf_interface *oi) { /* RFC3137 stub router support */ if (!CHECK_FLAG (oi->area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) return oi->output_cost; else return OSPF_OUTPUT_COST_INFINITE; } /* Set a link information. */ static char link_info_set (struct stream *s, struct in_addr id, struct in_addr data, u_char type, u_char tos, u_int16_t cost) { /* LSA stream is initially allocated to OSPF_MAX_LSA_SIZE, suits * vast majority of cases. Some rare routers with lots of links need more. * we try accomodate those here. */ if (STREAM_WRITEABLE(s) < OSPF_ROUTER_LSA_LINK_SIZE) { size_t ret = OSPF_MAX_LSA_SIZE; /* Can we enlarge the stream still? */ if (STREAM_SIZE(s) == OSPF_MAX_LSA_SIZE) { /* we futz the size here for simplicity, really we need to account * for just: * IP Header - (sizeof (struct ip)) * OSPF Header - OSPF_HEADER_SIZE * LSA Header - OSPF_LSA_HEADER_SIZE * MD5 auth data, if MD5 is configured - OSPF_AUTH_MD5_SIZE. * * Simpler just to subtract OSPF_MAX_LSA_SIZE though. */ ret = stream_resize (s, OSPF_MAX_PACKET_SIZE - OSPF_MAX_LSA_SIZE); } if (ret == OSPF_MAX_LSA_SIZE) { zlog_warn ("%s: Out of space in LSA stream, left %zd, size %zd", __func__, STREAM_REMAIN (s), STREAM_SIZE (s)); return 0; } } /* TOS based routing is not supported. */ stream_put_ipv4 (s, id.s_addr); /* Link ID. */ stream_put_ipv4 (s, data.s_addr); /* Link Data. */ stream_putc (s, type); /* Link Type. */ stream_putc (s, tos); /* TOS = 0. */ stream_putw (s, cost); /* Link Cost. */ return 1; } /* Describe Point-to-Point link (Section 12.4.1.1). */ static int lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi) { int links = 0; struct ospf_neighbor *nbr; struct in_addr id, mask; u_int16_t cost = ospf_link_cost (oi); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Set link Point-to-Point"); if ((nbr = ospf_nbr_lookup_ptop (oi))) if (nbr->state == NSM_Full) { /* For unnumbered point-to-point networks, the Link Data field should specify the interface's MIB-II ifIndex value. */ links += link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_POINTOPOINT, 0, cost); } /* Regardless of the state of the neighboring router, we must add a Type 3 link (stub network). N.B. Options 1 & 2 share basically the same logic. */ masklen2ip (oi->address->prefixlen, &mask); id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr & mask.s_addr; links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); return links; } /* Describe Broadcast Link. */ static int lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *dr; struct in_addr id, mask; u_int16_t cost = ospf_link_cost (oi); /* Describe Type 3 Link. */ if (oi->state == ISM_Waiting) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s is in state Waiting. " "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); } dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi)); /* Describe Type 2 link. */ if (dr && (dr->state == NSM_Full || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) && ospf_nbr_count (oi, NSM_Full) > 0) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s has a DR. " "Adding transit interface", oi->ifp->name); return link_info_set (s, DR (oi), oi->address->u.prefix4, LSA_LINK_TYPE_TRANSIT, 0, cost); } /* Describe type 3 link. */ else { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Interface %s has no DR. " "Adding stub interface", oi->ifp->name); masklen2ip (oi->address->prefixlen, &mask); id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); } } static int lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi) { struct in_addr id, mask; /* Describe Type 3 Link. */ if (oi->state != ISM_Loopback) return 0; mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; return link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost); } /* Describe Virtual Link. */ static int lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi) { struct ospf_neighbor *nbr; u_int16_t cost = ospf_link_cost (oi); if (oi->state == ISM_PointToPoint) if ((nbr = ospf_nbr_lookup_ptop (oi))) if (nbr->state == NSM_Full) { return link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_VIRTUALLINK, 0, cost); } return 0; } #define lsa_link_nbma_set(S,O) lsa_link_broadcast_set (S, O) /* this function add for support point-to-multipoint ,see rfc2328 12.4.1.4.*/ /* from "edward rrr" http://marc.theaimsgroup.com/?l=zebra&m=100739222210507&w=2 */ static int lsa_link_ptomp_set (struct stream *s, struct ospf_interface *oi) { int links = 0; struct route_node *rn; struct ospf_neighbor *nbr = NULL; struct in_addr id, mask; u_int16_t cost = ospf_link_cost (oi); mask.s_addr = 0xffffffff; id.s_addr = oi->address->u.prefix4.s_addr; links += link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("PointToMultipoint: running ptomultip_set"); /* Search neighbor, */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) /* Ignore myself. */ if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) if (nbr->state == NSM_Full) { links += link_info_set (s, nbr->router_id, oi->address->u.prefix4, LSA_LINK_TYPE_POINTOPOINT, 0, cost); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("PointToMultipoint: set link to %s", inet_ntoa(oi->address->u.prefix4)); } return links; } /* Set router-LSA link information. */ static int router_lsa_link_set (struct stream *s, struct ospf_area *area) { struct listnode *node; struct ospf_interface *oi; int links = 0; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { struct interface *ifp = oi->ifp; /* Check interface is up, OSPF is enable. */ if (if_is_operative (ifp)) { if (oi->state != ISM_Down) { oi->lsa_pos_beg = links; /* Describe each link. */ switch (oi->type) { case OSPF_IFTYPE_POINTOPOINT: links += lsa_link_ptop_set (s, oi); break; case OSPF_IFTYPE_BROADCAST: links += lsa_link_broadcast_set (s, oi); break; case OSPF_IFTYPE_NBMA: links += lsa_link_nbma_set (s, oi); break; case OSPF_IFTYPE_POINTOMULTIPOINT: links += lsa_link_ptomp_set (s, oi); break; case OSPF_IFTYPE_VIRTUALLINK: links += lsa_link_virtuallink_set (s, oi); break; case OSPF_IFTYPE_LOOPBACK: links += lsa_link_loopback_set (s, oi); } oi->lsa_pos_end = links; } } } return links; } /* Set router-LSA body. */ static void ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area) { unsigned long putp; u_int16_t cnt; /* Set flags. */ stream_putc (s, router_lsa_flags (area)); /* Set Zero fields. */ stream_putc (s, 0); /* Keep pointer to # links. */ putp = stream_get_endp(s); /* Forward word */ stream_putw(s, 0); /* Set all link information. */ cnt = router_lsa_link_set (s, area); /* Set # of links here. */ stream_putw_at (s, putp, cnt); } static int ospf_stub_router_timer (struct thread *t) { struct ospf_area *area = THREAD_ARG (t); area->t_stub_router = NULL; SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); /* clear stub route state and generate router-lsa refresh, don't * clobber an administratively set stub-router state though. */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) return 0; UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); ospf_router_lsa_update_area (area); return 0; } static void ospf_stub_router_check (struct ospf_area *area) { /* area must either be administratively configured to be stub * or startup-time stub-router must be configured and we must in a pre-stub * state. */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED)) { SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); return; } /* not admin-stubbed, check whether startup stubbing is configured and * whether it's not been done yet */ if (CHECK_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED)) return; if (area->ospf->stub_router_startup_time == OSPF_STUB_ROUTER_UNCONFIGURED) { /* stub-router is hence done forever for this area, even if someone * tries configure it (take effect next restart). */ SET_FLAG (area->stub_router_state, OSPF_AREA_WAS_START_STUB_ROUTED); return; } /* startup stub-router configured and not yet done */ SET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED); OSPF_AREA_TIMER_ON (area->t_stub_router, ospf_stub_router_timer, area->ospf->stub_router_startup_time); } /* Create new router-LSA. */ static struct ospf_lsa * ospf_router_lsa_new (struct ospf_area *area) { struct ospf *ospf = area->ospf; struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new; int length; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type1]: Create router-LSA instance"); /* check whether stub-router is desired, and if this is the first * router LSA. */ ospf_stub_router_check (area); /* Create a stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); /* Set LSA common header fields. */ lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_OPTIONS_NSSA_GET (area), OSPF_ROUTER_LSA, ospf->router_id, ospf->router_id); /* Set router-LSA body fields. */ ospf_router_lsa_body_set (s, area); /* Set length. */ length = stream_get_endp (s); lsah = (struct lsa_header *) STREAM_DATA (s); lsah->length = htons (length); /* Now, create OSPF LSA instance. */ if ( (new = ospf_lsa_new ()) == NULL) { zlog_err ("%s: Unable to create new lsa", __func__); return NULL; } new->area = area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* Copy LSA data to store, discard stream. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); return new; } /* Originate Router-LSA. */ static struct ospf_lsa * ospf_router_lsa_originate (struct ospf_area *area) { struct ospf_lsa *new; /* Create new router-LSA instance. */ if ( (new = ospf_router_lsa_new (area)) == NULL) { zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); return NULL; } /* Sanity check. */ if (new->data->adv_router.s_addr == 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type1]: AdvRouter is 0, discard"); ospf_lsa_discard (new); return NULL; } /* Install LSA to LSDB. */ new = ospf_lsa_install (area->ospf, NULL, new); /* Update LSA origination count. */ area->ospf->lsa_originate_count++; /* Flooding new LSA through area. */ ospf_flood_through_area (area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate router-LSA %p", new->data->type, inet_ntoa (new->data->id), new); ospf_lsa_header_dump (new->data); } return new; } /* Refresh router-LSA. */ static struct ospf_lsa * ospf_router_lsa_refresh (struct ospf_lsa *lsa) { struct ospf_area *area = lsa->area; struct ospf_lsa *new; /* Sanity check. */ assert (lsa->data); /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_area (area, lsa); /* Unregister LSA from refresh-list */ ospf_refresher_unregister_lsa (area->ospf, lsa); /* Create new router-LSA instance. */ if ( (new = ospf_router_lsa_new (area)) == NULL) { zlog_err ("%s: ospf_router_lsa_new returned NULL", __func__); return NULL; } new->data->ls_seqnum = lsa_seqnum_increment (lsa); ospf_lsa_install (area->ospf, NULL, new); /* Flood LSA through area. */ ospf_flood_through_area (area, NULL, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: router-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return NULL; } int ospf_router_lsa_update_area (struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("[router-LSA]: (router-LSA area update)"); /* Now refresh router-LSA. */ if (area->router_lsa_self) ospf_lsa_refresh (area->ospf, area->router_lsa_self); /* Newly originate router-LSA. */ else ospf_router_lsa_originate (area); return 0; } int ospf_router_lsa_update (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_area *area; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("Timer[router-LSA Update]: (timer expire)"); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { struct ospf_lsa *lsa = area->router_lsa_self; struct router_lsa *rl; const char *area_str; /* Keep Area ID string. */ area_str = AREA_NAME (area); /* If LSA not exist in this Area, originate new. */ if (lsa == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug("LSA[Type1]: Create router-LSA for Area %s", area_str); ospf_router_lsa_originate (area); } /* If router-ID is changed, Link ID must change. First flush old LSA, then originate new. */ else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug("LSA[Type%d:%s]: Refresh router-LSA for Area %s", lsa->data->type, inet_ntoa (lsa->data->id), area_str); ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush_area (lsa, area); ospf_lsa_unlock (&area->router_lsa_self); area->router_lsa_self = NULL; /* Refresh router-LSA, (not install) and flood through area. */ ospf_router_lsa_update_area (area); } else { rl = (struct router_lsa *) lsa->data; /* Refresh router-LSA, (not install) and flood through area. */ if (rl->flags != ospf->flags) ospf_router_lsa_update_area (area); } } return 0; } /* network-LSA related functions. */ /* Originate Network-LSA. */ static void ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi) { struct in_addr mask; struct route_node *rn; struct ospf_neighbor *nbr; masklen2ip (oi->address->prefixlen, &mask); stream_put_ipv4 (s, mask.s_addr); /* The network-LSA lists those routers that are fully adjacent to the Designated Router; each fully adjacent router is identified by its OSPF Router ID. The Designated Router includes itself in this list. RFC2328, Section 12.4.2 */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr->state == NSM_Full || nbr == oi->nbr_self) stream_put_ipv4 (s, nbr->router_id.s_addr); } static struct ospf_lsa * ospf_network_lsa_new (struct ospf_interface *oi) { struct stream *s; struct ospf_lsa *new; struct lsa_header *lsah; struct ospf_if_params *oip; int length; /* If there are no neighbours on this network (the net is stub), the router does not originate network-LSA (see RFC 12.4.2) */ if (oi->full_nbrs == 0) return NULL; if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type2]: Create network-LSA instance"); /* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s); lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)), OSPF_NETWORK_LSA, DR (oi), oi->ospf->router_id); /* Set network-LSA body fields. */ ospf_network_lsa_body_set (s, oi); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Create OSPF LSA instance. */ if ( (new = ospf_lsa_new ()) == NULL) { zlog_err ("%s: ospf_lsa_new returned NULL", __func__); return NULL; } new->area = oi->area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* Copy LSA to store. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); /* Remember prior network LSA sequence numbers, even if we stop * originating one for this oi, to try avoid re-originating LSAs with a * prior sequence number, and thus speed up adjency forming & convergence. */ if ((oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4))) { new->data->ls_seqnum = oip->network_lsa_seqnum; new->data->ls_seqnum = lsa_seqnum_increment (new); } else { oip = ospf_get_if_params (oi->ifp, oi->address->u.prefix4); ospf_if_update_params (oi->ifp, oi->address->u.prefix4); } oip->network_lsa_seqnum = new->data->ls_seqnum; return new; } /* Originate network-LSA. */ void ospf_network_lsa_update (struct ospf_interface *oi) { struct ospf_lsa *new; if (oi->network_lsa_self != NULL) { ospf_lsa_refresh (oi->ospf, oi->network_lsa_self); return; } /* Create new network-LSA instance. */ new = ospf_network_lsa_new (oi); if (new == NULL) return; /* Install LSA to LSDB. */ new = ospf_lsa_install (oi->ospf, oi, new); /* Update LSA origination count. */ oi->ospf->lsa_originate_count++; /* Flooding new LSA through area. */ ospf_flood_through_area (oi->area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate network-LSA %p", new->data->type, inet_ntoa (new->data->id), new); ospf_lsa_header_dump (new->data); } return; } static struct ospf_lsa * ospf_network_lsa_refresh (struct ospf_lsa *lsa) { struct ospf_area *area = lsa->area; struct ospf_lsa *new, *new2; struct ospf_if_params *oip; struct ospf_interface *oi; assert (lsa->data); /* Retrieve the oi for the network LSA */ oi = ospf_if_lookup_by_local_addr (area->ospf, NULL, lsa->data->id); if (oi == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: network-LSA refresh: " "no oi found, ick, ignoring.", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_lsa_header_dump (lsa->data); } return NULL; } /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_area (area, lsa); /* Unregister LSA from refresh-list */ ospf_refresher_unregister_lsa (area->ospf, lsa); /* Create new network-LSA instance. */ new = ospf_network_lsa_new (oi); if (new == NULL) return NULL; oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4); assert (oip != NULL); oip->network_lsa_seqnum = new->data->ls_seqnum = lsa_seqnum_increment (lsa); new2 = ospf_lsa_install (area->ospf, oi, new); assert (new2 == new); /* Flood LSA through aera. */ ospf_flood_through_area (area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: network-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } static void stream_put_ospf_metric (struct stream *s, u_int32_t metric_value) { u_int32_t metric; char *mp; /* Put 0 metric. TOS metric is not supported. */ metric = htonl (metric_value); mp = (char *) &metric; mp++; stream_put (s, mp, 3); } /* summary-LSA related functions. */ static void ospf_summary_lsa_body_set (struct stream *s, struct prefix *p, u_int32_t metric) { struct in_addr mask; masklen2ip (p->prefixlen, &mask); /* Put Network Mask. */ stream_put_ipv4 (s, mask.s_addr); /* Set # TOS. */ stream_putc (s, (u_char) 0); /* Set metric. */ stream_put_ospf_metric (s, metric); } static struct ospf_lsa * ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p, u_int32_t metric, struct in_addr id) { struct stream *s; struct ospf_lsa *new; struct lsa_header *lsah; int length; if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type3]: Create summary-LSA instance"); /* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s); lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, id, area->ospf->router_id); /* Set summary-LSA body fields. */ ospf_summary_lsa_body_set (s, p, metric); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Create OSPF LSA instance. */ new = ospf_lsa_new (); new->area = area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* Copy LSA to store. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); return new; } /* Originate Summary-LSA. */ struct ospf_lsa * ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, struct ospf_area *area) { struct ospf_lsa *new; struct in_addr id; id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_SUMMARY_LSA, p); if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ if ( !(new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id))) return NULL; /* Instlal LSA to LSDB. */ new = ospf_lsa_install (area->ospf, NULL, new); /* Update LSA origination count. */ area->ospf->lsa_originate_count++; /* Flooding new LSA through area. */ ospf_flood_through_area (area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate summary-LSA %p", new->data->type, inet_ntoa (new->data->id), new); ospf_lsa_header_dump (new->data); } return new; } static struct ospf_lsa* ospf_summary_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) { struct ospf_lsa *new; struct summary_lsa *sl; struct prefix p; /* Sanity check. */ assert (lsa->data); sl = (struct summary_lsa *)lsa->data; p.prefixlen = ip_masklen (sl->mask); new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), sl->header.id); if (!new) return NULL; new->data->ls_seqnum = lsa_seqnum_increment (lsa); ospf_lsa_install (ospf, NULL, new); /* Flood LSA through AS. */ ospf_flood_through_area (new->area, NULL, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: summary-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } /* summary-ASBR-LSA related functions. */ static void ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p, u_int32_t metric) { /* Put Network Mask. */ stream_put_ipv4 (s, (u_int32_t) 0); /* Set # TOS. */ stream_putc (s, (u_char) 0); /* Set metric. */ stream_put_ospf_metric (s, metric); } static struct ospf_lsa * ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p, u_int32_t metric, struct in_addr id) { struct stream *s; struct ospf_lsa *new; struct lsa_header *lsah; int length; if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type3]: Create summary-LSA instance"); /* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s); lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, id, area->ospf->router_id); /* Set summary-LSA body fields. */ ospf_summary_asbr_lsa_body_set (s, p, metric); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Create OSPF LSA instance. */ new = ospf_lsa_new (); new->area = area; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_SELF_CHECKED); /* Copy LSA to store. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); return new; } /* Originate summary-ASBR-LSA. */ struct ospf_lsa * ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, struct ospf_area *area) { struct ospf_lsa *new; struct in_addr id; id = ospf_lsa_unique_id (area->ospf, area->lsdb, OSPF_ASBR_SUMMARY_LSA, p); if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d]: Link ID not available, can't originate", OSPF_ASBR_SUMMARY_LSA); return NULL; } /* Create new summary-LSA instance. */ new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id); if (!new) return NULL; /* Install LSA to LSDB. */ new = ospf_lsa_install (area->ospf, NULL, new); /* Update LSA origination count. */ area->ospf->lsa_originate_count++; /* Flooding new LSA through area. */ ospf_flood_through_area (area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p", new->data->type, inet_ntoa (new->data->id), new); ospf_lsa_header_dump (new->data); } return new; } static struct ospf_lsa* ospf_summary_asbr_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) { struct ospf_lsa *new; struct summary_lsa *sl; struct prefix p; /* Sanity check. */ assert (lsa->data); sl = (struct summary_lsa *)lsa->data; p.prefixlen = ip_masklen (sl->mask); new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric), sl->header.id); if (!new) return NULL; new->data->ls_seqnum = lsa_seqnum_increment (lsa); ospf_lsa_install (ospf, NULL, new); /* Flood LSA through area. */ ospf_flood_through_area (new->area, NULL, new); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: summary-ASBR-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } /* AS-external-LSA related functions. */ /* Get nexthop for AS-external-LSAs. Return nexthop if its interface is connected, else 0*/ static struct in_addr ospf_external_lsa_nexthop_get (struct ospf *ospf, struct in_addr nexthop) { struct in_addr fwd; struct prefix nh; struct listnode *node; struct ospf_interface *oi; fwd.s_addr = 0; if (!nexthop.s_addr) return fwd; /* Check whether nexthop is covered by OSPF network. */ nh.family = AF_INET; nh.u.prefix4 = nexthop; nh.prefixlen = IPV4_MAX_BITLEN; /* XXX/SCALE: If there were a lot of oi's on an ifp, then it'd be * better to make use of the per-ifp table of ois. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (if_is_operative (oi->ifp)) if (oi->address->family == AF_INET) if (prefix_match (oi->address, &nh)) return nexthop; return fwd; } /* NSSA-external-LSA related functions. */ /* Get 1st IP connection for Forward Addr */ struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *oi) { struct in_addr fwd; fwd.s_addr = 0; if (if_is_operative (oi->ifp)) return oi->address->u.prefix4; return fwd; } /* Get 1st IP connection for Forward Addr */ struct in_addr ospf_get_nssa_ip (struct ospf_area *area) { struct in_addr fwd; struct in_addr best_default; struct listnode *node; struct ospf_interface *oi; fwd.s_addr = 0; best_default.s_addr = 0; for (ALL_LIST_ELEMENTS_RO (area->ospf->oiflist, node, oi)) { if (if_is_operative (oi->ifp)) if (oi->area->external_routing == OSPF_AREA_NSSA) if (oi->address && oi->address->family == AF_INET) { if (best_default.s_addr == 0) best_default = oi->address->u.prefix4; if (oi->area == area) return oi->address->u.prefix4; } } if (best_default.s_addr != 0) return best_default; if (best_default.s_addr != 0) return best_default; return fwd; } #define DEFAULT_DEFAULT_METRIC 20 #define DEFAULT_DEFAULT_ORIGINATE_METRIC 10 #define DEFAULT_DEFAULT_ALWAYS_METRIC 1 #define DEFAULT_METRIC_TYPE EXTERNAL_METRIC_TYPE_2 int metric_type (struct ospf *ospf, u_char src) { return (ospf->dmetric[src].type < 0 ? DEFAULT_METRIC_TYPE : ospf->dmetric[src].type); } int metric_value (struct ospf *ospf, u_char src) { if (ospf->dmetric[src].value < 0) { if (src == DEFAULT_ROUTE) { if (ospf->default_originate == DEFAULT_ORIGINATE_ZEBRA) return DEFAULT_DEFAULT_ORIGINATE_METRIC; else return DEFAULT_DEFAULT_ALWAYS_METRIC; } else if (ospf->default_metric < 0) return DEFAULT_DEFAULT_METRIC; else return ospf->default_metric; } return ospf->dmetric[src].value; } /* Set AS-external-LSA body. */ static void ospf_external_lsa_body_set (struct stream *s, struct external_info *ei, struct ospf *ospf) { struct prefix_ipv4 *p = &ei->p; struct in_addr mask, fwd_addr; u_int32_t mvalue; int mtype; int type; /* Put Network Mask. */ masklen2ip (p->prefixlen, &mask); stream_put_ipv4 (s, mask.s_addr); /* If prefix is default, specify DEFAULT_ROUTE. */ type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ? ROUTEMAP_METRIC_TYPE (ei) : metric_type (ospf, type); mvalue = (ROUTEMAP_METRIC (ei) != -1) ? ROUTEMAP_METRIC (ei) : metric_value (ospf, type); /* Put type of external metric. */ stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0)); /* Put 0 metric. TOS metric is not supported. */ stream_put_ospf_metric (s, mvalue); /* Get forwarding address to nexthop if on the Connection List, else 0. */ fwd_addr = ospf_external_lsa_nexthop_get (ospf, ei->nexthop); /* Put forwarding address. */ stream_put_ipv4 (s, fwd_addr.s_addr); /* Put route tag -- This value should be introduced from configuration. */ stream_putl (s, 0); } /* Create new external-LSA. */ static struct ospf_lsa * ospf_external_lsa_new (struct ospf *ospf, struct external_info *ei, struct in_addr *old_id) { struct stream *s; struct lsa_header *lsah; struct ospf_lsa *new; struct in_addr id; int length; if (ei == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type5]: External info is NULL, can't originate"); return NULL; } if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type5]: Originate AS-external-LSA instance"); /* If old Link State ID is specified, refresh LSA with same ID. */ if (old_id) id = *old_id; /* Get Link State with unique ID. */ else { id = ospf_lsa_unique_id (ospf, ospf->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p); if (id.s_addr == 0xffffffff) { /* Maybe Link State ID not available. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type5]: Link ID not available, can't originate"); return NULL; } } /* Create new stream for LSA. */ s = stream_new (OSPF_MAX_LSA_SIZE); lsah = (struct lsa_header *) STREAM_DATA (s); /* Set LSA common header fields. */ lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA, id, ospf->router_id); /* Set AS-external-LSA body fields. */ ospf_external_lsa_body_set (s, ei, ospf); /* Set length. */ length = stream_get_endp (s); lsah->length = htons (length); /* Now, create OSPF LSA instance. */ new = ospf_lsa_new (); new->area = NULL; SET_FLAG (new->flags, OSPF_LSA_SELF | OSPF_LSA_APPROVED | OSPF_LSA_SELF_CHECKED); /* Copy LSA data to store, discard stream. */ new->data = ospf_lsa_data_new (length); memcpy (new->data, lsah, length); stream_free (s); return new; } /* As Type-7 */ static void ospf_install_flood_nssa (struct ospf *ospf, struct ospf_lsa *lsa, struct external_info *ei) { struct ospf_lsa *new; struct as_external_lsa *extlsa; struct ospf_area *area; struct listnode *node, *nnode; /* LSA may be a Type-5 originated via translation of a Type-7 LSA * which originated from an NSSA area. In which case it should not be * flooded back to NSSA areas. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return; /* NSSA Originate or Refresh (If anyNSSA) LSA is self-originated. And just installed as Type-5. Additionally, install as Type-7 LSDB for every attached NSSA. P-Bit controls which ABR performs translation to outside world; If we are an ABR....do not set the P-bit, because we send the Type-5, not as the ABR Translator, but as the ASBR owner within the AS! If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set. The elected ABR Translator will see the P-bit, Translate, and re-flood. Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to Type-5's to non-NSSA Areas. (it will also attempt a re-install) */ for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { /* Don't install Type-7 LSA's into nonNSSA area */ if (area->external_routing != OSPF_AREA_NSSA) continue; /* make lsa duplicate, lock=1 */ new = ospf_lsa_dup (lsa); new->area = area; new->data->type = OSPF_AS_NSSA_LSA; /* set P-bit if not ABR */ if (! IS_OSPF_ABR (ospf)) { SET_FLAG(new->data->options, OSPF_OPTION_NP); /* set non-zero FWD ADDR draft-ietf-ospf-nssa-update-09.txt if the network between the NSSA AS boundary router and the adjacent AS is advertised into OSPF as an internal OSPF route, the forwarding address should be the next op address as is cu currently done with type-5 LSAs. If the intervening network is not adversited into OSPF as an internal OSPF route and the type-7 LSA's P-bit is set a forwarding address should be selected from one of the router's active OSPF inteface addresses which belong to the NSSA. If no such addresses exist, then no type-7 LSA's with the P-bit set should originate from this router. */ /* kevinm: not updating lsa anymore, just new */ extlsa = (struct as_external_lsa *)(new->data); if (extlsa->e[0].fwd_addr.s_addr == 0) extlsa->e[0].fwd_addr = ospf_get_nssa_ip(area); /* this NSSA area in ifp */ if (extlsa->e[0].fwd_addr.s_addr == 0) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("LSA[Type-7]: Could not build FWD-ADDR"); ospf_lsa_discard (new); return; } } /* install also as Type-7 */ ospf_lsa_install (ospf, NULL, new); /* Remove Old, Lock New = 2 */ /* will send each copy, lock=2+n */ ospf_flood_through_as (ospf, NULL, new); /* all attached NSSA's, no AS/STUBs */ } } static struct ospf_lsa * ospf_lsa_translated_nssa_new (struct ospf *ospf, struct ospf_lsa *type7) { struct ospf_lsa *new; struct as_external_lsa *ext, *extnew; struct external_info ei; ext = (struct as_external_lsa *)(type7->data); /* need external_info struct, fill in bare minimum */ ei.p.family = AF_INET; ei.p.prefix = type7->data->id; ei.p.prefixlen = ip_masklen (ext->mask); ei.type = ZEBRA_ROUTE_OSPF; ei.nexthop = ext->header.adv_router; ei.route_map_set.metric = -1; ei.route_map_set.metric_type = -1; ei.tag = 0; if ( (new = ospf_external_lsa_new (ospf, &ei, &type7->data->id)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_nssa_translate_originate(): Could not originate " "Translated Type-5 for %s", inet_ntoa (ei.p.prefix)); return NULL; } extnew = (struct as_external_lsa *)(new->data); /* copy over Type-7 data to new */ extnew->e[0].tos = ext->e[0].tos; extnew->e[0].route_tag = ext->e[0].route_tag; extnew->e[0].fwd_addr.s_addr = ext->e[0].fwd_addr.s_addr; new->data->ls_seqnum = type7->data->ls_seqnum; /* add translated flag, checksum and lock new lsa */ SET_FLAG (new->flags, OSPF_LSA_LOCAL_XLT); /* Translated from 7 */ new = ospf_lsa_lock (new); return new; } /* Originate Translated Type-5 for supplied Type-7 NSSA LSA */ struct ospf_lsa * ospf_translated_nssa_originate (struct ospf *ospf, struct ospf_lsa *type7) { struct ospf_lsa *new; struct as_external_lsa *extnew; /* we cant use ospf_external_lsa_originate() as we need to set * the OSPF_LSA_LOCAL_XLT flag, must originate by hand */ if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_originate(): Could not translate " "Type-7, Id %s, to Type-5", inet_ntoa (type7->data->id)); return NULL; } extnew = (struct as_external_lsa *)new; if (IS_DEBUG_OSPF_NSSA) { zlog_debug ("ospf_translated_nssa_originate(): " "translated Type 7, installed:"); ospf_lsa_header_dump (new->data); zlog_debug (" Network mask: %d",ip_masklen (extnew->mask)); zlog_debug (" Forward addr: %s", inet_ntoa (extnew->e[0].fwd_addr)); } if ( (new = ospf_lsa_install (ospf, NULL, new)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_lsa_translated_nssa_originate(): " "Could not install LSA " "id %s", inet_ntoa (type7->data->id)); return NULL; } ospf->lsa_originate_count++; ospf_flood_through_as (ospf, NULL, new); return new; } /* Refresh Translated from NSSA AS-external-LSA. */ struct ospf_lsa * ospf_translated_nssa_refresh (struct ospf *ospf, struct ospf_lsa *type7, struct ospf_lsa *type5) { struct ospf_lsa *new = NULL; /* Sanity checks. */ assert (type7 || type5); if (!(type7 || type5)) return NULL; if (type7) assert (type7->data); if (type5) assert (type5->data); assert (ospf->anyNSSA); /* get required data according to what has been given */ if (type7 && type5 == NULL) { /* find the translated Type-5 for this Type-7 */ struct as_external_lsa *ext = (struct as_external_lsa *)(type7->data); struct prefix_ipv4 p = { .prefix = type7->data->id, .prefixlen = ip_masklen (ext->mask), .family = AF_INET, }; type5 = ospf_external_info_find_lsa (ospf, &p); } else if (type5 && type7 == NULL) { /* find the type-7 from which supplied type-5 was translated, * ie find first type-7 with same LSA Id. */ struct listnode *ln, *lnn; struct route_node *rn; struct ospf_lsa *lsa; struct ospf_area *area; for (ALL_LIST_ELEMENTS (ospf->areas, ln, lnn, area)) { if (area->external_routing != OSPF_AREA_NSSA && !type7) continue; LSDB_LOOP (NSSA_LSDB(area), rn, lsa) { if (lsa->data->id.s_addr == type5->data->id.s_addr) { type7 = lsa; break; } } } } /* do we have type7? */ if (!type7) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): no Type-7 found for " "Type-5 LSA Id %s", inet_ntoa (type5->data->id)); return NULL; } /* do we have valid translated type5? */ if (type5 == NULL || !CHECK_FLAG (type5->flags, OSPF_LSA_LOCAL_XLT) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): No translated Type-5 " "found for Type-7 with Id %s", inet_ntoa (type7->data->id)); return NULL; } /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as (ospf, type5); /* create new translated LSA */ if ( (new = ospf_lsa_translated_nssa_new (ospf, type7)) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not translate " "Type-7 for %s to Type-5", inet_ntoa (type7->data->id)); return NULL; } if ( !(new = ospf_lsa_install (ospf, NULL, new)) ) { if (IS_DEBUG_OSPF_NSSA) zlog_debug ("ospf_translated_nssa_refresh(): Could not install " "translated LSA, Id %s", inet_ntoa (type7->data->id)); return NULL; } /* Flood LSA through area. */ ospf_flood_through_as (ospf, NULL, new); return new; } int is_prefix_default (struct prefix_ipv4 *p) { struct prefix_ipv4 q; q.family = AF_INET; q.prefix.s_addr = 0; q.prefixlen = 0; return prefix_same ((struct prefix *) p, (struct prefix *) &q); } /* Originate an AS-external-LSA, install and flood. */ struct ospf_lsa * ospf_external_lsa_originate (struct ospf *ospf, struct external_info *ei) { struct ospf_lsa *new; /* Added for NSSA project.... External LSAs are originated in ASBRs as usual, but for NSSA systems. there is the global Type-5 LSDB and a Type-7 LSDB installed for every area. The Type-7's are flooded to every IR and every ABR; We install the Type-5 LSDB so that the normal "refresh" code operates as usual, and flag them as not used during ASE calculations. The Type-7 LSDB is used for calculations. Each Type-7 has a Forwarding Address of non-zero. If an ABR is the elected NSSA translator, following SPF and during the ABR task it will translate all the scanned Type-7's, with P-bit ON and not-self generated, and translate to Type-5's throughout the non-NSSA/STUB AS. A difference in operation depends whether this ASBR is an ABR or not. If not an ABR, the P-bit is ON, to indicate that any elected NSSA-ABR can perform its translation. If an ABR, the P-bit is OFF; No ABR will perform translation and this ASBR will flood the Type-5 LSA as usual. For the case where this ASBR is not an ABR, the ASE calculations are based on the Type-5 LSDB; The Type-7 LSDB exists just to demonstrate to the user that there are LSA's that belong to any attached NSSA. Finally, it just so happens that when the ABR is translating every Type-7 into Type-5, it installs it into the Type-5 LSDB as an approved Type-5 (translated from Type-7); at the end of translation if any Translated Type-5's remain unapproved, then they must be flushed from the AS. */ /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check (ospf, ei, NULL)) return NULL; /* Create new AS-external-LSA instance. */ if ((new = ospf_external_lsa_new (ospf, ei, NULL)) == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type5:%s]: Could not originate AS-external-LSA", inet_ntoa (ei->p.prefix)); return NULL; } /* Install newly created LSA into Type-5 LSDB, lock = 1. */ ospf_lsa_install (ospf, NULL, new); /* Update LSA origination count. */ ospf->lsa_originate_count++; /* Flooding new LSA. only to AS (non-NSSA/STUB) */ ospf_flood_through_as (ospf, NULL, new); /* If there is any attached NSSA, do special handling */ if (ospf->anyNSSA && /* stay away from translated LSAs! */ !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood Type-7 to all NSSAs */ /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: Originate AS-external-LSA %p", new->data->type, inet_ntoa (new->data->id), new); ospf_lsa_header_dump (new->data); } return new; } /* Originate AS-external-LSA from external info with initial flag. */ int ospf_external_lsa_originate_timer (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct route_node *rn; struct external_info *ei; struct route_table *rt; int type = THREAD_VAL (thread); ospf->t_external_lsa = NULL; /* Originate As-external-LSA from all type of distribute source. */ if ((rt = EXTERNAL_INFO (type))) for (rn = route_top (rt); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p)) if (!ospf_external_lsa_originate (ospf, ei)) zlog_warn ("LSA: AS-external-LSA was not originated."); return 0; } static struct external_info * ospf_default_external_info (struct ospf *ospf) { int type; struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefix.s_addr = 0; p.prefixlen = 0; /* First, lookup redistributed default route. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) if (EXTERNAL_INFO (type) && type != ZEBRA_ROUTE_OSPF) { rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p); if (rn != NULL) { route_unlock_node (rn); assert (rn->info); if (ospf_redistribute_check (ospf, rn->info, NULL)) return rn->info; } } return NULL; } int ospf_default_originate_timer (struct thread *thread) { struct prefix_ipv4 p; struct in_addr nexthop; struct external_info *ei; struct ospf *ospf; ospf = THREAD_ARG (thread); p.family = AF_INET; p.prefix.s_addr = 0; p.prefixlen = 0; if (ospf->default_originate == DEFAULT_ORIGINATE_ALWAYS) { /* If there is no default route via redistribute, then originate AS-external-LSA with nexthop 0 (self). */ nexthop.s_addr = 0; ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop); } if ((ei = ospf_default_external_info (ospf))) ospf_external_lsa_originate (ospf, ei); return 0; } /* Flush any NSSA LSAs for given prefix */ void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p) { struct listnode *node, *nnode; struct ospf_lsa *lsa; struct ospf_area *area; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if (area->external_routing == OSPF_AREA_NSSA) { if (!(lsa = ospf_lsa_lookup (area, OSPF_AS_NSSA_LSA, p->prefix, ospf->router_id))) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA: There is no such AS-NSSA-LSA %s/%d in LSDB", inet_ntoa (p->prefix), p->prefixlen); continue; } ospf_ls_retransmit_delete_nbr_area (area, lsa); if (!IS_LSA_MAXAGE (lsa)) { ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush_area (lsa, area); } } } } /* Flush an AS-external-LSA from LSDB and routing domain. */ void ospf_external_lsa_flush (struct ospf *ospf, u_char type, struct prefix_ipv4 *p, unsigned int ifindex /*, struct in_addr nexthop */) { struct ospf_lsa *lsa; if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA: Flushing AS-external-LSA %s/%d", inet_ntoa (p->prefix), p->prefixlen); /* First lookup LSA from LSDB. */ if (!(lsa = ospf_external_info_find_lsa (ospf, p))) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA: There is no such AS-external-LSA %s/%d in LSDB", inet_ntoa (p->prefix), p->prefixlen); return; } /* If LSA is selforiginated, not a translated LSA, and there is * NSSA area, flush Type-7 LSA's at first. */ if (IS_LSA_SELF(lsa) && (ospf->anyNSSA) && !(CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))) ospf_nssa_lsa_flush (ospf, p); /* Sweep LSA from Link State Retransmit List. */ ospf_ls_retransmit_delete_nbr_as (ospf, lsa); /* There must be no self-originated LSA in rtrs_external. */ #if 0 /* Remove External route from Zebra. */ ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop); #endif if (!IS_LSA_MAXAGE (lsa)) { /* Unregister LSA from Refresh queue. */ ospf_refresher_unregister_lsa (ospf, lsa); /* Flush AS-external-LSA through AS. */ ospf_lsa_flush_as (ospf, lsa); } if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("ospf_external_lsa_flush(): stop"); } void ospf_external_lsa_refresh_default (struct ospf *ospf) { struct prefix_ipv4 p; struct external_info *ei; struct ospf_lsa *lsa; p.family = AF_INET; p.prefixlen = 0; p.prefix.s_addr = 0; ei = ospf_default_external_info (ospf); lsa = ospf_external_info_find_lsa (ospf, &p); if (ei) { if (lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa); ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); } else { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); ospf_external_lsa_originate (ospf, ei); } } else { if (lsa) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA"); ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush_as (ospf, lsa); } } } void ospf_external_lsa_refresh_type (struct ospf *ospf, u_char type, int force) { struct route_node *rn; struct external_info *ei; if (type != DEFAULT_ROUTE) if (EXTERNAL_INFO(type)) /* Refresh each redistributed AS-external-LSAs. */ for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn)) if ((ei = rn->info)) if (!is_prefix_default (&ei->p)) { struct ospf_lsa *lsa; if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p))) ospf_external_lsa_refresh (ospf, lsa, ei, force); else ospf_external_lsa_originate (ospf, ei); } } /* Refresh AS-external-LSA. */ struct ospf_lsa * ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa, struct external_info *ei, int force) { struct ospf_lsa *new; int changed; /* Check the AS-external-LSA should be originated. */ if (!ospf_redistribute_check (ospf, ei, &changed)) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Could not be refreshed, " "redist check fail", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_external_lsa_flush (ospf, ei->type, &ei->p, ei->ifindex /*, ei->nexthop */); return NULL; } if (!changed && !force) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Not refreshed, not changed/forced", lsa->data->type, inet_ntoa (lsa->data->id)); return NULL; } /* Delete LSA from neighbor retransmit-list. */ ospf_ls_retransmit_delete_nbr_as (ospf, lsa); /* Unregister AS-external-LSA from refresh-list. */ ospf_refresher_unregister_lsa (ospf, lsa); new = ospf_external_lsa_new (ospf, ei, &lsa->data->id); if (new == NULL) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type, inet_ntoa (lsa->data->id)); return NULL; } new->data->ls_seqnum = lsa_seqnum_increment (lsa); ospf_lsa_install (ospf, NULL, new); /* As type-5. */ /* Flood LSA through AS. */ ospf_flood_through_as (ospf, NULL, new); /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */ if (ospf->anyNSSA && !(CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT))) ospf_install_flood_nssa (ospf, new, ei); /* Install/Flood per new rules */ /* Register self-originated LSA to refresh queue. * Translated LSAs should not be registered, but refreshed upon * refresh of the Type-7 */ if ( !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT) ) ospf_refresher_register_lsa (ospf, new); /* Debug logging. */ if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("LSA[Type%d:%s]: AS-external-LSA refresh", new->data->type, inet_ntoa (new->data->id)); ospf_lsa_header_dump (new->data); } return new; } /* LSA installation functions. */ /* Install router-LSA to an area. */ static struct ospf_lsa * ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) { struct ospf_area *area = new->area; /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs The entire routing table must be recalculated, starting with the shortest path calculations for each area (not just the area whose link-state database has changed). */ if (IS_LSA_SELF (new)) { /* Only install LSA if it is originated/refreshed by us. * If LSA was received by flooding, the RECEIVED flag is set so do * not link the LSA */ if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) return new; /* ignore stale LSA */ /* Set self-originated router-LSA. */ ospf_lsa_unlock (&area->router_lsa_self); area->router_lsa_self = ospf_lsa_lock (new); ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) ospf_spf_calculate_schedule (ospf, SPF_FLAG_ROUTER_LSA_INSTALL); return new; } #define OSPF_INTERFACE_TIMER_ON(T,F,V) \ if (!(T)) \ (T) = thread_add_timer (master, (F), oi, (V)) /* Install network-LSA to an area. */ static struct ospf_lsa * ospf_network_lsa_install (struct ospf *ospf, struct ospf_interface *oi, struct ospf_lsa *new, int rt_recalc) { /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs The entire routing table must be recalculated, starting with the shortest path calculations for each area (not just the area whose link-state database has changed). */ if (IS_LSA_SELF (new)) { /* We supposed that when LSA is originated by us, we pass the int for which it was originated. If LSA was received by flooding, the RECEIVED flag is set, so we do not link the LSA to the int. */ if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED)) return new; /* ignore stale LSA */ ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = ospf_lsa_lock (new); ospf_refresher_register_lsa (ospf, new); } if (rt_recalc) ospf_spf_calculate_schedule (ospf, SPF_FLAG_NETWORK_LSA_INSTALL); return new; } /* Install summary-LSA to an area. */ static struct ospf_lsa * ospf_summary_lsa_install (struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) { if (rt_recalc && !IS_LSA_SELF (new)) { /* RFC 2328 Section 13.2 Summary-LSAs The best route to the destination described by the summary- LSA must be recalculated (see Section 16.5). If this destination is an AS boundary router, it may also be necessary to re-examine all the AS-external-LSAs. */ #if 0 /* This doesn't exist yet... */ ospf_summary_incremental_update(new); */ #else /* #if 0 */ ospf_spf_calculate_schedule (ospf, SPF_FLAG_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new); return new; } /* Install ASBR-summary-LSA to an area. */ static struct ospf_lsa * ospf_summary_asbr_lsa_install (struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) { if (rt_recalc && !IS_LSA_SELF (new)) { /* RFC 2328 Section 13.2 Summary-LSAs The best route to the destination described by the summary- LSA must be recalculated (see Section 16.5). If this destination is an AS boundary router, it may also be necessary to re-examine all the AS-external-LSAs. */ #if 0 /* These don't exist yet... */ ospf_summary_incremental_update(new); /* Isn't this done by the above call? - RFC 2328 Section 16.5 implies it should be */ /* ospf_ase_calculate_schedule(); */ #else /* #if 0 */ ospf_spf_calculate_schedule (ospf, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL); #endif /* #if 0 */ } /* register LSA to refresh-list. */ if (IS_LSA_SELF (new)) ospf_refresher_register_lsa (ospf, new); return new; } /* Install AS-external-LSA. */ static struct ospf_lsa * ospf_external_lsa_install (struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) { ospf_ase_register_external_lsa (new, ospf); /* If LSA is not self-originated, calculate an external route. */ if (rt_recalc) { /* RFC 2328 Section 13.2 AS-external-LSAs The best route to the destination described by the AS- external-LSA must be recalculated (see Section 16.6). */ if (!IS_LSA_SELF (new)) ospf_ase_incremental_update (ospf, new); } if (new->data->type == OSPF_AS_NSSA_LSA) { /* There is no point to register selforiginate Type-7 LSA for * refreshing. We rely on refreshing Type-5 LSA's */ if (IS_LSA_SELF (new)) return new; else { /* Try refresh type-5 translated LSA for this LSA, if one exists. * New translations will be taken care of by the abr_task. */ ospf_translated_nssa_refresh (ospf, new, NULL); } } /* Register self-originated LSA to refresh queue. * Leave Translated LSAs alone if NSSA is enabled */ if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_LOCAL_XLT ) ) ospf_refresher_register_lsa (ospf, new); return new; } void ospf_discard_from_db (struct ospf *ospf, struct ospf_lsdb *lsdb, struct ospf_lsa *lsa) { struct ospf_lsa *old; if (!lsdb) { zlog_warn ("%s: Called with NULL lsdb!", __func__); if (!lsa) zlog_warn ("%s: and NULL LSA!", __func__); else zlog_warn ("LSA[Type%d:%s]: not associated with LSDB!", lsa->data->type, inet_ntoa (lsa->data->id)); return; } old = ospf_lsdb_lookup (lsdb, lsa); if (!old) return; if (old->refresh_list >= 0) ospf_refresher_unregister_lsa (ospf, old); switch (old->data->type) { case OSPF_AS_EXTERNAL_LSA: ospf_ase_unregister_external_lsa (old, ospf); ospf_ls_retransmit_delete_nbr_as (ospf, old); break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: ospf_ls_retransmit_delete_nbr_as (ospf, old); break; #endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: ospf_ls_retransmit_delete_nbr_area (old->area, old); ospf_ase_unregister_external_lsa (old, ospf); break; default: ospf_ls_retransmit_delete_nbr_area (old->area, old); break; } ospf_lsa_maxage_delete (ospf, old); ospf_lsa_discard (old); } struct ospf_lsa * ospf_lsa_install (struct ospf *ospf, struct ospf_interface *oi, struct ospf_lsa *lsa) { struct ospf_lsa *new = NULL; struct ospf_lsa *old = NULL; struct ospf_lsdb *lsdb = NULL; int rt_recalc; /* Set LSDB. */ switch (lsa->data->type) { /* kevinm */ case OSPF_AS_NSSA_LSA: if (lsa->area) lsdb = lsa->area->lsdb; else lsdb = ospf->lsdb; break; case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsdb = ospf->lsdb; break; default: lsdb = lsa->area->lsdb; break; } assert (lsdb); /* RFC 2328 13.2. Installing LSAs in the database Installing a new LSA in the database, either as the result of flooding or a newly self-originated LSA, may cause the OSPF routing table structure to be recalculated. The contents of the new LSA should be compared to the old instance, if present. If there is no difference, there is no need to recalculate the routing table. When comparing an LSA to its previous instance, the following are all considered to be differences in contents: o The LSA's Options field has changed. o One of the LSA instances has LS age set to MaxAge, and the other does not. o The length field in the LSA header has changed. o The body of the LSA (i.e., anything outside the 20-byte LSA header) has changed. Note that this excludes changes in LS Sequence Number and LS Checksum. */ /* Look up old LSA and determine if any SPF calculation or incremental update is needed */ old = ospf_lsdb_lookup (lsdb, lsa); /* Do comparision and record if recalc needed. */ rt_recalc = 0; if ( old == NULL || ospf_lsa_different(old, lsa)) rt_recalc = 1; /* Sequence number check (Section 14.1 of rfc 2328) "Premature aging is used when it is time for a self-originated LSA's sequence number field to wrap. At this point, the current LSA instance (having LS sequence number MaxSequenceNumber) must be prematurely aged and flushed from the routing domain before a new instance with sequence number equal to InitialSequenceNumber can be originated. " */ if (ntohl(lsa->data->ls_seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) { if (ospf_lsa_is_self_originated(ospf, lsa)) { lsa->data->ls_seqnum = htonl(OSPF_MAX_SEQUENCE_NUMBER); if (!IS_LSA_MAXAGE(lsa)) lsa->flags |= OSPF_LSA_PREMATURE_AGE; lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) { zlog_debug ("ospf_lsa_install() Premature Aging " "lsa 0x%p, seqnum 0x%x", lsa, ntohl(lsa->data->ls_seqnum)); ospf_lsa_header_dump (lsa->data); } } else { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) { zlog_debug ("ospf_lsa_install() got an lsa with seq 0x80000000 " "that was not self originated. Ignoring\n"); ospf_lsa_header_dump (lsa->data); } return old; } } /* discard old LSA from LSDB */ if (old != NULL) ospf_discard_from_db (ospf, lsdb, lsa); /* Calculate Checksum if self-originated?. */ if (IS_LSA_SELF (lsa)) ospf_lsa_checksum (lsa->data); /* Insert LSA to LSDB. */ ospf_lsdb_add (lsdb, lsa); lsa->lsdb = lsdb; /* Do LSA specific installation process. */ switch (lsa->data->type) { case OSPF_ROUTER_LSA: new = ospf_router_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_NETWORK_LSA: assert (oi); new = ospf_network_lsa_install (ospf, oi, lsa, rt_recalc); break; case OSPF_SUMMARY_LSA: new = ospf_summary_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_ASBR_SUMMARY_LSA: new = ospf_summary_asbr_lsa_install (ospf, lsa, rt_recalc); break; case OSPF_AS_EXTERNAL_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: if (IS_LSA_SELF (lsa)) lsa->oi = oi; /* Specify outgoing ospf-interface for this LSA. */ else { /* Incoming "oi" for this LSA has set at LSUpd reception. */ } /* Fallthrough */ case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_install (lsa, rt_recalc); break; #endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: new = ospf_external_lsa_install (ospf, lsa, rt_recalc); default: /* type-6,8,9....nothing special */ break; } if (new == NULL) return new; /* Installation failed, cannot proceed further -- endo. */ /* Debug logs. */ if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) { char area_str[INET_ADDRSTRLEN]; switch (lsa->data->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_NSSA_LSA: zlog_debug ("LSA[%s]: Install %s", dump_lsa_key (new), LOOKUP (ospf_lsa_type_msg, new->data->type)); break; default: strcpy (area_str, inet_ntoa (new->area->area_id)); zlog_debug ("LSA[%s]: Install %s to Area %s", dump_lsa_key (new), LOOKUP (ospf_lsa_type_msg, new->data->type), area_str); break; } } /* If received LSA' ls_age is MaxAge, or lsa is being prematurely aged (it's getting flushed out of the area), set LSA on MaxAge LSA list. */ if (IS_LSA_MAXAGE (new)) { if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) zlog_debug ("LSA[Type%d:%s]: Install LSA 0x%p, MaxAge", new->data->type, inet_ntoa (new->data->id), lsa); ospf_lsa_maxage (ospf, lsa); } return new; } int ospf_check_nbr_status (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { struct route_node *rn; struct ospf_neighbor *nbr; if (ospf_if_is_enable (oi)) for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading) { route_unlock_node (rn); return 0; } } return 1; } static int ospf_maxage_lsa_remover (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct ospf_lsa *lsa; struct route_node *rn; int reschedule = 0; ospf->t_maxage = NULL; if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[MaxAge]: remover Start"); reschedule = !ospf_check_nbr_status (ospf); if (!reschedule) for (rn = route_top(ospf->maxage_lsa); rn; rn = route_next(rn)) { if ((lsa = rn->info) == NULL) { continue; } /* There is at least one neighbor from which we still await an ack * for that LSA, so we are not allowed to remove it from our lsdb yet * as per RFC 2328 section 14 para 4 a) */ if (lsa->retransmit_counter > 0) { reschedule = 1; continue; } /* TODO: maybe convert this function to a work-queue */ if (thread_should_yield (thread)) { OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0); route_unlock_node(rn); /* route_top/route_next */ return 0; } /* Remove LSA from the LSDB */ if (IS_LSA_SELF (lsa)) if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: LSA 0x%lx is self-originated: ", lsa->data->type, inet_ntoa (lsa->data->id), (u_long)lsa); if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: MaxAge LSA removed from list", lsa->data->type, inet_ntoa (lsa->data->id)); if (CHECK_FLAG (lsa->flags, OSPF_LSA_PREMATURE_AGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("originating new lsa for lsa 0x%p\n", lsa); ospf_lsa_refresh (ospf, lsa); } /* Remove from lsdb. */ if (lsa->lsdb) { ospf_discard_from_db (ospf, lsa->lsdb, lsa); ospf_lsdb_delete (lsa->lsdb, lsa); } else zlog_warn ("%s: LSA[Type%d:%s]: No associated LSDB!", __func__, lsa->data->type, inet_ntoa (lsa->data->id)); } /* A MaxAge LSA must be removed immediately from the router's link state database as soon as both a) it is no longer contained on any neighbor Link state retransmission lists and b) none of the router's neighbors are in states Exchange or Loading. */ if (reschedule) OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, ospf->maxage_delay); return 0; } void ospf_lsa_maxage_delete (struct ospf *ospf, struct ospf_lsa *lsa) { struct route_node *rn; struct prefix_ptr lsa_prefix; lsa_prefix.family = 0; lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; lsa_prefix.prefix = (uintptr_t) lsa; if ((rn = route_node_lookup(ospf->maxage_lsa, (struct prefix *)&lsa_prefix))) { if (rn->info == lsa) { UNSET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); ospf_lsa_unlock (&lsa); /* maxage_lsa */ rn->info = NULL; route_unlock_node (rn); /* unlock node because lsa is deleted */ } route_unlock_node (rn); /* route_node_lookup */ } } /* Add LSA onto the MaxAge list, and schedule for removal. * This does *not* lead to the LSA being flooded, that must be taken * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this * function). */ void ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa) { struct prefix_ptr lsa_prefix; struct route_node *rn; /* When we saw a MaxAge LSA flooded to us, we put it on the list and schedule the MaxAge LSA remover. */ if (CHECK_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list", lsa->data->type, inet_ntoa (lsa->data->id), lsa); return; } lsa_prefix.family = 0; lsa_prefix.prefixlen = sizeof(lsa_prefix.prefix) * CHAR_BIT; lsa_prefix.prefix = (uintptr_t) lsa; if ((rn = route_node_get (ospf->maxage_lsa, (struct prefix *)&lsa_prefix)) != NULL) { if (rn->info != NULL) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: found LSA (%p) in table for LSA %p %d", dump_lsa_key (lsa), rn->info, lsa, lsa_prefix.prefixlen); route_unlock_node (rn); } else { rn->info = ospf_lsa_lock(lsa); SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE); } } else { zlog_err("Unable to allocate memory for maxage lsa\n"); assert(0); } if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa)); OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, ospf->maxage_delay); } static int ospf_lsa_maxage_walker_remover (struct ospf *ospf, struct ospf_lsa *lsa) { /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return 0; if (IS_LSA_MAXAGE (lsa)) /* Self-originated LSAs should NOT time-out instead, they're flushed and submitted to the max_age list explicitly. */ if (!ospf_lsa_is_self_originated (ospf, lsa)) { if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) zlog_debug("LSA[%s]: is MaxAge", dump_lsa_key (lsa)); switch (lsa->data->type) { #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* * As a general rule, whenever network topology has changed * (due to an LSA removal in this case), routing recalculation * should be triggered. However, this is not true for opaque * LSAs. Even if an opaque LSA instance is going to be removed * from the routing domain, it does not mean a change in network * topology, and thus, routing recalculation is not needed here. */ break; #endif /* HAVE_OPAQUE_LSA */ case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: ospf_ase_incremental_update (ospf, lsa); break; default: ospf_spf_calculate_schedule (ospf, SPF_FLAG_MAXAGE); break; } ospf_lsa_maxage (ospf, lsa); } if (IS_LSA_MAXAGE (lsa) && !ospf_lsa_is_self_originated (ospf, lsa)) if (LS_AGE (lsa) > OSPF_LSA_MAXAGE + 30) printf ("Eek! Shouldn't happen!\n"); return 0; } /* Periodical check of MaxAge LSA. */ int ospf_lsa_maxage_walker (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct route_node *rn; struct ospf_lsa *lsa; struct ospf_area *area; struct listnode *node, *nnode; ospf->t_maxage_walker = NULL; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); } /* for AS-external-LSAs. */ if (ospf->lsdb) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_maxage_walker_remover (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } OSPF_TIMER_ON (ospf->t_maxage_walker, ospf_lsa_maxage_walker, OSPF_LSA_MAXAGE_CHECK_INTERVAL); return 0; } struct ospf_lsa * ospf_lsa_lookup_by_prefix (struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p, struct in_addr router_id) { struct ospf_lsa *lsa; struct in_addr mask, id; struct lsa_header_mask { struct lsa_header header; struct in_addr mask; } *hmask; lsa = ospf_lsdb_lookup_by_id (lsdb, type, p->prefix, router_id); if (lsa == NULL) return NULL; masklen2ip (p->prefixlen, &mask); hmask = (struct lsa_header_mask *) lsa->data; if (mask.s_addr != hmask->mask.s_addr) { id.s_addr = p->prefix.s_addr | (~mask.s_addr); lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, router_id); if (!lsa) return NULL; } return lsa; } struct ospf_lsa * ospf_lsa_lookup (struct ospf_area *area, u_int32_t type, struct in_addr id, struct in_addr adv_router) { struct ospf *ospf = ospf_lookup(); assert(ospf); switch (type) { case OSPF_ROUTER_LSA: case OSPF_NETWORK_LSA: case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: case OSPF_AS_NSSA_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: #endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router); case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ return ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, adv_router); default: break; } return NULL; } struct ospf_lsa * ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, struct in_addr id) { struct ospf_lsa *lsa; struct route_node *rn; switch (type) { case OSPF_ROUTER_LSA: return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_NETWORK_LSA: for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn)) if ((lsa = rn->info)) if (IPV4_ADDR_SAME (&lsa->data->id, &id)) { route_unlock_node (rn); return lsa; } break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* Currently not used. */ assert (1); return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id); case OSPF_AS_EXTERNAL_LSA: case OSPF_AS_NSSA_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* Currently not used. */ break; #endif /* HAVE_OPAQUE_LSA */ default: break; } return NULL; } struct ospf_lsa * ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah) { struct ospf_lsa *match; #ifdef HAVE_OPAQUE_LSA /* * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11) * is redefined to have two subfields; opaque-type and opaque-id. * However, it is harmless to treat the two sub fields together, as if * they two were forming a unique LSA-ID. */ #endif /* HAVE_OPAQUE_LSA */ match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router); if (match == NULL) if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) zlog_debug ("LSA[Type%d:%s]: Lookup by header, NO MATCH", lsah->type, inet_ntoa (lsah->id)); return match; } /* return +n, l1 is more recent. return -n, l2 is more recent. return 0, l1 and l2 is identical. */ int ospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2) { int r; int x, y; if (l1 == NULL && l2 == NULL) return 0; if (l1 == NULL) return -1; if (l2 == NULL) return 1; /* compare LS sequence number. */ x = (int) ntohl (l1->data->ls_seqnum); y = (int) ntohl (l2->data->ls_seqnum); if (x > y) return 1; if (x < y) return -1; /* compare LS checksum. */ r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum); if (r) return r; /* compare LS age. */ if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) return 1; else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2)) return -1; /* compare LS age with MaxAgeDiff. */ if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF) return -1; else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF) return 1; /* LSAs are identical. */ return 0; } /* If two LSAs are different, return 1, otherwise return 0. */ int ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2) { char *p1, *p2; assert (l1); assert (l2); assert (l1->data); assert (l2->data); if (l1->data->options != l2->data->options) return 1; if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2)) return 1; if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1)) return 1; if (l1->data->length != l2->data->length) return 1; if (l1->data->length == 0) return 1; if (CHECK_FLAG ((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) return 1; /* May be a stale LSA in the LSBD */ assert ( ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE); p1 = (char *) l1->data; p2 = (char *) l2->data; if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, ntohs( l1->data->length ) - OSPF_LSA_HEADER_SIZE) != 0) return 1; return 0; } #ifdef ORIGINAL_CODING void ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr, struct ospf_lsa *self, struct ospf_lsa *new) { u_int32_t seqnum; /* Adjust LS Sequence Number. */ seqnum = ntohl (new->data->ls_seqnum) + 1; self->data->ls_seqnum = htonl (seqnum); /* Recalculate LSA checksum. */ ospf_lsa_checksum (self->data); /* Reflooding LSA. */ /* RFC2328 Section 13.3 On non-broadcast networks, separate Link State Update packets must be sent, as unicasts, to each adjacent neighbor (i.e., those in state Exchange or greater). The destination IP addresses for these packets are the neighbors' IP addresses. */ if (nbr->oi->type == OSPF_IFTYPE_NBMA) { struct route_node *rn; struct ospf_neighbor *onbr; for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn)) if ((onbr = rn->info) != NULL) if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange) ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT); } else ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT); if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("LSA[Type%d:%s]: Flush self-originated LSA", self->data->type, inet_ntoa (self->data->id)); } #else /* ORIGINAL_CODING */ static int ospf_lsa_flush_schedule (struct ospf *ospf, struct ospf_lsa *lsa) { if (lsa == NULL || !IS_LSA_SELF (lsa)) return 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); /* Force given lsa's age to MaxAge. */ lsa->data->ls_age = htons (OSPF_LSA_MAXAGE); switch (lsa->data->type) { #ifdef HAVE_OPAQUE_LSA /* Opaque wants to be notified of flushes */ case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_refresh (lsa); break; #endif /* HAVE_OPAQUE_LSA */ default: ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush (ospf, lsa); break; } return 0; } void ospf_flush_self_originated_lsas_now (struct ospf *ospf) { struct listnode *node, *nnode; struct listnode *node2, *nnode2; struct ospf_area *area; struct ospf_interface *oi; struct ospf_lsa *lsa; struct route_node *rn; int need_to_flush_ase = 0; for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { if ((lsa = area->router_lsa_self) != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_refresher_unregister_lsa (ospf, lsa); ospf_lsa_flush_area (lsa, area); ospf_lsa_unlock (&area->router_lsa_self); area->router_lsa_self = NULL; } for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi)) { if ((lsa = oi->network_lsa_self) != NULL && oi->state == ISM_DR && oi->full_nbrs > 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id)); ospf_refresher_unregister_lsa (ospf, oi->network_lsa_self); ospf_lsa_flush_area (oi->network_lsa_self, area); ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = NULL; } if (oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT) need_to_flush_ase = 1; } LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } if (need_to_flush_ase) { LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_lsa_flush_schedule (ospf, lsa); #endif /* HAVE_OPAQUE_LSA */ } /* * Make sure that the MaxAge LSA remover is executed immediately, * without conflicting to other threads. */ if (ospf->t_maxage != NULL) { OSPF_TIMER_OFF (ospf->t_maxage); thread_execute (master, ospf_maxage_lsa_remover, ospf, 0); } return; } #endif /* ORIGINAL_CODING */ /* If there is self-originated LSA, then return 1, otherwise return 0. */ /* An interface-independent version of ospf_lsa_is_self_originated */ int ospf_lsa_is_self_originated (struct ospf *ospf, struct ospf_lsa *lsa) { struct listnode *node; struct ospf_interface *oi; /* This LSA is already checked. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED)) return IS_LSA_SELF (lsa); /* Make sure LSA is self-checked. */ SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED); /* AdvRouter and Router ID is the same. */ if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf->router_id)) SET_FLAG (lsa->flags, OSPF_LSA_SELF); /* LSA is router-LSA. */ else if (lsa->data->type == OSPF_ROUTER_LSA && IPV4_ADDR_SAME (&lsa->data->id, &ospf->router_id)) SET_FLAG (lsa->flags, OSPF_LSA_SELF); /* LSA is network-LSA. Compare Link ID with all interfaces. */ else if (lsa->data->type == OSPF_NETWORK_LSA) for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { /* Ignore virtual link. */ if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (oi->address->family == AF_INET) if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4)) { /* to make it easier later */ SET_FLAG (lsa->flags, OSPF_LSA_SELF); return IS_LSA_SELF (lsa); } } return IS_LSA_SELF (lsa); } /* Get unique Link State ID. */ struct in_addr ospf_lsa_unique_id (struct ospf *ospf, struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p) { struct ospf_lsa *lsa; struct in_addr mask, id; id = p->prefix; /* Check existence of LSA instance. */ lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf->router_id); if (lsa) { struct as_external_lsa *al = (struct as_external_lsa *) lsa->data; if (ip_masklen (al->mask) == p->prefixlen) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("ospf_lsa_unique_id(): " "Can't get Link State ID for %s/%d", inet_ntoa (p->prefix), p->prefixlen); /* id.s_addr = 0; */ id.s_addr = 0xffffffff; return id; } /* Masklen differs, then apply wildcard mask to Link State ID. */ else { masklen2ip (p->prefixlen, &mask); id.s_addr = p->prefix.s_addr | (~mask.s_addr); lsa = ospf_lsdb_lookup_by_id (ospf->lsdb, type, id, ospf->router_id); if (lsa) { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) zlog_debug ("ospf_lsa_unique_id(): " "Can't get Link State ID for %s/%d", inet_ntoa (p->prefix), p->prefixlen); /* id.s_addr = 0; */ id.s_addr = 0xffffffff; return id; } } } return id; } #define LSA_ACTION_FLOOD_AREA 1 #define LSA_ACTION_FLUSH_AREA 2 struct lsa_action { u_char action; struct ospf_area *area; struct ospf_lsa *lsa; }; static int ospf_lsa_action (struct thread *t) { struct lsa_action *data; data = THREAD_ARG (t); if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) zlog_debug ("LSA[Action]: Performing scheduled LSA action: %d", data->action); switch (data->action) { case LSA_ACTION_FLOOD_AREA: ospf_flood_through_area (data->area, NULL, data->lsa); break; case LSA_ACTION_FLUSH_AREA: ospf_lsa_flush_area (data->lsa, data->area); break; } ospf_lsa_unlock (&data->lsa); /* Message */ XFREE (MTYPE_OSPF_MESSAGE, data); return 0; } void ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa) { struct lsa_action *data; data = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); data->action = LSA_ACTION_FLOOD_AREA; data->area = area; data->lsa = ospf_lsa_lock (lsa); /* Message / Flood area */ thread_add_event (master, ospf_lsa_action, data, 0); } void ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa) { struct lsa_action *data; data = XCALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action)); data->action = LSA_ACTION_FLUSH_AREA; data->area = area; data->lsa = ospf_lsa_lock (lsa); /* Message / Flush area */ thread_add_event (master, ospf_lsa_action, data, 0); } /* LSA Refreshment functions. */ struct ospf_lsa * ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa) { struct external_info *ei; struct ospf_lsa *new = NULL; assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF)); assert (IS_LSA_SELF (lsa)); assert (lsa->lock > 0); switch (lsa->data->type) { /* Router and Network LSAs are processed differently. */ case OSPF_ROUTER_LSA: new = ospf_router_lsa_refresh (lsa); break; case OSPF_NETWORK_LSA: new = ospf_network_lsa_refresh (lsa); break; case OSPF_SUMMARY_LSA: new = ospf_summary_lsa_refresh (ospf, lsa); break; case OSPF_ASBR_SUMMARY_LSA: new = ospf_summary_asbr_lsa_refresh (ospf, lsa); break; case OSPF_AS_EXTERNAL_LSA: /* Translated from NSSA Type-5s are refreshed when * from refresh of Type-7 - do not refresh these directly. */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) break; ei = ospf_external_info_check (lsa); if (ei) new = ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE); else ospf_lsa_flush_as (ospf, lsa); break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: new = ospf_opaque_lsa_refresh (lsa); break; #endif /* HAVE_OPAQUE_LSA */ default: break; } return new; } void ospf_refresher_register_lsa (struct ospf *ospf, struct ospf_lsa *lsa) { u_int16_t index, current_index; assert (lsa->lock > 0); assert (IS_LSA_SELF (lsa)); if (lsa->refresh_list < 0) { int delay; if (LS_AGE (lsa) == 0 && ntohl (lsa->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER) /* Randomize first update by OSPF_LS_REFRESH_SHIFT factor */ delay = OSPF_LS_REFRESH_SHIFT + (random () % OSPF_LS_REFRESH_TIME); else /* Randomize another updates by +-OSPF_LS_REFRESH_JITTER factor */ delay = OSPF_LS_REFRESH_TIME - LS_AGE (lsa) - OSPF_LS_REFRESH_JITTER + (random () % (2*OSPF_LS_REFRESH_JITTER)); if (delay < 0) delay = 0; current_index = ospf->lsa_refresh_queue.index + (quagga_time (NULL) - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY; index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY) % (OSPF_LSA_REFRESHER_SLOTS); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]: lsa %s with age %d added to index %d", inet_ntoa (lsa->data->id), LS_AGE (lsa), index); if (!ospf->lsa_refresh_queue.qs[index]) ospf->lsa_refresh_queue.qs[index] = list_new (); listnode_add (ospf->lsa_refresh_queue.qs[index], ospf_lsa_lock (lsa)); /* lsa_refresh_queue */ lsa->refresh_list = index; if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_refresher_register_lsa(): " "setting refresh_list on lsa %p (slod %d)", inet_ntoa (lsa->data->id), lsa, index); } } void ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa) { assert (lsa->lock > 0); assert (IS_LSA_SELF (lsa)); if (lsa->refresh_list >= 0) { struct list *refresh_list = ospf->lsa_refresh_queue.qs[lsa->refresh_list]; listnode_delete (refresh_list, lsa); if (!listcount (refresh_list)) { list_free (refresh_list); ospf->lsa_refresh_queue.qs[lsa->refresh_list] = NULL; } ospf_lsa_unlock (&lsa); /* lsa_refresh_queue */ lsa->refresh_list = -1; } } int ospf_lsa_refresh_walker (struct thread *t) { struct list *refresh_list; struct listnode *node, *nnode; struct ospf *ospf = THREAD_ARG (t); struct ospf_lsa *lsa; int i; struct list *lsa_to_refresh = list_new (); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]:ospf_lsa_refresh_walker(): start"); i = ospf->lsa_refresh_queue.index; /* Note: if clock has jumped backwards, then time change could be negative, so we are careful to cast the expression to unsigned before taking modulus. */ ospf->lsa_refresh_queue.index = ((unsigned long)(ospf->lsa_refresh_queue.index + (quagga_time (NULL) - ospf->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS; if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d", ospf->lsa_refresh_queue.index); for (;i != ospf->lsa_refresh_queue.index; i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS) { if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): " "refresh index %d", i); refresh_list = ospf->lsa_refresh_queue.qs [i]; assert (i >= 0); ospf->lsa_refresh_queue.qs [i] = NULL; if (refresh_list) { for (ALL_LIST_ELEMENTS (refresh_list, node, nnode, lsa)) { if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh:%s]: ospf_lsa_refresh_walker(): " "refresh lsa %p (slot %d)", inet_ntoa (lsa->data->id), lsa, i); assert (lsa->lock > 0); list_delete_node (refresh_list, node); lsa->refresh_list = -1; listnode_add (lsa_to_refresh, lsa); } list_free (refresh_list); } } ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, ospf->lsa_refresh_interval); ospf->lsa_refresher_started = quagga_time (NULL); for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa)) { ospf_lsa_refresh (ospf, lsa); assert (lsa->lock > 0); ospf_lsa_unlock (&lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/ } list_delete (lsa_to_refresh); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): end"); return 0; } quagga-0.99.24.1/ospfd/ospf_packet.c0000644000175000017500000034564412476520570014031 00000000000000/* * OSPF Sending and Receiving OSPF Packets. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "sockunion.h" #include "stream.h" #include "log.h" #include "sockopt.h" #include "checksum.h" #include "md5.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_dump.h" /* Packet Type String. */ const struct message ospf_packet_type_str[] = { { OSPF_MSG_HELLO, "Hello" }, { OSPF_MSG_DB_DESC, "Database Description" }, { OSPF_MSG_LS_REQ, "Link State Request" }, { OSPF_MSG_LS_UPD, "Link State Update" }, { OSPF_MSG_LS_ACK, "Link State Acknowledgment" }, }; const size_t ospf_packet_type_str_max = sizeof (ospf_packet_type_str) / sizeof (ospf_packet_type_str[0]); /* Minimum (besides OSPF_HEADER_SIZE) lengths for OSPF packets of particular types, offset is the "type" field of a packet. */ static const u_int16_t ospf_packet_minlen[] = { 0, OSPF_HELLO_MIN_SIZE, OSPF_DB_DESC_MIN_SIZE, OSPF_LS_REQ_MIN_SIZE, OSPF_LS_UPD_MIN_SIZE, OSPF_LS_ACK_MIN_SIZE, }; /* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular types, offset is the "LSA type" field. */ static const u_int16_t ospf_lsa_minlen[] = { 0, OSPF_ROUTER_LSA_MIN_SIZE, OSPF_NETWORK_LSA_MIN_SIZE, OSPF_SUMMARY_LSA_MIN_SIZE, OSPF_SUMMARY_LSA_MIN_SIZE, OSPF_AS_EXTERNAL_LSA_MIN_SIZE, 0, OSPF_AS_EXTERNAL_LSA_MIN_SIZE, 0, 0, 0, 0, }; /* for ospf_check_auth() */ static int ospf_check_sum (struct ospf_header *); /* OSPF authentication checking function */ static int ospf_auth_type (struct ospf_interface *oi) { int auth_type; if (OSPF_IF_PARAM (oi, auth_type) == OSPF_AUTH_NOTSET) auth_type = oi->area->auth_type; else auth_type = OSPF_IF_PARAM (oi, auth_type); /* Handle case where MD5 key list is not configured aka Cisco */ if (auth_type == OSPF_AUTH_CRYPTOGRAPHIC && list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) return OSPF_AUTH_NULL; return auth_type; } struct ospf_packet * ospf_packet_new (size_t size) { struct ospf_packet *new; new = XCALLOC (MTYPE_OSPF_PACKET, sizeof (struct ospf_packet)); new->s = stream_new (size); return new; } void ospf_packet_free (struct ospf_packet *op) { if (op->s) stream_free (op->s); XFREE (MTYPE_OSPF_PACKET, op); op = NULL; } struct ospf_fifo * ospf_fifo_new () { struct ospf_fifo *new; new = XCALLOC (MTYPE_OSPF_FIFO, sizeof (struct ospf_fifo)); return new; } /* Add new packet to fifo. */ void ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op) { if (fifo->tail) fifo->tail->next = op; else fifo->head = op; fifo->tail = op; fifo->count++; } /* Add new packet to head of fifo. */ static void ospf_fifo_push_head (struct ospf_fifo *fifo, struct ospf_packet *op) { op->next = fifo->head; if (fifo->tail == NULL) fifo->tail = op; fifo->head = op; fifo->count++; } /* Delete first packet from fifo. */ struct ospf_packet * ospf_fifo_pop (struct ospf_fifo *fifo) { struct ospf_packet *op; op = fifo->head; if (op) { fifo->head = op->next; if (fifo->head == NULL) fifo->tail = NULL; fifo->count--; } return op; } /* Return first fifo entry. */ struct ospf_packet * ospf_fifo_head (struct ospf_fifo *fifo) { return fifo->head; } /* Flush ospf packet fifo. */ void ospf_fifo_flush (struct ospf_fifo *fifo) { struct ospf_packet *op; struct ospf_packet *next; for (op = fifo->head; op; op = next) { next = op->next; ospf_packet_free (op); } fifo->head = fifo->tail = NULL; fifo->count = 0; } /* Free ospf packet fifo. */ void ospf_fifo_free (struct ospf_fifo *fifo) { ospf_fifo_flush (fifo); XFREE (MTYPE_OSPF_FIFO, fifo); } void ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op) { if (!oi->obuf) { zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, " "destination %s) called with NULL obuf, ignoring " "(please report this bug)!\n", IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), inet_ntoa (op->dst)); return; } /* Add packet to end of queue. */ ospf_fifo_push (oi->obuf, op); /* Debug of packet fifo*/ /* ospf_fifo_debug (oi->obuf); */ } static void ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op) { if (!oi->obuf) { zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, " "destination %s) called with NULL obuf, ignoring " "(please report this bug)!\n", IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state), LOOKUP (ospf_packet_type_str, stream_getc_from(op->s, 1)), inet_ntoa (op->dst)); return; } /* Add packet to head of queue. */ ospf_fifo_push_head (oi->obuf, op); /* Debug of packet fifo*/ /* ospf_fifo_debug (oi->obuf); */ } void ospf_packet_delete (struct ospf_interface *oi) { struct ospf_packet *op; op = ospf_fifo_pop (oi->obuf); if (op) ospf_packet_free (op); } struct ospf_packet * ospf_packet_dup (struct ospf_packet *op) { struct ospf_packet *new; if (stream_get_endp(op->s) != op->length) /* XXX size_t */ zlog_warn ("ospf_packet_dup stream %lu ospf_packet %u size mismatch", (u_long)STREAM_SIZE(op->s), op->length); /* Reserve space for MD5 authentication that may be added later. */ new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE); stream_copy (new->s, op->s); new->dst = op->dst; new->length = op->length; return new; } /* XXX inline */ static unsigned int ospf_packet_authspace (struct ospf_interface *oi) { int auth = 0; if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC) auth = OSPF_AUTH_MD5_SIZE; return auth; } static unsigned int ospf_packet_max (struct ospf_interface *oi) { int max; max = oi->ifp->mtu - ospf_packet_authspace(oi); max -= (OSPF_HEADER_SIZE + sizeof (struct ip)); return max; } static int ospf_check_md5_digest (struct ospf_interface *oi, struct ospf_header *ospfh) { MD5_CTX ctx; unsigned char digest[OSPF_AUTH_MD5_SIZE]; struct crypt_key *ck; struct ospf_neighbor *nbr; u_int16_t length = ntohs (ospfh->length); /* Get secret key. */ ck = ospf_crypt_key_lookup (OSPF_IF_PARAM (oi, auth_crypt), ospfh->u.crypt.key_id); if (ck == NULL) { zlog_warn ("interface %s: ospf_check_md5 no key %d", IF_NAME (oi), ospfh->u.crypt.key_id); return 0; } /* check crypto seqnum. */ nbr = ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id); if (nbr && ntohl(nbr->crypt_seqnum) > ntohl(ospfh->u.crypt.crypt_seqnum)) { zlog_warn ("interface %s: ospf_check_md5 bad sequence %d (expect %d)", IF_NAME (oi), ntohl(ospfh->u.crypt.crypt_seqnum), ntohl(nbr->crypt_seqnum)); return 0; } /* Generate a digest for the ospf packet - their digest + our digest. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ospfh, length); MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* compare the two */ if (memcmp ((caddr_t)ospfh + length, digest, OSPF_AUTH_MD5_SIZE)) { zlog_warn ("interface %s: ospf_check_md5 checksum mismatch", IF_NAME (oi)); return 0; } /* save neighbor's crypt_seqnum */ if (nbr) nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; return 1; } /* This function is called from ospf_write(), it will detect the authentication scheme and if it is MD5, it will change the sequence and update the MD5 digest. */ static int ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op) { struct ospf_header *ospfh; unsigned char digest[OSPF_AUTH_MD5_SIZE] = {0}; MD5_CTX ctx; void *ibuf; u_int32_t t; struct crypt_key *ck; const u_int8_t *auth_key; ibuf = STREAM_DATA (op->s); ospfh = (struct ospf_header *) ibuf; if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) return 0; /* We do this here so when we dup a packet, we don't have to waste CPU rewriting other headers. Note that quagga_time /deliberately/ is not used here */ t = (time(NULL) & 0xFFFFFFFF); if (t > oi->crypt_seqnum) oi->crypt_seqnum = t; else oi->crypt_seqnum++; ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum); /* Get MD5 Authentication key from auth_key list. */ if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) auth_key = (const u_int8_t *) digest; else { ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); auth_key = ck->auth_key; } /* Generate a digest for the entire packet + our secret key. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, ibuf, ntohs (ospfh->length)); MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* Append md5 digest to the end of the stream. */ stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE); /* We do *NOT* increment the OSPF header length. */ op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE; if (stream_get_endp(op->s) != op->length) /* XXX size_t */ zlog_warn("ospf_make_md5_digest: length mismatch stream %lu ospf_packet %u", (u_long)stream_get_endp(op->s), op->length); return OSPF_AUTH_MD5_SIZE; } static int ospf_ls_req_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_ls_req = NULL; /* Send Link State Request. */ if (ospf_ls_request_count (nbr)) ospf_ls_req_send (nbr); /* Set Link State Request retransmission timer. */ OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); return 0; } void ospf_ls_req_event (struct ospf_neighbor *nbr) { if (nbr->t_ls_req) { thread_cancel (nbr->t_ls_req); nbr->t_ls_req = NULL; } nbr->t_ls_req = thread_add_event (master, ospf_ls_req_timer, nbr, 0); } /* Cyclic timer function. Fist registered in ospf_nbr_new () in ospf_neighbor.c */ int ospf_ls_upd_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_ls_upd = NULL; /* Send Link State Update. */ if (ospf_ls_retransmit_count (nbr) > 0) { struct list *update; struct ospf_lsdb *lsdb; int i; int retransmit_interval; retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval); lsdb = &nbr->ls_rxmt; update = list_new (); for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { struct route_table *table = lsdb->type[i].db; struct route_node *rn; for (rn = route_top (table); rn; rn = route_next (rn)) { struct ospf_lsa *lsa; if ((lsa = rn->info) != NULL) /* Don't retransmit an LSA if we received it within the last RxmtInterval seconds - this is to allow the neighbour a chance to acknowledge the LSA as it may have ben just received before the retransmit timer fired. This is a small tweak to what is in the RFC, but it will cut out out a lot of retransmit traffic - MAG */ if (tv_cmp (tv_sub (recent_relative_time (), lsa->tv_recv), int2tv (retransmit_interval)) >= 0) listnode_add (update, rn->info); } } if (listcount (update) > 0) ospf_ls_upd_send (nbr, update, OSPF_SEND_PACKET_DIRECT); list_delete (update); } /* Set LS Update retransmission timer. */ OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); return 0; } int ospf_ls_ack_timer (struct thread *thread) { struct ospf_interface *oi; oi = THREAD_ARG (thread); oi->t_ls_ack = NULL; /* Send Link State Acknowledgment. */ if (listcount (oi->ls_ack) > 0) ospf_ls_ack_send_delayed (oi); /* Set LS Ack timer. */ OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); return 0; } #ifdef WANT_OSPF_WRITE_FRAGMENT static void ospf_write_frags (int fd, struct ospf_packet *op, struct ip *iph, struct msghdr *msg, unsigned int maxdatasize, unsigned int mtu, int flags, u_char type) { #define OSPF_WRITE_FRAG_SHIFT 3 u_int16_t offset; struct iovec *iovp; int ret; assert ( op->length == stream_get_endp(op->s) ); assert (msg->msg_iovlen == 2); /* we can but try. * * SunOS, BSD and BSD derived kernels likely will clear ip_id, as * well as the IP_MF flag, making this all quite pointless. * * However, for a system on which IP_MF is left alone, and ip_id left * alone or else which sets same ip_id for each fragment this might * work, eg linux. * * XXX-TODO: It would be much nicer to have the kernel's use their * existing fragmentation support to do this for us. Bugs/RFEs need to * be raised against the various kernels. */ /* set More Frag */ iph->ip_off |= IP_MF; /* ip frag offset is expressed in units of 8byte words */ offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT; iovp = &msg->msg_iov[1]; while ( (stream_get_endp(op->s) - stream_get_getp (op->s)) > maxdatasize ) { /* data length of this frag is to next offset value */ iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT; iph->ip_len = iovp->iov_len + sizeof (struct ip); assert (iph->ip_len <= mtu); sockopt_iphdrincl_swab_htosys (iph); ret = sendmsg (fd, msg, flags); sockopt_iphdrincl_swab_systoh (iph); if (ret < 0) zlog_warn ("*** ospf_write_frags: sendmsg failed to %s," " id %d, off %d, len %d, mtu %u failed with %s", inet_ntoa (iph->ip_dst), iph->ip_id, iph->ip_off, iph->ip_len, mtu, safe_strerror (errno)); if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) { zlog_debug ("ospf_write_frags: sent id %d, off %d, len %d to %s\n", iph->ip_id, iph->ip_off, iph->ip_len, inet_ntoa (iph->ip_dst)); if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) { zlog_debug ("-----------------IP Header Dump----------------------"); ospf_ip_header_dump (iph); zlog_debug ("-----------------------------------------------------"); } } iph->ip_off += offset; stream_forward_getp (op->s, iovp->iov_len); iovp->iov_base = STREAM_PNT (op->s); } /* setup for final fragment */ iovp->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s); iph->ip_len = iovp->iov_len + sizeof (struct ip); iph->ip_off &= (~IP_MF); } #endif /* WANT_OSPF_WRITE_FRAGMENT */ static int ospf_write (struct thread *thread) { struct ospf *ospf = THREAD_ARG (thread); struct ospf_interface *oi; struct ospf_packet *op; struct sockaddr_in sa_dst; struct ip iph; struct msghdr msg; struct iovec iov[2]; u_char type; int ret; int flags = 0; struct listnode *node; #ifdef WANT_OSPF_WRITE_FRAGMENT static u_int16_t ipid = 0; #endif /* WANT_OSPF_WRITE_FRAGMENT */ u_int16_t maxdatasize; #define OSPF_WRITE_IPHL_SHIFT 2 ospf->t_write = NULL; node = listhead (ospf->oi_write_q); assert (node); oi = listgetdata (node); assert (oi); #ifdef WANT_OSPF_WRITE_FRAGMENT /* seed ipid static with low order bits of time */ if (ipid == 0) ipid = (time(NULL) & 0xffff); #endif /* WANT_OSPF_WRITE_FRAGMENT */ /* convenience - max OSPF data per packet, * and reliability - not more data, than our * socket can accept */ maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) - sizeof (struct ip); /* Get one packet from queue. */ op = ospf_fifo_head (oi->obuf); assert (op); assert (op->length >= OSPF_HEADER_SIZE); if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS) || op->dst.s_addr == htonl (OSPF_ALLDROUTERS)) ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex); /* Rewrite the md5 signature & update the seq */ ospf_make_md5_digest (oi, op); /* Retrieve OSPF packet type. */ stream_set_getp (op->s, 1); type = stream_getc (op->s); /* reset get pointer */ stream_set_getp (op->s, 0); memset (&iph, 0, sizeof (struct ip)); memset (&sa_dst, 0, sizeof (sa_dst)); sa_dst.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_dst.sin_len = sizeof(sa_dst); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sa_dst.sin_addr = op->dst; sa_dst.sin_port = htons (0); /* Set DONTROUTE flag if dst is unicast. */ if (oi->type != OSPF_IFTYPE_VIRTUALLINK) if (!IN_MULTICAST (htonl (op->dst.s_addr))) flags = MSG_DONTROUTE; iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT; /* it'd be very strange for header to not be 4byte-word aligned but.. */ if ( sizeof (struct ip) > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) ) iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */ iph.ip_v = IPVERSION; iph.ip_tos = IPTOS_PREC_INTERNETCONTROL; iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length; #if defined(__DragonFly__) /* * DragonFly's raw socket expects ip_len/ip_off in network byte order. */ iph.ip_len = htons(iph.ip_len); #endif #ifdef WANT_OSPF_WRITE_FRAGMENT /* XXX-MT: not thread-safe at all.. * XXX: this presumes this is only programme sending OSPF packets * otherwise, no guarantee ipid will be unique */ iph.ip_id = ++ipid; #endif /* WANT_OSPF_WRITE_FRAGMENT */ iph.ip_off = 0; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) iph.ip_ttl = OSPF_VL_IP_TTL; else iph.ip_ttl = OSPF_IP_TTL; iph.ip_p = IPPROTO_OSPFIGP; iph.ip_sum = 0; iph.ip_src.s_addr = oi->address->u.prefix4.s_addr; iph.ip_dst.s_addr = op->dst.s_addr; memset (&msg, 0, sizeof (msg)); msg.msg_name = (caddr_t) &sa_dst; msg.msg_namelen = sizeof (sa_dst); msg.msg_iov = iov; msg.msg_iovlen = 2; iov[0].iov_base = (char*)&iph; iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT; iov[1].iov_base = STREAM_PNT (op->s); iov[1].iov_len = op->length; /* Sadly we can not rely on kernels to fragment packets because of either * IP_HDRINCL and/or multicast destination being set. */ #ifdef WANT_OSPF_WRITE_FRAGMENT if ( op->length > maxdatasize ) ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize, oi->ifp->mtu, flags, type); #endif /* WANT_OSPF_WRITE_FRAGMENT */ /* send final fragment (could be first) */ sockopt_iphdrincl_swab_htosys (&iph); ret = sendmsg (ospf->fd, &msg, flags); sockopt_iphdrincl_swab_systoh (&iph); if (ret < 0) zlog_warn ("*** sendmsg in ospf_write failed to %s, " "id %d, off %d, len %d, interface %s, mtu %u: %s", inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len, oi->ifp->name, oi->ifp->mtu, safe_strerror (errno)); /* Show debug sending packet. */ if (IS_DEBUG_OSPF_PACKET (type - 1, SEND)) { if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) { zlog_debug ("-----------------------------------------------------"); ospf_ip_header_dump (&iph); stream_set_getp (op->s, 0); ospf_packet_dump (op->s); } zlog_debug ("%s sent to [%s] via [%s].", LOOKUP (ospf_packet_type_str, type), inet_ntoa (op->dst), IF_NAME (oi)); if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL)) zlog_debug ("-----------------------------------------------------"); } /* Now delete packet from queue. */ ospf_packet_delete (oi); /* Move this interface to the tail of write_q to serve everyone in a round robin fashion */ listnode_move_to_tail (ospf->oi_write_q, node); if (ospf_fifo_head (oi->obuf) == NULL) { oi->on_write_q = 0; list_delete_node (ospf->oi_write_q, node); } /* If packets still remain in queue, call write thread. */ if (!list_isempty (ospf->oi_write_q)) ospf->t_write = thread_add_write (master, ospf_write, ospf, ospf->fd); return 0; } /* OSPF Hello message read -- RFC2328 Section 10.5. */ static void ospf_hello (struct ip *iph, struct ospf_header *ospfh, struct stream * s, struct ospf_interface *oi, int size) { struct ospf_hello *hello; struct ospf_neighbor *nbr; int old_state; struct prefix p; /* increment statistics. */ oi->hello_in++; hello = (struct ospf_hello *) STREAM_PNT (s); /* If Hello is myself, silently discard. */ if (IPV4_ADDR_SAME (&ospfh->router_id, &oi->ospf->router_id)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { zlog_debug ("ospf_header[%s/%s]: selforiginated, " "dropping.", LOOKUP (ospf_packet_type_str, ospfh->type), inet_ntoa (iph->ip_src)); } return; } /* get neighbor prefix. */ p.family = AF_INET; p.prefixlen = ip_masklen (hello->network_mask); p.u.prefix4 = iph->ip_src; /* Compare network mask. */ /* Checking is ignored for Point-to-Point and Virtual link. */ if (oi->type != OSPF_IFTYPE_POINTOPOINT && oi->type != OSPF_IFTYPE_VIRTUALLINK) if (oi->address->prefixlen != p.prefixlen) { zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch on %s (configured prefix length is %d, but hello packet indicates %d).", inet_ntoa(ospfh->router_id), IF_NAME(oi), (int)oi->address->prefixlen, (int)p.prefixlen); return; } /* Compare Router Dead Interval. */ if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval)) { zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch " "(expected %u, but received %u).", inet_ntoa(ospfh->router_id), OSPF_IF_PARAM(oi, v_wait), ntohl(hello->dead_interval)); return; } /* Compare Hello Interval - ignored if fast-hellos are set. */ if (OSPF_IF_PARAM (oi, fast_hello) == 0) { if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval)) { zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch " "(expected %u, but received %u).", inet_ntoa(ospfh->router_id), OSPF_IF_PARAM(oi, v_hello), ntohs(hello->hello_interval)); return; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet %s [Hello:RECV]: Options %s", inet_ntoa (ospfh->router_id), ospf_options_dump (hello->options)); /* Compare options. */ #define REJECT_IF_TBIT_ON 1 /* XXX */ #ifdef REJECT_IF_TBIT_ON if (CHECK_FLAG (hello->options, OSPF_OPTION_T)) { /* * This router does not support non-zero TOS. * Drop this Hello packet not to establish neighbor relationship. */ zlog_warn ("Packet %s [Hello:RECV]: T-bit on, drop it.", inet_ntoa (ospfh->router_id)); return; } #endif /* REJECT_IF_TBIT_ON */ #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE) && CHECK_FLAG (hello->options, OSPF_OPTION_O)) { /* * This router does know the correct usage of O-bit * the bit should be set in DD packet only. */ zlog_warn ("Packet %s [Hello:RECV]: O-bit abuse?", inet_ntoa (ospfh->router_id)); #ifdef STRICT_OBIT_USAGE_CHECK return; /* Reject this packet. */ #else /* STRICT_OBIT_USAGE_CHECK */ UNSET_FLAG (hello->options, OSPF_OPTION_O); /* Ignore O-bit. */ #endif /* STRICT_OBIT_USAGE_CHECK */ } #endif /* HAVE_OPAQUE_LSA */ /* new for NSSA is to ensure that NP is on and E is off */ if (oi->area->external_routing == OSPF_AREA_NSSA) { if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP) && CHECK_FLAG (hello->options, OSPF_OPTION_NP) && ! CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) && ! CHECK_FLAG (hello->options, OSPF_OPTION_E))) { zlog_warn ("NSSA-Packet-%s[Hello:RECV]: my options: %x, his options %x", inet_ntoa (ospfh->router_id), OPTIONS (oi), hello->options); return; } if (IS_DEBUG_OSPF_NSSA) zlog_debug ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id)); } else /* The setting of the E-bit found in the Hello Packet's Options field must match this area's ExternalRoutingCapability A mismatch causes processing to stop and the packet to be dropped. The setting of the rest of the bits in the Hello Packet's Options field should be ignored. */ if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) != CHECK_FLAG (hello->options, OSPF_OPTION_E)) { zlog_warn ("Packet %s [Hello:RECV]: my options: %x, his options %x", inet_ntoa(ospfh->router_id), OPTIONS (oi), hello->options); return; } /* get neighbour struct */ nbr = ospf_nbr_get (oi, ospfh, iph, &p); /* neighbour must be valid, ospf_nbr_get creates if none existed */ assert (nbr); old_state = nbr->state; /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* RFC2328 Section 9.5.1 If the router is not eligible to become Designated Router, (snip) It must also send an Hello Packet in reply to an Hello Packet received from any eligible neighbor (other than the current Designated Router and Backup Designated Router). */ if (oi->type == OSPF_IFTYPE_NBMA) if (PRIORITY(oi) == 0 && hello->priority > 0 && IPV4_ADDR_CMP(&DR(oi), &iph->ip_src) && IPV4_ADDR_CMP(&BDR(oi), &iph->ip_src)) OSPF_NSM_TIMER_ON (nbr->t_hello_reply, ospf_hello_reply_timer, OSPF_HELLO_REPLY_DELAY); /* on NBMA network type, it happens to receive bidirectional Hello packet without advance 1-Way Received event. To avoid incorrect DR-seletion, raise 1-Way Received event.*/ if (oi->type == OSPF_IFTYPE_NBMA && (old_state == NSM_Down || old_state == NSM_Attempt)) { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived); nbr->priority = hello->priority; nbr->d_router = hello->d_router; nbr->bd_router = hello->bd_router; return; } if (ospf_nbr_bidirectional (&oi->ospf->router_id, hello->neighbors, size - OSPF_HELLO_MIN_SIZE)) { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_TwoWayReceived); nbr->options |= hello->options; } else { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived); /* Set neighbor information. */ nbr->priority = hello->priority; nbr->d_router = hello->d_router; nbr->bd_router = hello->bd_router; return; } /* If neighbor itself declares DR and no BDR exists, cause event BackupSeen */ if (IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router)) if (hello->bd_router.s_addr == 0 && oi->state == ISM_Waiting) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); /* neighbor itself declares BDR. */ if (oi->state == ISM_Waiting && IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router)) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_BackupSeen); /* had not previously. */ if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->d_router) && IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->d_router)) || (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->d_router) && IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->d_router))) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); /* had not previously. */ if ((IPV4_ADDR_SAME (&nbr->address.u.prefix4, &hello->bd_router) && IPV4_ADDR_CMP (&nbr->address.u.prefix4, &nbr->bd_router)) || (IPV4_ADDR_CMP (&nbr->address.u.prefix4, &hello->bd_router) && IPV4_ADDR_SAME (&nbr->address.u.prefix4, &nbr->bd_router))) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); /* Neighbor priority check. */ if (nbr->priority >= 0 && nbr->priority != hello->priority) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_NeighborChange); /* Set neighbor information. */ nbr->priority = hello->priority; nbr->d_router = hello->d_router; nbr->bd_router = hello->bd_router; } /* Save DD flags/options/Seqnum received. */ static void ospf_db_desc_save_current (struct ospf_neighbor *nbr, struct ospf_db_desc *dd) { nbr->last_recv.flags = dd->flags; nbr->last_recv.options = dd->options; nbr->last_recv.dd_seqnum = ntohl (dd->dd_seqnum); } /* Process rest of DD packet. */ static void ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi, struct ospf_neighbor *nbr, struct ospf_db_desc *dd, u_int16_t size) { struct ospf_lsa *new, *find; struct lsa_header *lsah; stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE); for (size -= OSPF_DB_DESC_MIN_SIZE; size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE) { lsah = (struct lsa_header *) STREAM_PNT (s); stream_forward_getp (s, OSPF_LSA_HEADER_SIZE); /* Unknown LS type. */ if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) { zlog_warn ("Packet [DD:RECV]: Unknown LS type %d.", lsah->type); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsah->type) && ! CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } #endif /* HAVE_OPAQUE_LSA */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ /* Check for stub area. Reject if AS-External from stub but allow if from NSSA. */ if (oi->area->external_routing == OSPF_AREA_STUB) { zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.", lsah->type, inet_ntoa (lsah->id), (oi->area->external_routing == OSPF_AREA_STUB) ?\ "STUB" : "NSSA"); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); return; } break; default: break; } /* Create LS-request object. */ new = ospf_ls_request_new (lsah); /* Lookup received LSA, then add LS request list. */ find = ospf_lsa_lookup_by_header (oi->area, lsah); /* ospf_lsa_more_recent is fine with NULL pointers */ switch (ospf_lsa_more_recent (find, new)) { case -1: /* Neighbour has a more recent LSA, we must request it */ ospf_ls_request_add (nbr, new); case 0: /* If we have a copy of this LSA, it's either less recent * and we're requesting it from neighbour (the case above), or * it's as recent and we both have same copy (this case). * * In neither of these two cases is there any point in * describing our copy of the LSA to the neighbour in a * DB-Summary packet, if we're still intending to do so. * * See: draft-ogier-ospf-dbex-opt-00.txt, describing the * backward compatible optimisation to OSPF DB Exchange / * DB Description process implemented here. */ if (find) ospf_lsdb_delete (&nbr->db_sum, find); ospf_lsa_discard (new); break; default: /* We have the more recent copy, nothing specific to do: * - no need to request neighbours stale copy * - must leave DB summary list copy alone */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet [DD:RECV]: LSA received Type %d, " "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id)); ospf_lsa_discard (new); } } /* Master */ if (IS_SET_DD_MS (nbr->dd_flags)) { nbr->dd_seqnum++; /* Both sides have no More, then we're done with Exchange */ if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); else ospf_db_desc_send (nbr); } /* Slave */ else { nbr->dd_seqnum = ntohl (dd->dd_seqnum); /* Send DD packet in reply. * * Must be done to acknowledge the Master's DD, regardless of * whether we have more LSAs ourselves to describe. * * This function will clear the 'More' bit, if after this DD * we have no more LSAs to describe to the master.. */ ospf_db_desc_send (nbr); /* Slave can raise ExchangeDone now, if master is also done */ if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone); } /* Save received neighbor values from DD. */ ospf_db_desc_save_current (nbr, dd); } static int ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr) { /* Is DD duplicated? */ if (dd->options == nbr->last_recv.options && dd->flags == nbr->last_recv.flags && dd->dd_seqnum == htonl (nbr->last_recv.dd_seqnum)) return 1; return 0; } /* OSPF Database Description message read -- RFC2328 Section 10.6. */ static void ospf_db_desc (struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_db_desc *dd; struct ospf_neighbor *nbr; /* Increment statistics. */ oi->db_desc_in++; dd = (struct ospf_db_desc *) STREAM_PNT (s); nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Packet[DD]: Unknown Neighbor %s", inet_ntoa (ospfh->router_id)); return; } /* Check MTU. */ if ((OSPF_IF_PARAM (oi, mtu_ignore) == 0) && (ntohs (dd->mtu) > oi->ifp->mtu)) { zlog_warn ("Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u", inet_ntoa (nbr->router_id), ntohs (dd->mtu), IF_NAME (oi), oi->ifp->mtu); return; } /* * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is not * required. In fact at least JunOS sends DD packets with P bit clear. * Until proper solution is developped, this hack should help. * * Update: According to the RFCs, N bit is specified /only/ for Hello * options, unfortunately its use in DD options is not specified. Hence some * implementations follow E-bit semantics and set it in DD options, and some * treat it as unspecified and hence follow the directive "default for * options is clear", ie unset. * * Reset the flag, as ospfd follows E-bit semantics. */ if ( (oi->area->external_routing == OSPF_AREA_NSSA) && (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) && (!CHECK_FLAG (dd->options, OSPF_OPTION_NP)) ) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options", inet_ntoa (nbr->router_id) ); SET_FLAG (dd->options, OSPF_OPTION_NP); } #ifdef REJECT_IF_TBIT_ON if (CHECK_FLAG (dd->options, OSPF_OPTION_T)) { /* * In Hello protocol, optional capability must have checked * to prevent this T-bit enabled router be my neighbor. */ zlog_warn ("Packet[DD]: Neighbor %s: T-bit on?", inet_ntoa (nbr->router_id)); return; } #endif /* REJECT_IF_TBIT_ON */ #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (dd->options, OSPF_OPTION_O) && !CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { /* * This node is not configured to handle O-bit, for now. * Clear it to ignore unsupported capability proposed by neighbor. */ UNSET_FLAG (dd->options, OSPF_OPTION_O); } #endif /* HAVE_OPAQUE_LSA */ /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* Process DD packet by neighbor status. */ switch (nbr->state) { case NSM_Down: case NSM_Attempt: case NSM_TwoWay: zlog_warn ("Packet[DD]: Neighbor %s state is %s, packet discarded.", inet_ntoa(nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state)); break; case NSM_Init: OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived); /* If the new state is ExStart, the processing of the current packet should then continue in this new state by falling through to case ExStart below. */ if (nbr->state != NSM_ExStart) break; case NSM_ExStart: /* Initial DBD */ if ((IS_SET_DD_ALL (dd->flags) == OSPF_DD_FLAG_ALL) && (size == OSPF_DB_DESC_MIN_SIZE)) { if (IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) > 0) { /* We're Slave---obey */ zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).", inet_ntoa(nbr->router_id)); nbr->dd_seqnum = ntohl (dd->dd_seqnum); /* Reset I/MS */ UNSET_FLAG (nbr->dd_flags, (OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I)); } else { /* We're Master, ignore the initial DBD from Slave */ zlog_info ("Packet[DD]: Neighbor %s: Initial DBD from Slave, " "ignoring.", inet_ntoa(nbr->router_id)); break; } } /* Ack from the Slave */ else if (!IS_SET_DD_MS (dd->flags) && !IS_SET_DD_I (dd->flags) && ntohl (dd->dd_seqnum) == nbr->dd_seqnum && IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) < 0) { zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Master).", inet_ntoa(nbr->router_id)); /* Reset I, leaving MS */ UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_I); } else { zlog_warn ("Packet[DD]: Neighbor %s Negotiation fails.", inet_ntoa(nbr->router_id)); break; } /* This is where the real Options are saved */ nbr->options = dd->options; #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Neighbor[%s] is %sOpaque-capable.", inet_ntoa (nbr->router_id), CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT "); if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O) && IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) { zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; " "Opaque-LSAs cannot be reliably advertised " "in this network.", inet_ntoa (nbr->router_id)); /* This situation is undesirable, but not a real error. */ } } #endif /* HAVE_OPAQUE_LSA */ OSPF_NSM_EVENT_EXECUTE (nbr, NSM_NegotiationDone); /* continue processing rest of packet. */ ospf_db_desc_proc (s, oi, nbr, dd, size); break; case NSM_Exchange: if (ospf_db_desc_is_dup (dd, nbr)) { if (IS_SET_DD_MS (nbr->dd_flags)) /* Master: discard duplicated DD packet. */ zlog_info ("Packet[DD] (Master): Neighbor %s packet duplicated.", inet_ntoa (nbr->router_id)); else /* Slave: cause to retransmit the last Database Description. */ { zlog_info ("Packet[DD] [Slave]: Neighbor %s packet duplicated.", inet_ntoa (nbr->router_id)); ospf_db_desc_resend (nbr); } break; } /* Otherwise DD packet should be checked. */ /* Check Master/Slave bit mismatch */ if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags)) { zlog_warn ("Packet[DD]: Neighbor %s MS-bit mismatch.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d", dd->flags, nbr->dd_flags); break; } /* Check initialize bit is set. */ if (IS_SET_DD_I (dd->flags)) { zlog_info ("Packet[DD]: Neighbor %s I-bit set.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); break; } /* Check DD Options. */ if (dd->options != nbr->options) { #ifdef ORIGINAL_CODING /* Save the new options for debugging */ nbr->options = dd->options; #endif /* ORIGINAL_CODING */ zlog_warn ("Packet[DD]: Neighbor %s options mismatch.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); break; } /* Check DD sequence number. */ if ((IS_SET_DD_MS (nbr->dd_flags) && ntohl (dd->dd_seqnum) != nbr->dd_seqnum) || (!IS_SET_DD_MS (nbr->dd_flags) && ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1)) { zlog_warn ("Packet[DD]: Neighbor %s sequence number mismatch.", inet_ntoa(nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); break; } /* Continue processing rest of packet. */ ospf_db_desc_proc (s, oi, nbr, dd, size); break; case NSM_Loading: case NSM_Full: if (ospf_db_desc_is_dup (dd, nbr)) { if (IS_SET_DD_MS (nbr->dd_flags)) { /* Master should discard duplicate DD packet. */ zlog_info ("Packet[DD]: Neighbor %s duplicated, " "packet discarded.", inet_ntoa(nbr->router_id)); break; } else { struct timeval t, now; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); t = tv_sub (now, nbr->last_send_ts); if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0) { /* In states Loading and Full the slave must resend its last Database Description packet in response to duplicate Database Description packets received from the master. For this reason the slave must wait RouterDeadInterval seconds before freeing the last Database Description packet. Reception of a Database Description packet from the master after this interval will generate a SeqNumberMismatch neighbor event. RFC2328 Section 10.8 */ ospf_db_desc_resend (nbr); break; } } } OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); break; default: zlog_warn ("Packet[DD]: Neighbor %s NSM illegal status %u.", inet_ntoa(nbr->router_id), nbr->state); break; } } #define OSPF_LSA_KEY_SIZE 12 /* type(4) + id(4) + ar(4) */ /* OSPF Link State Request Read -- RFC2328 Section 10.7. */ static void ospf_ls_req (struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_neighbor *nbr; u_int32_t ls_type; struct in_addr ls_id; struct in_addr adv_router; struct ospf_lsa *find; struct list *ls_upd; unsigned int length; /* Increment statistics. */ oi->ls_req_in++; nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Request: Unknown Neighbor %s.", inet_ntoa (ospfh->router_id)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* Neighbor State should be Exchange or later. */ if (nbr->state != NSM_Exchange && nbr->state != NSM_Loading && nbr->state != NSM_Full) { zlog_warn ("Link State Request received from %s: " "Neighbor state is %s, packet discarded.", inet_ntoa (ospfh->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state)); return; } /* Send Link State Update for ALL requested LSAs. */ ls_upd = list_new (); length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; while (size >= OSPF_LSA_KEY_SIZE) { /* Get one slice of Link State Request. */ ls_type = stream_getl (s); ls_id.s_addr = stream_get_ipv4 (s); adv_router.s_addr = stream_get_ipv4 (s); /* Verify LSA type. */ if (ls_type < OSPF_MIN_LSA || ls_type >= OSPF_MAX_LSA) { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); list_delete (ls_upd); return; } /* Search proper LSA in LSDB. */ find = ospf_lsa_lookup (oi->area, ls_type, ls_id, adv_router); if (find == NULL) { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); list_delete (ls_upd); return; } /* Packet overflows MTU size, send immediately. */ if (length + ntohs (find->data->length) > ospf_packet_max (oi)) { if (oi->type == OSPF_IFTYPE_NBMA) ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); else ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); /* Only remove list contents. Keep ls_upd. */ list_delete_all_node (ls_upd); length = OSPF_HEADER_SIZE + OSPF_LS_UPD_MIN_SIZE; } /* Append LSA to update list. */ listnode_add (ls_upd, find); length += ntohs (find->data->length); size -= OSPF_LSA_KEY_SIZE; } /* Send rest of Link State Update. */ if (listcount (ls_upd) > 0) { if (oi->type == OSPF_IFTYPE_NBMA) ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT); else ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_INDIRECT); list_delete (ls_upd); } else list_free (ls_upd); } /* Get the list of LSAs from Link State Update packet. And process some validation -- RFC2328 Section 13. (1)-(2). */ static struct list * ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s, struct ospf_interface *oi, size_t size) { u_int16_t count, sum; u_int32_t length; struct lsa_header *lsah; struct ospf_lsa *lsa; struct list *lsas; lsas = list_new (); count = stream_getl (s); size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */ for (; size >= OSPF_LSA_HEADER_SIZE && count > 0; size -= length, stream_forward_getp (s, length), count--) { lsah = (struct lsa_header *) STREAM_PNT (s); length = ntohs (lsah->length); if (length > size) { zlog_warn ("Link State Update: LSA length exceeds packet size."); break; } /* Validate the LSA's LS checksum. */ sum = lsah->checksum; if (! ospf_lsa_checksum_valid (lsah)) { /* (bug #685) more details in a one-line message make it possible * to identify problem source on the one hand and to have a better * chance to compress repeated messages in syslog on the other */ zlog_warn ("Link State Update: LSA checksum error %x/%x, ID=%s from: nbr %s, router ID %s, adv router %s", sum, lsah->checksum, inet_ntoa (lsah->id), inet_ntoa (nbr->src), inet_ntoa (nbr->router_id), inet_ntoa (lsah->adv_router)); continue; } /* Examine the LSA's LS type. */ if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA) { zlog_warn ("Link State Update: Unknown LS type %d", lsah->type); continue; } /* * What if the received LSA's age is greater than MaxAge? * Treat it as a MaxAge case -- endo. */ if (ntohs (lsah->ls_age) > OSPF_LSA_MAXAGE) lsah->ls_age = htons (OSPF_LSA_MAXAGE); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { #ifdef STRICT_OBIT_USAGE_CHECK if ((IS_OPAQUE_LSA(lsah->type) && ! CHECK_FLAG (lsah->options, OSPF_OPTION_O)) || (! IS_OPAQUE_LSA(lsah->type) && CHECK_FLAG (lsah->options, OSPF_OPTION_O))) { /* * This neighbor must know the exact usage of O-bit; * the bit will be set in Type-9,10,11 LSAs only. */ zlog_warn ("LSA[Type%d:%s]: O-bit abuse?", lsah->type, inet_ntoa (lsah->id)); continue; } #endif /* STRICT_OBIT_USAGE_CHECK */ /* Do not take in AS External Opaque-LSAs if we are a stub. */ if (lsah->type == OSPF_OPAQUE_AS_LSA && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id)); continue; } } else if (IS_OPAQUE_LSA(lsah->type)) { zlog_warn ("LSA[Type%d:%s]: Opaque capability mismatch?", lsah->type, inet_ntoa (lsah->id)); continue; } #endif /* HAVE_OPAQUE_LSA */ /* Create OSPF LSA instance. */ lsa = ospf_lsa_new (); /* We may wish to put some error checking if type NSSA comes in and area not in NSSA mode */ switch (lsah->type) { case OSPF_AS_EXTERNAL_LSA: #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_AS_LSA: #endif /* HAVE_OPAQUE_LSA */ lsa->area = NULL; break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: lsa->oi = oi; /* Remember incoming interface for flooding control. */ /* Fallthrough */ #endif /* HAVE_OPAQUE_LSA */ default: lsa->area = oi->area; break; } lsa->data = ospf_lsa_data_new (length); memcpy (lsa->data, lsah, length); if (IS_DEBUG_OSPF_EVENT) zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update", lsa->data->type, inet_ntoa (lsa->data->id), lsa); listnode_add (lsas, lsa); } return lsas; } /* Cleanup Update list. */ static void ospf_upd_list_clean (struct list *lsas) { struct listnode *node, *nnode; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) ospf_lsa_discard (lsa); list_delete (lsas); } /* OSPF Link State Update message read -- RFC2328 Section 13. */ static void ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_neighbor *nbr; struct list *lsas; struct listnode *node, *nnode; struct ospf_lsa *lsa = NULL; /* unsigned long ls_req_found = 0; */ /* Dis-assemble the stream, update each entry, re-encapsulate for flooding */ /* Increment statistics. */ oi->ls_upd_in++; /* Check neighbor. */ nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s", inet_ntoa (ospfh->router_id), IF_NAME (oi)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); /* Check neighbor state. */ if (nbr->state < NSM_Exchange) { zlog_warn ("Link State Update: " "Neighbor[%s] state %s is less than Exchange", inet_ntoa (ospfh->router_id), LOOKUP(ospf_nsm_state_msg, nbr->state)); return; } /* Get list of LSAs from Link State Update packet. - Also perorms Stages * 1 (validate LSA checksum) and 2 (check for LSA consistent type) * of section 13. */ lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size); #ifdef HAVE_OPAQUE_LSA /* * If self-originated Opaque-LSAs that have flooded before restart * are contained in the received LSUpd message, corresponding LSReq * messages to be sent may have to be modified. * To eliminate possible race conditions such that flushing and normal * updating for the same LSA would take place alternately, this trick * must be done before entering to the loop below. */ /* XXX: Why is this Opaque specific? Either our core code is deficient * and this should be fixed generally, or Opaque is inventing strawman * problems */ ospf_opaque_adjust_lsreq (nbr, lsas); #endif /* HAVE_OPAQUE_LSA */ #define DISCARD_LSA(L,N) {\ if (IS_DEBUG_OSPF_EVENT) \ zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \ ospf_lsa_discard (L); \ continue; } /* Process each LSA received in the one packet. * * Numbers in parentheses, e.g. (1), (2), etc., and the corresponding * text below are from the steps in RFC 2328, Section 13. */ for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa)) { struct ospf_lsa *ls_ret, *current; int ret = 1; if (IS_DEBUG_OSPF_NSSA) { char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; char buf3[INET_ADDRSTRLEN]; zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s", lsa->data->type, inet_ntop (AF_INET, &ospfh->router_id, buf1, INET_ADDRSTRLEN), inet_ntop (AF_INET, &lsa->data->id, buf2, INET_ADDRSTRLEN), inet_ntop (AF_INET, &lsa->data->adv_router, buf3, INET_ADDRSTRLEN)); } listnode_delete (lsas, lsa); /* We don't need it in list anymore */ /* (1) Validate Checksum - Done above by ospf_ls_upd_list_lsa() */ /* (2) LSA Type - Done above by ospf_ls_upd_list_lsa() */ /* (3) Do not take in AS External LSAs if we are a stub or NSSA. */ /* Do not take in AS NSSA if this neighbor and we are not NSSA */ /* Do take in Type-7's if we are an NSSA */ /* If we are also an ABR, later translate them to a Type-5 packet */ /* Later, an NSSA Re-fresh can Re-fresh Type-7's and an ABR will translate them to a separate Type-5 packet. */ if (lsa->data->type == OSPF_AS_EXTERNAL_LSA) /* Reject from STUB or NSSA */ if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) { if (IS_DEBUG_OSPF_NSSA) zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area"); DISCARD_LSA (lsa, 1); } if (lsa->data->type == OSPF_AS_NSSA_LSA) if (nbr->oi->area->external_routing != OSPF_AREA_NSSA) { if (IS_DEBUG_OSPF_NSSA) zlog_debug("Incoming NSSA LSA Discarded: Not NSSA Area"); DISCARD_LSA (lsa,2); } /* VU229804: Router-LSA Adv-ID must be equal to LS-ID */ if (lsa->data->type == OSPF_ROUTER_LSA) if (!IPV4_ADDR_SAME(&lsa->data->id, &lsa->data->adv_router)) { char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; char buf3[INET_ADDRSTRLEN]; zlog_err("Incoming Router-LSA from %s with " "Adv-ID[%s] != LS-ID[%s]", inet_ntop (AF_INET, &ospfh->router_id, buf1, INET_ADDRSTRLEN), inet_ntop (AF_INET, &lsa->data->id, buf2, INET_ADDRSTRLEN), inet_ntop (AF_INET, &lsa->data->adv_router, buf3, INET_ADDRSTRLEN)); zlog_err("OSPF domain compromised by attack or corruption. " "Verify correct operation of -ALL- OSPF routers."); DISCARD_LSA (lsa, 0); } /* Find the LSA in the current database. */ current = ospf_lsa_lookup_by_header (oi->area, lsa->data); /* (4) If the LSA's LS age is equal to MaxAge, and there is currently no instance of the LSA in the router's link state database, and none of router's neighbors are in states Exchange or Loading, then take the following actions: */ if (IS_LSA_MAXAGE (lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ ospf_ls_ack_send (nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF (lsa, LSA)) { zlog_debug ("Link State Update[%s]: LS age is equal to MaxAge.", dump_lsa_key(lsa)); } DISCARD_LSA (lsa, 3); } #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && IPV4_ADDR_SAME (&lsa->data->adv_router, &oi->ospf->router_id)) { /* * Even if initial flushing seems to be completed, there might * be a case that self-originated LSA with MaxAge still remain * in the routing domain. * Just send an LSAck message to cease retransmission. */ if (IS_LSA_MAXAGE (lsa)) { zlog_warn ("LSA[%s]: Boomerang effect?", dump_lsa_key (lsa)); ospf_ls_ack_send (nbr, lsa); ospf_lsa_discard (lsa); if (current != NULL && ! IS_LSA_MAXAGE (current)) ospf_opaque_lsa_refresh_schedule (current); continue; } /* * If an instance of self-originated Opaque-LSA is not found * in the LSDB, there are some possible cases here. * * 1) This node lost opaque-capability after restart. * 2) Else, a part of opaque-type is no more supported. * 3) Else, a part of opaque-id is no more supported. * * Anyway, it is still this node's responsibility to flush it. * Otherwise, the LSA instance remains in the routing domain * until its age reaches to MaxAge. */ /* XXX: We should deal with this for *ALL* LSAs, not just opaque */ if (current == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("LSA[%s]: Previously originated Opaque-LSA," "not found in the LSDB.", dump_lsa_key (lsa)); SET_FLAG (lsa->flags, OSPF_LSA_SELF); ospf_opaque_self_originated_lsa_received (nbr, lsa); ospf_ls_ack_send (nbr, lsa); continue; } } #endif /* HAVE_OPAQUE_LSA */ /* It might be happen that received LSA is self-originated network LSA, but * router ID is changed. So, we should check if LSA is a network-LSA whose * Link State ID is one of the router's own IP interface addresses but whose * Advertising Router is not equal to the router's own Router ID * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed. */ if(lsa->data->type == OSPF_NETWORK_LSA) { struct listnode *oinode, *oinnode; struct ospf_interface *out_if; int Flag = 0; for (ALL_LIST_ELEMENTS (oi->ospf->oiflist, oinode, oinnode, out_if)) { if(out_if == NULL) break; if((IPV4_ADDR_SAME(&out_if->address->u.prefix4, &lsa->data->id)) && (!(IPV4_ADDR_SAME(&oi->ospf->router_id, &lsa->data->adv_router)))) { if(out_if->network_lsa_self) { ospf_lsa_flush_area(lsa,out_if->area); if(IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d", lsa, (int) lsa->data->type); ospf_lsa_discard (lsa); Flag = 1; } break; } } if(Flag) continue; } /* (5) Find the instance of this LSA that is currently contained in the router's link state database. If there is no database copy, or the received LSA is more recent than the database copy the following steps must be performed. (The sub steps from RFC 2328 section 13 step (5) will be performed in ospf_flood() ) */ if (current == NULL || (ret = ospf_lsa_more_recent (current, lsa)) < 0) { /* Actual flooding procedure. */ if (ospf_flood (oi->ospf, nbr, current, lsa) < 0) /* Trap NSSA later. */ DISCARD_LSA (lsa, 4); continue; } /* (6) Else, If there is an instance of the LSA on the sending neighbor's Link state request list, an error has occurred in the Database Exchange process. In this case, restart the Database Exchange process by generating the neighbor event BadLSReq for the sending neighbor and stop processing the Link State Update packet. */ if (ospf_ls_request_lookup (nbr, lsa)) { OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq); zlog_warn("LSA[%s] instance exists on Link state request list", dump_lsa_key(lsa)); /* Clean list of LSAs. */ ospf_upd_list_clean (lsas); /* this lsa is not on lsas list already. */ ospf_lsa_discard (lsa); return; } /* If the received LSA is the same instance as the database copy (i.e., neither one is more recent) the following two steps should be performed: */ if (ret == 0) { /* If the LSA is listed in the Link state retransmission list for the receiving adjacency, the router itself is expecting an acknowledgment for this LSA. The router should treat the received LSA as an acknowledgment by removing the LSA from the Link state retransmission list. This is termed an "implied acknowledgment". */ ls_ret = ospf_ls_retransmit_lookup (nbr, lsa); if (ls_ret != NULL) { ospf_ls_retransmit_delete (nbr, ls_ret); /* Delayed acknowledgment sent if advertisement received from Designated Router, otherwise do nothing. */ if (oi->state == ISM_Backup) if (NBR_IS_DR (nbr)) listnode_add (oi->ls_ack, ospf_lsa_lock (lsa)); DISCARD_LSA (lsa, 5); } else /* Acknowledge the receipt of the LSA by sending a Link State Acknowledgment packet back out the receiving interface. */ { ospf_ls_ack_send (nbr, lsa); DISCARD_LSA (lsa, 6); } } /* The database copy is more recent. If the database copy has LS age equal to MaxAge and LS sequence number equal to MaxSequenceNumber, simply discard the received LSA without acknowledging it. (In this case, the LSA's LS sequence number is wrapping, and the MaxSequenceNumber LSA must be completely flushed before any new LSA instance can be introduced). */ else if (ret > 0) /* Database copy is more recent */ { if (IS_LSA_MAXAGE (current) && current->data->ls_seqnum == htonl (OSPF_MAX_SEQUENCE_NUMBER)) { DISCARD_LSA (lsa, 7); } /* Otherwise, as long as the database copy has not been sent in a Link State Update within the last MinLSArrival seconds, send the database copy back to the sending neighbor, encapsulated within a Link State Update Packet. The Link State Update Packet should be sent directly to the neighbor. In so doing, do not put the database copy of the LSA on the neighbor's link state retransmission list, and do not acknowledge the received (less recent) LSA instance. */ else { struct timeval now; quagga_gettime (QUAGGA_CLK_MONOTONIC, &now); if (tv_cmp (tv_sub (now, current->tv_orig), int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0) /* Trap NSSA type later.*/ ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT); DISCARD_LSA (lsa, 8); } } } #undef DISCARD_LSA assert (listcount (lsas) == 0); list_delete (lsas); } /* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */ static void ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh, struct stream *s, struct ospf_interface *oi, u_int16_t size) { struct ospf_neighbor *nbr; /* increment statistics. */ oi->ls_ack_in++; nbr = ospf_nbr_lookup (oi, iph, ospfh); if (nbr == NULL) { zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.", inet_ntoa (ospfh->router_id)); return; } /* Add event to thread. */ OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived); if (nbr->state < NSM_Exchange) { zlog_warn ("Link State Acknowledgment: " "Neighbor[%s] state %s is less than Exchange", inet_ntoa (ospfh->router_id), LOOKUP(ospf_nsm_state_msg, nbr->state)); return; } while (size >= OSPF_LSA_HEADER_SIZE) { struct ospf_lsa *lsa, *lsr; lsa = ospf_lsa_new (); lsa->data = (struct lsa_header *) STREAM_PNT (s); /* lsah = (struct lsa_header *) STREAM_PNT (s); */ size -= OSPF_LSA_HEADER_SIZE; stream_forward_getp (s, OSPF_LSA_HEADER_SIZE); if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA) { lsa->data = NULL; ospf_lsa_discard (lsa); continue; } lsr = ospf_ls_retransmit_lookup (nbr, lsa); if (lsr != NULL && ospf_lsa_more_recent (lsr, lsa) == 0) { #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsr->data->type)) ospf_opaque_ls_ack_received (nbr, lsr); #endif /* HAVE_OPAQUE_LSA */ ospf_ls_retransmit_delete (nbr, lsr); } lsa->data = NULL; ospf_lsa_discard (lsa); } return; } static struct stream * ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf) { int ret; struct ip *iph; u_int16_t ip_len; unsigned int ifindex = 0; struct iovec iov; /* Header and data both require alignment. */ char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())]; struct msghdr msgh; memset (&msgh, 0, sizeof (struct msghdr)); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_control = (caddr_t) buff; msgh.msg_controllen = sizeof (buff); ret = stream_recvmsg (ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE+1); if (ret < 0) { zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno)); return NULL; } if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */ { zlog_warn("ospf_recv_packet: discarding runt packet of length %d " "(ip header size is %u)", ret, (u_int)sizeof(iph)); return NULL; } /* Note that there should not be alignment problems with this assignment because this is at the beginning of the stream data buffer. */ iph = (struct ip *) STREAM_DATA(ibuf); sockopt_iphdrincl_swab_systoh (iph); ip_len = iph->ip_len; #if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000) /* * Kernel network code touches incoming IP header parameters, * before protocol specific processing. * * 1) Convert byteorder to host representation. * --> ip_len, ip_id, ip_off * * 2) Adjust ip_len to strip IP header size! * --> If user process receives entire IP packet via RAW * socket, it must consider adding IP header size to * the "ip_len" field of "ip" structure. * * For more details, see . */ ip_len = ip_len + (iph->ip_hl << 2); #endif #if defined(__DragonFly__) /* * in DragonFly's raw socket, ip_len/ip_off are read * in network byte order. * As OpenBSD < 200311 adjust ip_len to strip IP header size! */ ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2); #endif ifindex = getsockopt_ifindex (AF_INET, &msgh); *ifp = if_lookup_by_index (ifindex); if (ret != ip_len) { zlog_warn ("ospf_recv_packet read length mismatch: ip_len is %d, " "but recvmsg returned %d", ip_len, ret); return NULL; } return ibuf; } static struct ospf_interface * ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp, struct ip *iph, struct ospf_header *ospfh) { struct ospf_interface *rcv_oi; struct ospf_vl_data *vl_data; struct ospf_area *vl_area; struct listnode *node; if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) || !OSPF_IS_AREA_BACKBONE (ospfh)) return NULL; /* look for local OSPF interface matching the destination * to determine Area ID. We presume therefore the destination address * is unique, or at least (for "unnumbered" links), not used in other * areas */ if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_dst)) == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id); if (!vl_area) continue; if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) && IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("associating packet with %s", IF_NAME (vl_data->vl_oi)); if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("This VL is not up yet, sorry"); return NULL; } return vl_data->vl_oi; } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("couldn't find any VL to associate the packet with"); return NULL; } static int ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh) { /* Check match the Area ID of the receiving interface. */ if (OSPF_AREA_SAME (&oi->area, &ospfh)) return 1; return 0; } /* Unbound socket will accept any Raw IP packets if proto is matched. To prevent it, compare src IP address and i/f address with masking i/f network mask. */ static int ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src) { struct in_addr mask, me, him; if (oi->type == OSPF_IFTYPE_POINTOPOINT || oi->type == OSPF_IFTYPE_VIRTUALLINK) return 1; masklen2ip (oi->address->prefixlen, &mask); me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; him.s_addr = ip_src.s_addr & mask.s_addr; if (IPV4_ADDR_SAME (&me, &him)) return 1; return 0; } /* Return 1, if the packet is properly authenticated and checksummed, 0 otherwise. In particular, check that AuType header field is valid and matches the locally configured AuType, and that D.5 requirements are met. */ static int ospf_check_auth (struct ospf_interface *oi, struct ospf_header *ospfh) { struct crypt_key *ck; u_int16_t iface_auth_type; u_int16_t pkt_auth_type = ntohs (ospfh->auth_type); switch (pkt_auth_type) { case OSPF_AUTH_NULL: /* RFC2328 D.5.1 */ if (OSPF_AUTH_NULL != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Null", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (! ospf_check_sum (ospfh)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Null auth OK, but checksum error, Router-ID %s", IF_NAME (oi), inet_ntoa (ospfh->router_id)); return 0; } return 1; case OSPF_AUTH_SIMPLE: /* RFC2328 D.5.2 */ if (OSPF_AUTH_SIMPLE != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Simple", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Simple auth failed", IF_NAME (oi)); return 0; } if (! ospf_check_sum (ospfh)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: Simple auth OK, checksum error, Router-ID %s", IF_NAME (oi), inet_ntoa (ospfh->router_id)); return 0; } return 1; case OSPF_AUTH_CRYPTOGRAPHIC: /* RFC2328 D.5.3 */ if (OSPF_AUTH_CRYPTOGRAPHIC != (iface_auth_type = ospf_auth_type (oi))) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: auth-type mismatch, local %s, rcvd Cryptographic", IF_NAME (oi), LOOKUP (ospf_auth_type_str, iface_auth_type)); return 0; } if (ospfh->checksum) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: OSPF header checksum is not 0", IF_NAME (oi)); return 0; } /* only MD5 crypto method can pass ospf_packet_examin() */ if ( NULL == (ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) || ospfh->u.crypt.key_id != ck->key_id || /* Condition above uses the last key ID on the list, which is different from what ospf_crypt_key_lookup() does. A bug? */ ! ospf_check_md5_digest (oi, ospfh) ) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: MD5 auth failed", IF_NAME (oi)); return 0; } return 1; default: if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) zlog_warn ("interface %s: invalid packet auth-type (%02x)", IF_NAME (oi), pkt_auth_type); return 0; } } static int ospf_check_sum (struct ospf_header *ospfh) { u_int32_t ret; u_int16_t sum; /* clear auth_data for checksum. */ memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); /* keep checksum and clear. */ sum = ospfh->checksum; memset (&ospfh->checksum, 0, sizeof (u_int16_t)); /* calculate checksum. */ ret = in_cksum (ospfh, ntohs (ospfh->length)); if (ret != sum) { zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X", ret, sum); return 0; } return 1; } /* Verify, that given link/TOS records are properly sized/aligned and match Router-LSA "# links" and "# TOS" fields as specified in RFC2328 A.4.2. */ static unsigned ospf_router_lsa_links_examin ( struct router_lsa_link * link, u_int16_t linkbytes, const u_int16_t num_links ) { unsigned counted_links = 0, thislinklen; while (linkbytes) { thislinklen = OSPF_ROUTER_LSA_LINK_SIZE + 4 * link->m[0].tos_count; if (thislinklen > linkbytes) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: length error in link block #%u", __func__, counted_links); return MSG_NG; } link = (struct router_lsa_link *)((caddr_t) link + thislinklen); linkbytes -= thislinklen; counted_links++; } if (counted_links != num_links) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: %u link blocks declared, %u present", __func__, num_links, counted_links); return MSG_NG; } return MSG_OK; } /* Verify, that the given LSA is properly sized/aligned (including type-specific minimum length constraint). */ static unsigned ospf_lsa_examin (struct lsa_header * lsah, const u_int16_t lsalen, const u_char headeronly) { unsigned ret; struct router_lsa * rlsa; if ( lsah->type < OSPF_MAX_LSA && ospf_lsa_minlen[lsah->type] && lsalen < OSPF_LSA_HEADER_SIZE + ospf_lsa_minlen[lsah->type] ) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) %s", __func__, lsalen, LOOKUP (ospf_lsa_type_msg, lsah->type)); return MSG_NG; } switch (lsah->type) { case OSPF_ROUTER_LSA: /* RFC2328 A.4.2, LSA header + 4 bytes followed by N>=1 (12+)-byte link blocks */ if (headeronly) { ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; break; } rlsa = (struct router_lsa *) lsah; ret = ospf_router_lsa_links_examin ( (struct router_lsa_link *) rlsa->link, lsalen - OSPF_LSA_HEADER_SIZE - 4, /* skip: basic header, "flags", 0, "# links" */ ntohs (rlsa->links) /* 16 bits */ ); break; case OSPF_AS_EXTERNAL_LSA: /* RFC2328 A.4.5, LSA header + 4 bytes followed by N>=1 12-bytes long blocks */ case OSPF_AS_NSSA_LSA: /* RFC3101 C, idem */ ret = (lsalen - OSPF_LSA_HEADER_SIZE - OSPF_AS_EXTERNAL_LSA_MIN_SIZE) % 12 ? MSG_NG : MSG_OK; break; /* Following LSA types are considered OK length-wise as soon as their minimum * length constraint is met and length of the whole LSA is a multiple of 4 * (basic LSA header size is already a multiple of 4). */ case OSPF_NETWORK_LSA: /* RFC2328 A.4.3, LSA header + 4 bytes followed by N>=1 router-IDs */ case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: /* RFC2328 A.4.4, LSA header + 4 bytes followed by N>=1 4-bytes TOS blocks */ #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: /* RFC5250 A.2, "some number of octets (of application-specific * data) padded to 32-bit alignment." This is considered equivalent * to 4-byte alignment of all other LSA types, see OSPF-ALIGNMENT.txt * file for the detailed analysis of this passage. */ #endif ret = lsalen % 4 ? MSG_NG : MSG_OK; break; default: if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: unsupported LSA type 0x%02x", __func__, lsah->type); return MSG_NG; } if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: alignment error in %s", __func__, LOOKUP (ospf_lsa_type_msg, lsah->type)); return ret; } /* Verify if the provided input buffer is a valid sequence of LSAs. This includes verification of LSA blocks length/alignment and dispatching of deeper-level checks. */ static unsigned ospf_lsaseq_examin ( struct lsa_header *lsah, /* start of buffered data */ size_t length, const u_char headeronly, /* When declared_num_lsas is not 0, compare it to the real number of LSAs and treat the difference as an error. */ const u_int32_t declared_num_lsas ) { u_int32_t counted_lsas = 0; while (length) { u_int16_t lsalen; if (length < OSPF_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%zu B) trailing (#%u) LSA header", __func__, length, counted_lsas); return MSG_NG; } /* save on ntohs() calls here and in the LSA validator */ lsalen = ntohs (lsah->length); if (lsalen < OSPF_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed LSA header #%u, declared length is %u B", __func__, counted_lsas, lsalen); return MSG_NG; } if (headeronly) { /* less checks here and in ospf_lsa_examin() */ if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 1)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed header-only LSA #%u", __func__, counted_lsas); return MSG_NG; } lsah = (struct lsa_header *) ((caddr_t) lsah + OSPF_LSA_HEADER_SIZE); length -= OSPF_LSA_HEADER_SIZE; } else { /* make sure the input buffer is deep enough before further checks */ if (lsalen > length) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: anomaly in LSA #%u: declared length is %u B, buffered length is %zu B", __func__, counted_lsas, lsalen, length); return MSG_NG; } if (MSG_OK != ospf_lsa_examin (lsah, lsalen, 0)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed LSA #%u", __func__, counted_lsas); return MSG_NG; } lsah = (struct lsa_header *) ((caddr_t) lsah + lsalen); length -= lsalen; } counted_lsas++; } if (declared_num_lsas && counted_lsas != declared_num_lsas) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: #LSAs declared (%u) does not match actual (%u)", __func__, declared_num_lsas, counted_lsas); return MSG_NG; } return MSG_OK; } /* Verify a complete OSPF packet for proper sizing/alignment. */ static unsigned ospf_packet_examin (struct ospf_header * oh, const unsigned bytesonwire) { u_int16_t bytesdeclared, bytesauth; unsigned ret; struct ospf_ls_update * lsupd; /* Length, 1st approximation. */ if (bytesonwire < OSPF_HEADER_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) packet", __func__, bytesonwire); return MSG_NG; } /* Now it is safe to access header fields. Performing length check, allow * for possible extra bytes of crypto auth/padding, which are not counted * in the OSPF header "length" field. */ if (oh->version != OSPF_VERSION) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: invalid (%u) protocol version", __func__, oh->version); return MSG_NG; } bytesdeclared = ntohs (oh->length); if (ntohs (oh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) bytesauth = 0; else { if (oh->u.crypt.auth_data_len != OSPF_AUTH_MD5_SIZE) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: unsupported crypto auth length (%u B)", __func__, oh->u.crypt.auth_data_len); return MSG_NG; } bytesauth = OSPF_AUTH_MD5_SIZE; } if (bytesdeclared + bytesauth > bytesonwire) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: packet length error (%u real, %u+%u declared)", __func__, bytesonwire, bytesdeclared, bytesauth); return MSG_NG; } /* Length, 2nd approximation. The type-specific constraint is checked against declared length, not amount of bytes on wire. */ if ( oh->type >= OSPF_MSG_HELLO && oh->type <= OSPF_MSG_LS_ACK && bytesdeclared < OSPF_HEADER_SIZE + ospf_packet_minlen[oh->type] ) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: undersized (%u B) %s packet", __func__, bytesdeclared, LOOKUP (ospf_packet_type_str, oh->type)); return MSG_NG; } switch (oh->type) { case OSPF_MSG_HELLO: /* RFC2328 A.3.2, packet header + OSPF_HELLO_MIN_SIZE bytes followed by N>=0 router-IDs. */ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE) % 4 ? MSG_NG : MSG_OK; break; case OSPF_MSG_DB_DESC: /* RFC2328 A.3.3, packet header + OSPF_DB_DESC_MIN_SIZE bytes followed by N>=0 header-only LSAs. */ ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_DB_DESC_MIN_SIZE, 1, /* header-only LSAs */ 0 ); break; case OSPF_MSG_LS_REQ: /* RFC2328 A.3.4, packet header followed by N>=0 12-bytes request blocks. */ ret = (bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_REQ_MIN_SIZE) % OSPF_LSA_KEY_SIZE ? MSG_NG : MSG_OK; break; case OSPF_MSG_LS_UPD: /* RFC2328 A.3.5, packet header + OSPF_LS_UPD_MIN_SIZE bytes followed by N>=0 full LSAs (with N declared beforehand). */ lsupd = (struct ospf_ls_update *) ((caddr_t) oh + OSPF_HEADER_SIZE); ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) lsupd + OSPF_LS_UPD_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_UPD_MIN_SIZE, 0, /* full LSAs */ ntohl (lsupd->num_lsas) /* 32 bits */ ); break; case OSPF_MSG_LS_ACK: /* RFC2328 A.3.6, packet header followed by N>=0 header-only LSAs. */ ret = ospf_lsaseq_examin ( (struct lsa_header *) ((caddr_t) oh + OSPF_HEADER_SIZE + OSPF_LS_ACK_MIN_SIZE), bytesdeclared - OSPF_HEADER_SIZE - OSPF_LS_ACK_MIN_SIZE, 1, /* header-only LSAs */ 0 ); break; default: if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: invalid packet type 0x%02x", __func__, oh->type); return MSG_NG; } if (ret != MSG_OK && IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("%s: malformed %s packet", __func__, LOOKUP (ospf_packet_type_str, oh->type)); return ret; } /* OSPF Header verification. */ static int ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { /* Check Area ID. */ if (!ospf_check_area_id (oi, ospfh)) { zlog_warn ("interface %s: ospf_read invalid Area ID %s.", IF_NAME (oi), inet_ntoa (ospfh->area_id)); return -1; } /* Check network mask, Silently discarded. */ if (! ospf_check_network_mask (oi, iph->ip_src)) { zlog_warn ("interface %s: ospf_read network address is not same [%s]", IF_NAME (oi), inet_ntoa (iph->ip_src)); return -1; } /* Check authentication. The function handles logging actions, where required. */ if (! ospf_check_auth (oi, ospfh)) return -1; return 0; } /* Starting point of packet process function. */ int ospf_read (struct thread *thread) { int ret; struct stream *ibuf; struct ospf *ospf; struct ospf_interface *oi; struct ip *iph; struct ospf_header *ospfh; u_int16_t length; struct interface *ifp; /* first of all get interface pointer. */ ospf = THREAD_ARG (thread); /* prepare for next packet. */ ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd); stream_reset(ospf->ibuf); if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf))) return -1; /* This raw packet is known to be at least as big as its IP header. */ /* Note that there should not be alignment problems with this assignment because this is at the beginning of the stream data buffer. */ iph = (struct ip *) STREAM_DATA (ibuf); /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */ if (ifp == NULL) /* Handle cases where the platform does not support retrieving the ifindex, and also platforms (such as Solaris 8) that claim to support ifindex retrieval but do not. */ ifp = if_lookup_address (iph->ip_src); if (ifp == NULL) return 0; /* IP Header dump. */ if (IS_DEBUG_OSPF_PACKET(0, RECV)) ospf_ip_header_dump (iph); /* Self-originated packet should be discarded silently. */ if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src)) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) { zlog_debug ("ospf_read[%s]: Dropping self-originated packet", inet_ntoa (iph->ip_src)); } return 0; } /* Advance from IP header to OSPF header (iph->ip_hl has been verified by ospf_recv_packet() to be correct). */ stream_forward_getp (ibuf, iph->ip_hl * 4); ospfh = (struct ospf_header *) STREAM_PNT (ibuf); if (MSG_OK != ospf_packet_examin (ospfh, stream_get_endp (ibuf) - stream_get_getp (ibuf))) return -1; /* Now it is safe to access all fields of OSPF packet header. */ /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp); /* ospf_verify_header() relies on a valid "oi" and thus can be called only after the passive/backbone/other checks below are passed. These checks in turn access the fields of unverified "ospfh" structure for their own purposes and must remain very accurate in doing this. */ /* If incoming interface is passive one, ignore it. */ if (oi && OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) { char buf[3][INET_ADDRSTRLEN]; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ignoring packet from router %s sent to %s, " "received on a passive interface, %s", inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), inet_ntop(AF_INET, &oi->address->u.prefix4, buf[2], sizeof(buf[2]))); if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) { /* Try to fix multicast membership. * Some OS:es may have problems in this area, * make sure it is removed. */ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); ospf_if_set_multicast(oi); } return 0; } /* if no local ospf_interface, * or header area is backbone but ospf_interface is not * check for VLINK interface */ if ( (oi == NULL) || (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id) && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id)) ) { if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Packet from [%s] received on link %s" " but no ospf_interface", inet_ntoa (iph->ip_src), ifp->name); return 0; } } /* else it must be a local ospf interface, check it was received on * correct link */ else if (oi->ifp != ifp) { if (IS_DEBUG_OSPF_EVENT) zlog_warn ("Packet from [%s] received on wrong link %s", inet_ntoa (iph->ip_src), ifp->name); return 0; } else if (oi->state == ISM_Down) { char buf[2][INET_ADDRSTRLEN]; zlog_warn ("Ignoring packet from %s to %s received on interface that is " "down [%s]; interface flags are %s", inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])), inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])), ifp->name, if_flag_dump(ifp->flags)); /* Fix multicast memberships? */ if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS)) OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS)) OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); if (oi->multicast_memberships) ospf_if_set_multicast(oi); return 0; } /* * If the received packet is destined for AllDRouters, the packet * should be accepted only if the received ospf interface state is * either DR or Backup -- endo. */ if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS) && (oi->state != ISM_DR && oi->state != ISM_Backup)) { zlog_warn ("Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)", inet_ntoa (iph->ip_src), IF_NAME (oi), LOOKUP (ospf_ism_state_msg, oi->state)); /* Try to fix multicast membership. */ SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS); ospf_if_set_multicast(oi); return 0; } /* Verify more OSPF header fields. */ ret = ospf_verify_header (ibuf, oi, iph, ospfh); if (ret < 0) { if (IS_DEBUG_OSPF_PACKET (0, RECV)) zlog_debug ("ospf_read[%s]: Header check failed, " "dropping.", inet_ntoa (iph->ip_src)); return ret; } /* Show debug receiving packet. */ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) { zlog_debug ("-----------------------------------------------------"); ospf_packet_dump (ibuf); } zlog_debug ("%s received from [%s] via [%s]", LOOKUP (ospf_packet_type_str, ospfh->type), inet_ntoa (ospfh->router_id), IF_NAME (oi)); zlog_debug (" src [%s],", inet_ntoa (iph->ip_src)); zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst)); if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) zlog_debug ("-----------------------------------------------------"); } stream_forward_getp (ibuf, OSPF_HEADER_SIZE); /* Adjust size to message length. */ length = ntohs (ospfh->length) - OSPF_HEADER_SIZE; /* Read rest of the packet and call each sort of packet routine. */ switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_hello (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_DB_DESC: ospf_db_desc (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_REQ: ospf_ls_req (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_UPD: ospf_ls_upd (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_ACK: ospf_ls_ack (iph, ospfh, ibuf, oi, length); break; default: zlog (NULL, LOG_WARNING, "interface %s: OSPF packet header type %d is illegal", IF_NAME (oi), ospfh->type); break; } return 0; } /* Make OSPF header. */ static void ospf_make_header (int type, struct ospf_interface *oi, struct stream *s) { struct ospf_header *ospfh; ospfh = (struct ospf_header *) STREAM_DATA (s); ospfh->version = (u_char) OSPF_VERSION; ospfh->type = (u_char) type; ospfh->router_id = oi->ospf->router_id; ospfh->checksum = 0; ospfh->area_id = oi->area->area_id; ospfh->auth_type = htons (ospf_auth_type (oi)); memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); stream_forward_endp (s, OSPF_HEADER_SIZE); } /* Make Authentication Data. */ static int ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh) { struct crypt_key *ck; switch (ospf_auth_type (oi)) { case OSPF_AUTH_NULL: /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ break; case OSPF_AUTH_SIMPLE: memcpy (ospfh->u.auth_data, OSPF_IF_PARAM (oi, auth_simple), OSPF_AUTH_SIMPLE_SIZE); break; case OSPF_AUTH_CRYPTOGRAPHIC: /* If key is not set, then set 0. */ if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt))) { ospfh->u.crypt.zero = 0; ospfh->u.crypt.key_id = 0; ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; } else { ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt))); ospfh->u.crypt.zero = 0; ospfh->u.crypt.key_id = ck->key_id; ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE; } /* note: the seq is done in ospf_make_md5_digest() */ break; default: /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ break; } return 0; } /* Fill rest of OSPF header. */ static void ospf_fill_header (struct ospf_interface *oi, struct stream *s, u_int16_t length) { struct ospf_header *ospfh; ospfh = (struct ospf_header *) STREAM_DATA (s); /* Fill length. */ ospfh->length = htons (length); /* Calculate checksum. */ if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) ospfh->checksum = in_cksum (ospfh, length); else ospfh->checksum = 0; /* Add Authentication Data. */ ospf_make_auth (oi, ospfh); } static int ospf_make_hello (struct ospf_interface *oi, struct stream *s) { struct ospf_neighbor *nbr; struct route_node *rn; u_int16_t length = OSPF_HELLO_MIN_SIZE; struct in_addr mask; unsigned long p; int flag = 0; /* Set netmask of interface. */ if (oi->type != OSPF_IFTYPE_POINTOPOINT && oi->type != OSPF_IFTYPE_VIRTUALLINK) masklen2ip (oi->address->prefixlen, &mask); else memset ((char *) &mask, 0, sizeof (struct in_addr)); stream_put_ipv4 (s, mask.s_addr); /* Set Hello Interval. */ if (OSPF_IF_PARAM (oi, fast_hello) == 0) stream_putw (s, OSPF_IF_PARAM (oi, v_hello)); else stream_putw (s, 0); /* hello-interval of 0 for fast-hellos */ if (IS_DEBUG_OSPF_EVENT) zlog_debug ("make_hello: options: %x, int: %s", OPTIONS(oi), IF_NAME (oi)); /* Set Options. */ stream_putc (s, OPTIONS (oi)); /* Set Router Priority. */ stream_putc (s, PRIORITY (oi)); /* Set Router Dead Interval. */ stream_putl (s, OSPF_IF_PARAM (oi, v_wait)); /* Set Designated Router. */ stream_put_ipv4 (s, DR (oi).s_addr); p = stream_get_endp (s); /* Set Backup Designated Router. */ stream_put_ipv4 (s, BDR (oi).s_addr); /* Add neighbor seen. */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (nbr->router_id.s_addr != 0) /* Ignore 0.0.0.0 node. */ if (nbr->state != NSM_Attempt) /* Ignore Down neighbor. */ if (nbr->state != NSM_Down) /* This is myself for DR election. */ if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) { /* Check neighbor is sane? */ if (nbr->d_router.s_addr != 0 && IPV4_ADDR_SAME (&nbr->d_router, &oi->address->u.prefix4) && IPV4_ADDR_SAME (&nbr->bd_router, &oi->address->u.prefix4)) flag = 1; stream_put_ipv4 (s, nbr->router_id.s_addr); length += 4; } /* Let neighbor generate BackupSeen. */ if (flag == 1) stream_putl_at (s, p, 0); /* ipv4 address, normally */ return length; } static int ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr, struct stream *s) { struct ospf_lsa *lsa; u_int16_t length = OSPF_DB_DESC_MIN_SIZE; u_char options; unsigned long pp; int i; struct ospf_lsdb *lsdb; /* Set Interface MTU. */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) stream_putw (s, 0); else stream_putw (s, oi->ifp->mtu); /* Set Options. */ options = OPTIONS (oi); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE)) SET_FLAG (options, OSPF_OPTION_O); #endif /* HAVE_OPAQUE_LSA */ stream_putc (s, options); /* DD flags */ pp = stream_get_endp (s); stream_putc (s, nbr->dd_flags); /* Set DD Sequence Number. */ stream_putl (s, nbr->dd_seqnum); /* shortcut unneeded walk of (empty) summary LSDBs */ if (ospf_db_summary_isempty (nbr)) goto empty; /* Describe LSA Header from Database Summary List. */ lsdb = &nbr->db_sum; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { struct route_table *table = lsdb->type[i].db; struct route_node *rn; for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = rn->info) != NULL) { #ifdef HAVE_OPAQUE_LSA if (IS_OPAQUE_LSA (lsa->data->type) && (! CHECK_FLAG (options, OSPF_OPTION_O))) { /* Suppress advertising opaque-informations. */ /* Remove LSA from DB summary list. */ ospf_lsdb_delete (lsdb, lsa); continue; } #endif /* HAVE_OPAQUE_LSA */ if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD)) { struct lsa_header *lsah; u_int16_t ls_age; /* DD packet overflows interface MTU. */ if (length + OSPF_LSA_HEADER_SIZE > ospf_packet_max (oi)) break; /* Keep pointer to LS age. */ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (s)); /* Proceed stream pointer. */ stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; /* Set LS age. */ ls_age = LS_AGE (lsa); lsah->ls_age = htons (ls_age); } /* Remove LSA from DB summary list. */ ospf_lsdb_delete (lsdb, lsa); } } /* Update 'More' bit */ if (ospf_db_summary_isempty (nbr)) { empty: if (nbr->state >= NSM_Exchange) { UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_M); /* Rewrite DD flags */ stream_putc_at (s, pp, nbr->dd_flags); } else { assert (IS_SET_DD_M(nbr->dd_flags)); } } return length; } static int ospf_make_ls_req_func (struct stream *s, u_int16_t *length, unsigned long delta, struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf_interface *oi; oi = nbr->oi; /* LS Request packet overflows interface MTU. */ if (*length + delta > ospf_packet_max(oi)) return 0; stream_putl (s, lsa->data->type); stream_put_ipv4 (s, lsa->data->id.s_addr); stream_put_ipv4 (s, lsa->data->adv_router.s_addr); ospf_lsa_unlock (&nbr->ls_req_last); nbr->ls_req_last = ospf_lsa_lock (lsa); *length += 12; return 1; } static int ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s) { struct ospf_lsa *lsa; u_int16_t length = OSPF_LS_REQ_MIN_SIZE; unsigned long delta = stream_get_endp(s)+12; struct route_table *table; struct route_node *rn; int i; struct ospf_lsdb *lsdb; lsdb = &nbr->ls_req; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { table = lsdb->type[i].db; for (rn = route_top (table); rn; rn = route_next (rn)) if ((lsa = (rn->info)) != NULL) if (ospf_make_ls_req_func (s, &length, delta, nbr, lsa) == 0) { route_unlock_node (rn); break; } } return length; } static int ls_age_increment (struct ospf_lsa *lsa, int delay) { int age; age = IS_LSA_MAXAGE (lsa) ? OSPF_LSA_MAXAGE : LS_AGE (lsa) + delay; return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age); } static int ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream *s) { struct ospf_lsa *lsa; struct listnode *node; u_int16_t length = 0; unsigned int size_noauth; unsigned long delta = stream_get_endp (s); unsigned long pp; int count = 0; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: Start"); pp = stream_get_endp (s); stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE); length += OSPF_LS_UPD_MIN_SIZE; /* Calculate amount of packet usable for data. */ size_noauth = stream_get_size(s) - ospf_packet_authspace(oi); while ((node = listhead (update)) != NULL) { struct lsa_header *lsah; u_int16_t ls_age; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: List Iteration %d", count); lsa = listgetdata (node); assert (lsa->data); /* Will it fit? */ if (length + delta + ntohs (lsa->data->length) > size_noauth) break; /* Keep pointer to LS age. */ lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (s)); /* Put LSA to Link State Request. */ stream_put (s, lsa->data, ntohs (lsa->data->length)); /* Set LS age. */ /* each hop must increment an lsa_age by transmit_delay of OSPF interface */ ls_age = ls_age_increment (lsa, OSPF_IF_PARAM (oi, transmit_delay)); lsah->ls_age = htons (ls_age); length += ntohs (lsa->data->length); count++; list_delete_node (update, node); ospf_lsa_unlock (&lsa); /* oi->ls_upd_queue */ } /* Now set #LSAs. */ stream_putl_at (s, pp, count); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_make_ls_upd: Stop"); return length; } static int ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s) { struct listnode *node, *nnode; u_int16_t length = OSPF_LS_ACK_MIN_SIZE; unsigned long delta = stream_get_endp(s) + 24; struct ospf_lsa *lsa; for (ALL_LIST_ELEMENTS (ack, node, nnode, lsa)) { assert (lsa); if (length + delta > ospf_packet_max (oi)) break; stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; listnode_delete (ack, lsa); ospf_lsa_unlock (&lsa); /* oi->ls_ack_direct.ls_ack */ } return length; } static void ospf_hello_send_sub (struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new (oi->ifp->mtu); /* Prepare OSPF common header. */ ospf_make_header (OSPF_MSG_HELLO, oi, op->s); /* Prepare OSPF Hello body. */ length += ospf_make_hello (oi, op->s); /* Fill OSPF header. */ ospf_fill_header (oi, op->s, length); /* Set packet length. */ op->length = length; op->dst.s_addr = addr; /* Add packet to the top of the interface output queue, so that they * can't get delayed by things like long queues of LS Update packets */ ospf_packet_add_top (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } static void ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma) { struct ospf_interface *oi; oi = nbr_nbma->oi; assert(oi); /* If this is passive interface, do not send OSPF Hello. */ if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) return; if (oi->type != OSPF_IFTYPE_NBMA) return; if (nbr_nbma->nbr != NULL && nbr_nbma->nbr->state != NSM_Down) return; if (PRIORITY(oi) == 0) return; if (nbr_nbma->priority == 0 && oi->state != ISM_DR && oi->state != ISM_Backup) return; ospf_hello_send_sub (oi, nbr_nbma->addr.s_addr); } int ospf_poll_timer (struct thread *thread) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = THREAD_ARG (thread); nbr_nbma->t_poll = NULL; if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Poll timer expire)", IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr)); ospf_poll_send (nbr_nbma); if (nbr_nbma->v_poll > 0) OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, nbr_nbma->v_poll); return 0; } int ospf_hello_reply_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_hello_reply = NULL; assert (nbr->oi); if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (hello-reply timer expire)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); ospf_hello_send_sub (nbr->oi, nbr->address.u.prefix4.s_addr); return 0; } /* Send OSPF Hello. */ void ospf_hello_send (struct ospf_interface *oi) { /* If this is passive interface, do not send OSPF Hello. */ if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE) return; if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_neighbor *nbr; struct route_node *rn; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (nbr != oi->nbr_self) if (nbr->state != NSM_Down) { /* RFC 2328 Section 9.5.1 If the router is not eligible to become Designated Router, it must periodically send Hello Packets to both the Designated Router and the Backup Designated Router (if they exist). */ if (PRIORITY(oi) == 0 && IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) && IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4)) continue; /* If the router is eligible to become Designated Router, it must periodically send Hello Packets to all neighbors that are also eligible. In addition, if the router is itself the Designated Router or Backup Designated Router, it must also send periodic Hello Packets to all other neighbors. */ if (nbr->priority == 0 && oi->state == ISM_DROther) continue; /* if oi->state == Waiting, send hello to all neighbors */ ospf_hello_send_sub (oi, nbr->address.u.prefix4.s_addr); } } else { /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) ospf_hello_send_sub (oi, oi->vl_data->peer_addr.s_addr); else ospf_hello_send_sub (oi, htonl (OSPF_ALLSPFROUTERS)); } } /* Send OSPF Database Description. */ void ospf_db_desc_send (struct ospf_neighbor *nbr) { struct ospf_interface *oi; struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; oi = nbr->oi; op = ospf_packet_new (oi->ifp->mtu); /* Prepare OSPF common header. */ ospf_make_header (OSPF_MSG_DB_DESC, oi, op->s); /* Prepare OSPF Database Description body. */ length += ospf_make_db_desc (oi, nbr, op->s); /* Fill OSPF header. */ ospf_fill_header (oi, op->s, length); /* Set packet length. */ op->length = length; /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else op->dst = nbr->address.u.prefix4; /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); /* Remove old DD packet, then copy new one and keep in neighbor structure. */ if (nbr->last_send) ospf_packet_free (nbr->last_send); nbr->last_send = ospf_packet_dup (op); quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts); } /* Re-send Database Description. */ void ospf_db_desc_resend (struct ospf_neighbor *nbr) { struct ospf_interface *oi; oi = nbr->oi; /* Add packet to the interface output queue. */ ospf_packet_add (oi, ospf_packet_dup (nbr->last_send)); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } /* Send Link State Request. */ void ospf_ls_req_send (struct ospf_neighbor *nbr) { struct ospf_interface *oi; struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; oi = nbr->oi; op = ospf_packet_new (oi->ifp->mtu); /* Prepare OSPF common header. */ ospf_make_header (OSPF_MSG_LS_REQ, oi, op->s); /* Prepare OSPF Link State Request body. */ length += ospf_make_ls_req (nbr, op->s); if (length == OSPF_HEADER_SIZE) { ospf_packet_free (op); return; } /* Fill OSPF header. */ ospf_fill_header (oi, op->s, length); /* Set packet length. */ op->length = length; /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else op->dst = nbr->address.u.prefix4; /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); /* Add Link State Request Retransmission Timer. */ OSPF_NSM_TIMER_ON (nbr->t_ls_req, ospf_ls_req_timer, nbr->v_ls_req); } /* Send Link State Update with an LSA. */ void ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa, int flag) { struct list *update; update = list_new (); listnode_add (update, lsa); ospf_ls_upd_send (nbr, update, flag); list_delete (update); } /* Determine size for packet. Must be at least big enough to accomodate next * LSA on list, which may be bigger than MTU size. * * Return pointer to new ospf_packet * NULL if we can not allocate, eg because LSA is bigger than imposed limit * on packet sizes (in which case offending LSA is deleted from update list) */ static struct ospf_packet * ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi) { struct ospf_lsa *lsa; struct listnode *ln; size_t size; static char warned = 0; lsa = listgetdata((ln = listhead (update))); assert (lsa->data); if ((OSPF_LS_UPD_MIN_SIZE + ntohs (lsa->data->length)) > ospf_packet_max (oi)) { if (!warned) { zlog_warn ("ospf_ls_upd_packet_new: oversized LSA encountered!" "will need to fragment. Not optimal. Try divide up" " your network with areas. Use 'debug ospf packet send'" " to see details, or look at 'show ip ospf database ..'"); warned = 1; } if (IS_DEBUG_OSPF_PACKET (0, SEND)) zlog_debug ("ospf_ls_upd_packet_new: oversized LSA id:%s," " %d bytes originated by %s, will be fragmented!", inet_ntoa (lsa->data->id), ntohs (lsa->data->length), inet_ntoa (lsa->data->adv_router)); /* * Allocate just enough to fit this LSA only, to avoid including other * LSAs in fragmented LSA Updates. */ size = ntohs (lsa->data->length) + (oi->ifp->mtu - ospf_packet_max (oi)) + OSPF_LS_UPD_MIN_SIZE; } else size = oi->ifp->mtu; if (size > OSPF_MAX_PACKET_SIZE) { zlog_warn ("ospf_ls_upd_packet_new: oversized LSA id:%s too big," " %d bytes, packet size %ld, dropping it completely." " OSPF routing is broken!", inet_ntoa (lsa->data->id), ntohs (lsa->data->length), (long int) size); list_delete_node (update, ln); return NULL; } /* IP header is built up separately by ospf_write(). This means, that we must * reduce the "affordable" size just calculated by length of an IP header. * This makes sure, that even if we manage to fill the payload with LSA data * completely, the final packet (our data plus IP header) still fits into * outgoing interface MTU. This correction isn't really meaningful for an * oversized LSA, but for consistency the correction is done for both cases. * * P.S. OSPF_MAX_PACKET_SIZE above already includes IP header size */ return ospf_packet_new (size - sizeof (struct ip)); } static void ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update, struct in_addr addr) { struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("listcount = %d, [%s]dst %s", listcount (update), IF_NAME(oi), inet_ntoa(addr)); op = ospf_ls_upd_packet_new (update, oi); /* Prepare OSPF common header. */ ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s); /* Prepare OSPF Link State Update body. * Includes Type-7 translation. */ length += ospf_make_ls_upd (oi, update, op->s); /* Fill OSPF header. */ ospf_fill_header (oi, op->s, length); /* Set packet length. */ op->length = length; /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT) op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else op->dst.s_addr = addr.s_addr; /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } static int ospf_ls_upd_send_queue_event (struct thread *thread) { struct ospf_interface *oi = THREAD_ARG(thread); struct route_node *rn; struct route_node *rnext; struct list *update; char again = 0; oi->t_ls_upd_event = NULL; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue start"); for (rn = route_top (oi->ls_upd_queue); rn; rn = rnext) { rnext = route_next (rn); if (rn->info == NULL) continue; update = (struct list *)rn->info; ospf_ls_upd_queue_send (oi, update, rn->p.u.prefix4); /* list might not be empty. */ if (listcount(update) == 0) { list_delete (rn->info); rn->info = NULL; route_unlock_node (rn); } else again = 1; } if (again != 0) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue: update lists not cleared," " %d nodes to try again, raising new event", again); oi->t_ls_upd_event = thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0); } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_ls_upd_send_queue stop"); return 0; } void ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag) { struct ospf_interface *oi; struct ospf_lsa *lsa; struct prefix_ipv4 p; struct route_node *rn; struct listnode *node; oi = nbr->oi; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) p.prefix = oi->vl_data->peer_addr; else if (oi->type == OSPF_IFTYPE_POINTOPOINT) p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); else if (flag == OSPF_SEND_PACKET_DIRECT) p.prefix = nbr->address.u.prefix4; else if (oi->state == ISM_DR || oi->state == ISM_Backup) p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS); else p.prefix.s_addr = htonl (OSPF_ALLDROUTERS); if (oi->type == OSPF_IFTYPE_NBMA) { if (flag == OSPF_SEND_PACKET_INDIRECT) zlog_warn ("* LS-Update is directly sent on NBMA network."); if (IPV4_ADDR_SAME(&oi->address->u.prefix4, &p.prefix.s_addr)) zlog_warn ("* LS-Update is sent to myself."); } rn = route_node_get (oi->ls_upd_queue, (struct prefix *) &p); if (rn->info == NULL) rn->info = list_new (); for (ALL_LIST_ELEMENTS_RO (update, node, lsa)) listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */ if (oi->t_ls_upd_event == NULL) oi->t_ls_upd_event = thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0); } static void ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack, struct in_addr dst) { struct ospf_packet *op; u_int16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new (oi->ifp->mtu); /* Prepare OSPF common header. */ ospf_make_header (OSPF_MSG_LS_ACK, oi, op->s); /* Prepare OSPF Link State Acknowledgment body. */ length += ospf_make_ls_ack (oi, ack, op->s); /* Fill OSPF header. */ ospf_fill_header (oi, op->s, length); /* Set packet length. */ op->length = length; /* Set destination IP address. */ op->dst = dst; /* Add packet to the interface output queue. */ ospf_packet_add (oi, op); /* Hook thread to write packet. */ OSPF_ISM_WRITE_ON (oi->ospf); } static int ospf_ls_ack_send_event (struct thread *thread) { struct ospf_interface *oi = THREAD_ARG (thread); oi->t_ls_ack_direct = NULL; while (listcount (oi->ls_ack_direct.ls_ack)) ospf_ls_ack_send_list (oi, oi->ls_ack_direct.ls_ack, oi->ls_ack_direct.dst); return 0; } void ospf_ls_ack_send (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { struct ospf_interface *oi = nbr->oi; if (listcount (oi->ls_ack_direct.ls_ack) == 0) oi->ls_ack_direct.dst = nbr->address.u.prefix4; listnode_add (oi->ls_ack_direct.ls_ack, ospf_lsa_lock (lsa)); if (oi->t_ls_ack_direct == NULL) oi->t_ls_ack_direct = thread_add_event (master, ospf_ls_ack_send_event, oi, 0); } /* Send Link State Acknowledgment delayed. */ void ospf_ls_ack_send_delayed (struct ospf_interface *oi) { struct in_addr dst; /* Decide destination address. */ /* RFC2328 Section 13.5 On non-broadcast networks, delayed Link State Acknowledgment packets must be unicast separately over each adjacency (i.e., neighbor whose state is >= Exchange). */ if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_neighbor *nbr; struct route_node *rn; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) while (listcount (oi->ls_ack)) ospf_ls_ack_send_list (oi, oi->ls_ack, nbr->address.u.prefix4); return; } if (oi->type == OSPF_IFTYPE_VIRTUALLINK) dst.s_addr = oi->vl_data->peer_addr.s_addr; else if (oi->state == ISM_DR || oi->state == ISM_Backup) dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else if (oi->type == OSPF_IFTYPE_POINTOPOINT) dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) dst.s_addr = htonl (OSPF_ALLSPFROUTERS); else dst.s_addr = htonl (OSPF_ALLDROUTERS); while (listcount (oi->ls_ack)) ospf_ls_ack_send_list (oi, oi->ls_ack, dst); } quagga-0.99.24.1/ospfd/ospf_network.c0000644000175000017500000002056312476520570014241 00000000000000/* * OSPF network related functions * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "sockunion.h" #include "log.h" #include "sockopt.h" #include "privs.h" extern struct zebra_privs_t ospfd_privs; #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_dump.h" /* Join to the OSPF ALL SPF ROUTERS multicast group. */ int ospf_if_add_allspfrouters (struct ospf *top, struct prefix *p, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllSPFRouters): %s; perhaps a kernel limit " "on # of multicast group memberships has been exceeded?", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] join AllSPFRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_drop_allspfrouters (struct ospf *top, struct prefix *p, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, htonl (OSPF_ALLSPFROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllSPFRouters): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] leave AllSPFRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } /* Join to the OSPF ALL Designated ROUTERS multicast group. */ int ospf_if_add_alldrouters (struct ospf *top, struct prefix *p, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_ADD_MEMBERSHIP, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllDRouters): %s; perhaps a kernel limit " "on # of multicast group memberships has been exceeded?", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] join AllDRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_drop_alldrouters (struct ospf *top, struct prefix *p, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (top->fd, IP_DROP_MEMBERSHIP, htonl (OSPF_ALLDROUTERS), ifindex); if (ret < 0) zlog_warn ("can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %s, " "ifindex %u, AllDRouters): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); else zlog_debug ("interface %s [%u] leave AllDRouters Multicast group.", inet_ntoa (p->u.prefix4), ifindex); return ret; } int ospf_if_ipmulticast (struct ospf *top, struct prefix *p, unsigned int ifindex) { u_char val; int ret, len; val = 0; len = sizeof (val); /* Prevent receiving self-origined multicast packets. */ ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val, len); if (ret < 0) zlog_warn ("can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s", top->fd, safe_strerror(errno)); /* Explicitly set multicast ttl to 1 -- endo. */ val = 1; ret = setsockopt (top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len); if (ret < 0) zlog_warn ("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s", top->fd, safe_strerror (errno)); ret = setsockopt_ipv4_multicast_if (top->fd, ifindex); if (ret < 0) zlog_warn("can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, " "ifindex %u): %s", top->fd, inet_ntoa(p->u.prefix4), ifindex, safe_strerror(errno)); return ret; } int ospf_sock_init (void) { int ospf_sock; int ret, hincl = 1; if ( ospfd_privs.change (ZPRIVS_RAISE) ) zlog_err ("ospf_sock_init: could not raise privs, %s", safe_strerror (errno) ); ospf_sock = socket (AF_INET, SOCK_RAW, IPPROTO_OSPFIGP); if (ospf_sock < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_err ("ospf_read_sock_init: socket: %s", safe_strerror (save_errno)); exit(1); } #ifdef IP_HDRINCL /* we will include IP header with packet */ ret = setsockopt (ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof (hincl)); if (ret < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_warn ("Can't set IP_HDRINCL option for fd %d: %s", ospf_sock, safe_strerror(save_errno)); } #elif defined (IPTOS_PREC_INTERNETCONTROL) #warning "IP_HDRINCL not available on this system" #warning "using IPTOS_PREC_INTERNETCONTROL" ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL); if (ret < 0) { int save_errno = errno; if ( ospfd_privs.change (ZPRIVS_LOWER) ) zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); zlog_warn ("can't set sockopt IP_TOS %d to socket %d: %s", tos, ospf_sock, safe_strerror(save_errno)); close (ospf_sock); /* Prevent sd leak. */ return ret; } #else /* !IPTOS_PREC_INTERNETCONTROL */ #warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL" zlog_warn ("IP_HDRINCL option not available"); #endif /* IP_HDRINCL */ ret = setsockopt_ifindex (AF_INET, ospf_sock, 1); if (ret < 0) zlog_warn ("Can't set pktinfo option for fd %d", ospf_sock); if (ospfd_privs.change (ZPRIVS_LOWER)) { zlog_err ("ospf_sock_init: could not lower privs, %s", safe_strerror (errno) ); } return ospf_sock; } void ospf_adjust_sndbuflen (struct ospf * ospf, unsigned int buflen) { int ret, newbuflen; /* Check if any work has to be done at all. */ if (ospf->maxsndbuflen >= buflen) return; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("%s: adjusting OSPF send buffer size to %d", __func__, buflen); if (ospfd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs, %s", __func__, safe_strerror (errno)); /* Now we try to set SO_SNDBUF to what our caller has requested * (the MTU of a newly added interface). However, if the OS has * truncated the actual buffer size to somewhat less size, try * to detect it and update our records appropriately. The OS * may allocate more buffer space, than requested, this isn't * a error. */ ret = setsockopt_so_sendbuf (ospf->fd, buflen); newbuflen = getsockopt_so_sendbuf (ospf->fd); if (ret < 0 || newbuflen < 0 || newbuflen < (int) buflen) zlog_warn ("%s: tried to set SO_SNDBUF to %u, but got %d", __func__, buflen, newbuflen); if (newbuflen >= 0) ospf->maxsndbuflen = (unsigned int)newbuflen; else zlog_warn ("%s: failed to get SO_SNDBUF", __func__); if (ospfd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs, %s", __func__, safe_strerror (errno)); } quagga-0.99.24.1/ospfd/ospf_dump.c0000644000175000017500000013544112476520570013517 00000000000000/* * OSPFd dump routine. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "thread.h" #include "prefix.h" #include "command.h" #include "stream.h" #include "log.h" #include "sockopt.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_network.h" const struct message ospf_ism_state_msg[] = { { ISM_DependUpon, "DependUpon" }, { ISM_Down, "Down" }, { ISM_Loopback, "Loopback" }, { ISM_Waiting, "Waiting" }, { ISM_PointToPoint, "Point-To-Point" }, { ISM_DROther, "DROther" }, { ISM_Backup, "Backup" }, { ISM_DR, "DR" }, }; const int ospf_ism_state_msg_max = OSPF_ISM_STATE_MAX; const struct message ospf_nsm_state_msg[] = { { NSM_DependUpon, "DependUpon" }, { NSM_Deleted, "Deleted" }, { NSM_Down, "Down" }, { NSM_Attempt, "Attempt" }, { NSM_Init, "Init" }, { NSM_TwoWay, "2-Way" }, { NSM_ExStart, "ExStart" }, { NSM_Exchange, "Exchange" }, { NSM_Loading, "Loading" }, { NSM_Full, "Full" }, }; const int ospf_nsm_state_msg_max = OSPF_NSM_STATE_MAX; const struct message ospf_lsa_type_msg[] = { { OSPF_UNKNOWN_LSA, "unknown" }, { OSPF_ROUTER_LSA, "router-LSA" }, { OSPF_NETWORK_LSA, "network-LSA" }, { OSPF_SUMMARY_LSA, "summary-LSA" }, { OSPF_ASBR_SUMMARY_LSA, "summary-LSA" }, { OSPF_AS_EXTERNAL_LSA, "AS-external-LSA" }, { OSPF_GROUP_MEMBER_LSA, "GROUP MEMBER LSA" }, { OSPF_AS_NSSA_LSA, "NSSA-LSA" }, { 8, "Type-8 LSA" }, { OSPF_OPAQUE_LINK_LSA, "Link-Local Opaque-LSA" }, { OSPF_OPAQUE_AREA_LSA, "Area-Local Opaque-LSA" }, { OSPF_OPAQUE_AS_LSA, "AS-external Opaque-LSA" }, }; const int ospf_lsa_type_msg_max = OSPF_MAX_LSA; const struct message ospf_link_state_id_type_msg[] = { { OSPF_UNKNOWN_LSA, "(unknown)" }, { OSPF_ROUTER_LSA, "" }, { OSPF_NETWORK_LSA, "(address of Designated Router)" }, { OSPF_SUMMARY_LSA, "(summary Network Number)" }, { OSPF_ASBR_SUMMARY_LSA, "(AS Boundary Router address)" }, { OSPF_AS_EXTERNAL_LSA, "(External Network Number)" }, { OSPF_GROUP_MEMBER_LSA, "(Group membership information)" }, { OSPF_AS_NSSA_LSA, "(External Network Number for NSSA)" }, { 8, "(Type-8 LSID)" }, { OSPF_OPAQUE_LINK_LSA, "(Link-Local Opaque-Type/ID)" }, { OSPF_OPAQUE_AREA_LSA, "(Area-Local Opaque-Type/ID)" }, { OSPF_OPAQUE_AS_LSA, "(AS-external Opaque-Type/ID)" }, }; const int ospf_link_state_id_type_msg_max = OSPF_MAX_LSA; const struct message ospf_network_type_msg[] = { { OSPF_IFTYPE_NONE, "NONE" }, { OSPF_IFTYPE_POINTOPOINT, "Point-to-Point" }, { OSPF_IFTYPE_BROADCAST, "Broadcast" }, { OSPF_IFTYPE_NBMA, "NBMA" }, { OSPF_IFTYPE_POINTOMULTIPOINT, "Point-to-MultiPoint" }, { OSPF_IFTYPE_VIRTUALLINK, "Virtual-Link" }, }; const int ospf_network_type_msg_max = OSPF_IFTYPE_MAX; /* AuType */ const struct message ospf_auth_type_str[] = { { OSPF_AUTH_NULL, "Null" }, { OSPF_AUTH_SIMPLE, "Simple" }, { OSPF_AUTH_CRYPTOGRAPHIC, "Cryptographic" }, }; const size_t ospf_auth_type_str_max = sizeof (ospf_auth_type_str) / sizeof (ospf_auth_type_str[0]); /* Configuration debug option variables. */ unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; unsigned long conf_debug_ospf_event = 0; unsigned long conf_debug_ospf_ism = 0; unsigned long conf_debug_ospf_nsm = 0; unsigned long conf_debug_ospf_lsa = 0; unsigned long conf_debug_ospf_zebra = 0; unsigned long conf_debug_ospf_nssa = 0; /* Enable debug option variables -- valid only session. */ unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; unsigned long term_debug_ospf_event = 0; unsigned long term_debug_ospf_ism = 0; unsigned long term_debug_ospf_nsm = 0; unsigned long term_debug_ospf_lsa = 0; unsigned long term_debug_ospf_zebra = 0; unsigned long term_debug_ospf_nssa = 0; const char * ospf_redist_string(u_int route_type) { return (route_type == ZEBRA_ROUTE_MAX) ? "Default" : zebra_route_string(route_type); } #define OSPF_AREA_STRING_MAXLEN 16 const char * ospf_area_name_string (struct ospf_area *area) { static char buf[OSPF_AREA_STRING_MAXLEN] = ""; u_int32_t area_id; if (!area) return "-"; area_id = ntohl (area->area_id.s_addr); snprintf (buf, OSPF_AREA_STRING_MAXLEN, "%d.%d.%d.%d", (area_id >> 24) & 0xff, (area_id >> 16) & 0xff, (area_id >> 8) & 0xff, area_id & 0xff); return buf; } #define OSPF_AREA_DESC_STRING_MAXLEN 23 const char * ospf_area_desc_string (struct ospf_area *area) { static char buf[OSPF_AREA_DESC_STRING_MAXLEN] = ""; u_char type; if (!area) return "(incomplete)"; type = area->external_routing; switch (type) { case OSPF_AREA_NSSA: snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [NSSA]", ospf_area_name_string (area)); break; case OSPF_AREA_STUB: snprintf (buf, OSPF_AREA_DESC_STRING_MAXLEN, "%s [Stub]", ospf_area_name_string (area)); break; default: return ospf_area_name_string (area); } return buf; } #define OSPF_IF_STRING_MAXLEN 40 const char * ospf_if_name_string (struct ospf_interface *oi) { static char buf[OSPF_IF_STRING_MAXLEN] = ""; u_int32_t ifaddr; if (!oi) return "inactive"; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) return oi->ifp->name; ifaddr = ntohl (oi->address->u.prefix4.s_addr); snprintf (buf, OSPF_IF_STRING_MAXLEN, "%s:%d.%d.%d.%d", oi->ifp->name, (ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff, (ifaddr >> 8) & 0xff, ifaddr & 0xff); return buf; } void ospf_nbr_state_message (struct ospf_neighbor *nbr, char *buf, size_t size) { int state; struct ospf_interface *oi = nbr->oi; if (IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4)) state = ISM_DR; else if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) state = ISM_Backup; else state = ISM_DROther; memset (buf, 0, size); snprintf (buf, size, "%s/%s", LOOKUP (ospf_nsm_state_msg, nbr->state), LOOKUP (ospf_ism_state_msg, state)); } const char * ospf_timeval_dump (struct timeval *t, char *buf, size_t size) { /* Making formatted timer strings. */ #define MINUTE_IN_SECONDS 60 #define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS) #define DAY_IN_SECONDS (24*HOUR_IN_SECONDS) #define WEEK_IN_SECONDS (7*DAY_IN_SECONDS) unsigned long w, d, h, m, s, ms, us; if (!t) return "inactive"; w = d = h = m = s = ms = us = 0; memset (buf, 0, size); us = t->tv_usec; if (us >= 1000) { ms = us / 1000; us %= 1000; } if (ms >= 1000) { t->tv_sec += ms / 1000; ms %= 1000; } if (t->tv_sec > WEEK_IN_SECONDS) { w = t->tv_sec / WEEK_IN_SECONDS; t->tv_sec -= w * WEEK_IN_SECONDS; } if (t->tv_sec > DAY_IN_SECONDS) { d = t->tv_sec / DAY_IN_SECONDS; t->tv_sec -= d * DAY_IN_SECONDS; } if (t->tv_sec >= HOUR_IN_SECONDS) { h = t->tv_sec / HOUR_IN_SECONDS; t->tv_sec -= h * HOUR_IN_SECONDS; } if (t->tv_sec >= MINUTE_IN_SECONDS) { m = t->tv_sec / MINUTE_IN_SECONDS; t->tv_sec -= m * MINUTE_IN_SECONDS; } if (w > 99) snprintf (buf, size, "%ldw%1ldd", w, d); else if (w) snprintf (buf, size, "%ldw%1ldd%02ldh", w, d, h); else if (d) snprintf (buf, size, "%1ldd%02ldh%02ldm", d, h, m); else if (h) snprintf (buf, size, "%ldh%02ldm%02lds", h, m, t->tv_sec); else if (m) snprintf (buf, size, "%ldm%02lds", m, t->tv_sec); else if (ms) snprintf (buf, size, "%ld.%03lds", t->tv_sec, ms); else snprintf (buf, size, "%ld usecs", t->tv_usec); return buf; } const char * ospf_timer_dump (struct thread *t, char *buf, size_t size) { struct timeval result; if (!t) return "inactive"; result = tv_sub (t->u.sands, recent_relative_time()); return ospf_timeval_dump (&result, buf, size); } #define OSPF_OPTION_STR_MAXLEN 24 char * ospf_options_dump (u_char options) { static char buf[OSPF_OPTION_STR_MAXLEN]; snprintf (buf, OSPF_OPTION_STR_MAXLEN, "*|%s|%s|%s|%s|%s|%s|*", (options & OSPF_OPTION_O) ? "O" : "-", (options & OSPF_OPTION_DC) ? "DC" : "-", (options & OSPF_OPTION_EA) ? "EA" : "-", (options & OSPF_OPTION_NP) ? "N/P" : "-", (options & OSPF_OPTION_MC) ? "MC" : "-", (options & OSPF_OPTION_E) ? "E" : "-"); return buf; } static void ospf_packet_hello_dump (struct stream *s, u_int16_t length) { struct ospf_hello *hello; int i; hello = (struct ospf_hello *) STREAM_PNT (s); zlog_debug ("Hello"); zlog_debug (" NetworkMask %s", inet_ntoa (hello->network_mask)); zlog_debug (" HelloInterval %d", ntohs (hello->hello_interval)); zlog_debug (" Options %d (%s)", hello->options, ospf_options_dump (hello->options)); zlog_debug (" RtrPriority %d", hello->priority); zlog_debug (" RtrDeadInterval %ld", (u_long)ntohl (hello->dead_interval)); zlog_debug (" DRouter %s", inet_ntoa (hello->d_router)); zlog_debug (" BDRouter %s", inet_ntoa (hello->bd_router)); length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; zlog_debug (" # Neighbors %d", length / 4); for (i = 0; length > 0; i++, length -= sizeof (struct in_addr)) zlog_debug (" Neighbor %s", inet_ntoa (hello->neighbors[i])); } static char * ospf_dd_flags_dump (u_char flags, char *buf, size_t size) { memset (buf, 0, size); snprintf (buf, size, "%s|%s|%s", (flags & OSPF_DD_FLAG_I) ? "I" : "-", (flags & OSPF_DD_FLAG_M) ? "M" : "-", (flags & OSPF_DD_FLAG_MS) ? "MS" : "-"); return buf; } void ospf_lsa_header_dump (struct lsa_header *lsah) { const char *lsah_type = LOOKUP (ospf_lsa_type_msg, lsah->type); zlog_debug (" LSA Header"); zlog_debug (" LS age %d", ntohs (lsah->ls_age)); zlog_debug (" Options %d (%s)", lsah->options, ospf_options_dump (lsah->options)); zlog_debug (" LS type %d (%s)", lsah->type, (lsah->type ? lsah_type : "unknown type")); zlog_debug (" Link State ID %s", inet_ntoa (lsah->id)); zlog_debug (" Advertising Router %s", inet_ntoa (lsah->adv_router)); zlog_debug (" LS sequence number 0x%lx", (u_long)ntohl (lsah->ls_seqnum)); zlog_debug (" LS checksum 0x%x", ntohs (lsah->checksum)); zlog_debug (" length %d", ntohs (lsah->length)); } static char * ospf_router_lsa_flags_dump (u_char flags, char *buf, size_t size) { memset (buf, 0, size); snprintf (buf, size, "%s|%s|%s", (flags & ROUTER_LSA_VIRTUAL) ? "V" : "-", (flags & ROUTER_LSA_EXTERNAL) ? "E" : "-", (flags & ROUTER_LSA_BORDER) ? "B" : "-"); return buf; } static void ospf_router_lsa_dump (struct stream *s, u_int16_t length) { char buf[BUFSIZ]; struct router_lsa *rl; int i, len; rl = (struct router_lsa *) STREAM_PNT (s); zlog_debug (" Router-LSA"); zlog_debug (" flags %s", ospf_router_lsa_flags_dump (rl->flags, buf, BUFSIZ)); zlog_debug (" # links %d", ntohs (rl->links)); len = ntohs (rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; for (i = 0; len > 0; i++) { zlog_debug (" Link ID %s", inet_ntoa (rl->link[i].link_id)); zlog_debug (" Link Data %s", inet_ntoa (rl->link[i].link_data)); zlog_debug (" Type %d", (u_char) rl->link[i].type); zlog_debug (" TOS %d", (u_char) rl->link[i].tos); zlog_debug (" metric %d", ntohs (rl->link[i].metric)); len -= 12; } } static void ospf_network_lsa_dump (struct stream *s, u_int16_t length) { struct network_lsa *nl; int i, cnt; nl = (struct network_lsa *) STREAM_PNT (s); cnt = (ntohs (nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; zlog_debug (" Network-LSA"); /* zlog_debug ("LSA total size %d", ntohs (nl->header.length)); zlog_debug ("Network-LSA size %d", ntohs (nl->header.length) - OSPF_LSA_HEADER_SIZE); */ zlog_debug (" Network Mask %s", inet_ntoa (nl->mask)); zlog_debug (" # Attached Routers %d", cnt); for (i = 0; i < cnt; i++) zlog_debug (" Attached Router %s", inet_ntoa (nl->routers[i])); } static void ospf_summary_lsa_dump (struct stream *s, u_int16_t length) { struct summary_lsa *sl; int size; int i; sl = (struct summary_lsa *) STREAM_PNT (s); zlog_debug (" Summary-LSA"); zlog_debug (" Network Mask %s", inet_ntoa (sl->mask)); size = ntohs (sl->header.length) - OSPF_LSA_HEADER_SIZE - 4; for (i = 0; size > 0; size -= 4, i++) zlog_debug (" TOS=%d metric %d", sl->tos, GET_METRIC (sl->metric)); } static void ospf_as_external_lsa_dump (struct stream *s, u_int16_t length) { struct as_external_lsa *al; int size; int i; al = (struct as_external_lsa *) STREAM_PNT (s); zlog_debug (" %s", ospf_lsa_type_msg[al->header.type].str); zlog_debug (" Network Mask %s", inet_ntoa (al->mask)); size = ntohs (al->header.length) - OSPF_LSA_HEADER_SIZE -4; for (i = 0; size > 0; size -= 12, i++) { zlog_debug (" bit %s TOS=%d metric %d", IS_EXTERNAL_METRIC (al->e[i].tos) ? "E" : "-", al->e[i].tos & 0x7f, GET_METRIC (al->e[i].metric)); zlog_debug (" Forwarding address %s", inet_ntoa (al->e[i].fwd_addr)); zlog_debug (" External Route Tag %d", al->e[i].route_tag); } } static void ospf_lsa_header_list_dump (struct stream *s, u_int16_t length) { struct lsa_header *lsa; zlog_debug (" # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE); /* LSA Headers. */ while (length > 0) { lsa = (struct lsa_header *) STREAM_PNT (s); ospf_lsa_header_dump (lsa); stream_forward_getp (s, OSPF_LSA_HEADER_SIZE); length -= OSPF_LSA_HEADER_SIZE; } } static void ospf_packet_db_desc_dump (struct stream *s, u_int16_t length) { struct ospf_db_desc *dd; char dd_flags[8]; u_int32_t gp; gp = stream_get_getp (s); dd = (struct ospf_db_desc *) STREAM_PNT (s); zlog_debug ("Database Description"); zlog_debug (" Interface MTU %d", ntohs (dd->mtu)); zlog_debug (" Options %d (%s)", dd->options, ospf_options_dump (dd->options)); zlog_debug (" Flags %d (%s)", dd->flags, ospf_dd_flags_dump (dd->flags, dd_flags, sizeof dd_flags)); zlog_debug (" Sequence Number 0x%08lx", (u_long)ntohl (dd->dd_seqnum)); length -= OSPF_HEADER_SIZE + OSPF_DB_DESC_MIN_SIZE; stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE); ospf_lsa_header_list_dump (s, length); stream_set_getp (s, gp); } static void ospf_packet_ls_req_dump (struct stream *s, u_int16_t length) { u_int32_t sp; u_int32_t ls_type; struct in_addr ls_id; struct in_addr adv_router; sp = stream_get_getp (s); length -= OSPF_HEADER_SIZE; zlog_debug ("Link State Request"); zlog_debug (" # Requests %d", length / 12); for (; length > 0; length -= 12) { ls_type = stream_getl (s); ls_id.s_addr = stream_get_ipv4 (s); adv_router.s_addr = stream_get_ipv4 (s); zlog_debug (" LS type %d", ls_type); zlog_debug (" Link State ID %s", inet_ntoa (ls_id)); zlog_debug (" Advertising Router %s", inet_ntoa (adv_router)); } stream_set_getp (s, sp); } static void ospf_packet_ls_upd_dump (struct stream *s, u_int16_t length) { u_int32_t sp; struct lsa_header *lsa; int lsa_len; u_int32_t count; length -= OSPF_HEADER_SIZE; sp = stream_get_getp (s); count = stream_getl (s); length -= 4; zlog_debug ("Link State Update"); zlog_debug (" # LSAs %d", count); while (length > 0 && count > 0) { if (length < OSPF_HEADER_SIZE || length % 4 != 0) { zlog_debug (" Remaining %d bytes; Incorrect length.", length); break; } lsa = (struct lsa_header *) STREAM_PNT (s); lsa_len = ntohs (lsa->length); ospf_lsa_header_dump (lsa); switch (lsa->type) { case OSPF_ROUTER_LSA: ospf_router_lsa_dump (s, length); break; case OSPF_NETWORK_LSA: ospf_network_lsa_dump (s, length); break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: ospf_summary_lsa_dump (s, length); break; case OSPF_AS_EXTERNAL_LSA: ospf_as_external_lsa_dump (s, length); break; case OSPF_AS_NSSA_LSA: ospf_as_external_lsa_dump (s, length); break; #ifdef HAVE_OPAQUE_LSA case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: ospf_opaque_lsa_dump (s, length); break; #endif /* HAVE_OPAQUE_LSA */ default: break; } stream_forward_getp (s, lsa_len); length -= lsa_len; count--; } stream_set_getp (s, sp); } static void ospf_packet_ls_ack_dump (struct stream *s, u_int16_t length) { u_int32_t sp; length -= OSPF_HEADER_SIZE; sp = stream_get_getp (s); zlog_debug ("Link State Acknowledgment"); ospf_lsa_header_list_dump (s, length); stream_set_getp (s, sp); } /* Expects header to be in host order */ void ospf_ip_header_dump (struct ip *iph) { /* IP Header dump. */ zlog_debug ("ip_v %d", iph->ip_v); zlog_debug ("ip_hl %d", iph->ip_hl); zlog_debug ("ip_tos %d", iph->ip_tos); zlog_debug ("ip_len %d", iph->ip_len); zlog_debug ("ip_id %u", (u_int32_t) iph->ip_id); zlog_debug ("ip_off %u", (u_int32_t) iph->ip_off); zlog_debug ("ip_ttl %d", iph->ip_ttl); zlog_debug ("ip_p %d", iph->ip_p); zlog_debug ("ip_sum 0x%x", (u_int32_t) iph->ip_sum); zlog_debug ("ip_src %s", inet_ntoa (iph->ip_src)); zlog_debug ("ip_dst %s", inet_ntoa (iph->ip_dst)); } static void ospf_header_dump (struct ospf_header *ospfh) { char buf[9]; u_int16_t auth_type = ntohs (ospfh->auth_type); zlog_debug ("Header"); zlog_debug (" Version %d", ospfh->version); zlog_debug (" Type %d (%s)", ospfh->type, LOOKUP (ospf_packet_type_str, ospfh->type)); zlog_debug (" Packet Len %d", ntohs (ospfh->length)); zlog_debug (" Router ID %s", inet_ntoa (ospfh->router_id)); zlog_debug (" Area ID %s", inet_ntoa (ospfh->area_id)); zlog_debug (" Checksum 0x%x", ntohs (ospfh->checksum)); zlog_debug (" AuType %s", LOOKUP (ospf_auth_type_str, auth_type)); switch (auth_type) { case OSPF_AUTH_NULL: break; case OSPF_AUTH_SIMPLE: memset (buf, 0, 9); strncpy (buf, (char *) ospfh->u.auth_data, 8); zlog_debug (" Simple Password %s", buf); break; case OSPF_AUTH_CRYPTOGRAPHIC: zlog_debug (" Cryptographic Authentication"); zlog_debug (" Key ID %d", ospfh->u.crypt.key_id); zlog_debug (" Auth Data Len %d", ospfh->u.crypt.auth_data_len); zlog_debug (" Sequence number %ld", (u_long)ntohl (ospfh->u.crypt.crypt_seqnum)); break; default: zlog_debug ("* This is not supported authentication type"); break; } } void ospf_packet_dump (struct stream *s) { struct ospf_header *ospfh; unsigned long gp; /* Preserve pointer. */ gp = stream_get_getp (s); /* OSPF Header dump. */ ospfh = (struct ospf_header *) STREAM_PNT (s); /* Until detail flag is set, return. */ if (!(term_debug_ospf_packet[ospfh->type - 1] & OSPF_DEBUG_DETAIL)) return; /* Show OSPF header detail. */ ospf_header_dump (ospfh); stream_forward_getp (s, OSPF_HEADER_SIZE); switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_packet_hello_dump (s, ntohs (ospfh->length)); break; case OSPF_MSG_DB_DESC: ospf_packet_db_desc_dump (s, ntohs (ospfh->length)); break; case OSPF_MSG_LS_REQ: ospf_packet_ls_req_dump (s, ntohs (ospfh->length)); break; case OSPF_MSG_LS_UPD: ospf_packet_ls_upd_dump (s, ntohs (ospfh->length)); break; case OSPF_MSG_LS_ACK: ospf_packet_ls_ack_dump (s, ntohs (ospfh->length)); break; default: break; } stream_set_getp (s, gp); } /* [no] debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) [send|recv [detail]] */ DEFUN (debug_ospf_packet, debug_ospf_packet_all_cmd, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", DEBUG_STR OSPF_STR "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n") { int type = 0; int flag = 0; int i; assert (argc > 0); /* Check packet type. */ if (strncmp (argv[0], "h", 1) == 0) type = OSPF_DEBUG_HELLO; else if (strncmp (argv[0], "d", 1) == 0) type = OSPF_DEBUG_DB_DESC; else if (strncmp (argv[0], "ls-r", 4) == 0) type = OSPF_DEBUG_LS_REQ; else if (strncmp (argv[0], "ls-u", 4) == 0) type = OSPF_DEBUG_LS_UPD; else if (strncmp (argv[0], "ls-a", 4) == 0) type = OSPF_DEBUG_LS_ACK; else if (strncmp (argv[0], "a", 1) == 0) type = OSPF_DEBUG_ALL; /* Default, both send and recv. */ if (argc == 1) flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV; /* send or recv. */ if (argc >= 2) { if (strncmp (argv[1], "s", 1) == 0) flag = OSPF_DEBUG_SEND; else if (strncmp (argv[1], "r", 1) == 0) flag = OSPF_DEBUG_RECV; else if (strncmp (argv[1], "d", 1) == 0) flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; } /* detail. */ if (argc == 3) if (strncmp (argv[2], "d", 1) == 0) flag |= OSPF_DEBUG_DETAIL; for (i = 0; i < 5; i++) if (type & (0x01 << i)) { if (vty->node == CONFIG_NODE) DEBUG_PACKET_ON (i, flag); else TERM_DEBUG_PACKET_ON (i, flag); } return CMD_SUCCESS; } ALIAS (debug_ospf_packet, debug_ospf_packet_send_recv_cmd, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail information\n") ALIAS (debug_ospf_packet, debug_ospf_packet_send_recv_detail_cmd, "debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") DEFUN (no_debug_ospf_packet, no_debug_ospf_packet_all_cmd, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all)", NO_STR DEBUG_STR OSPF_STR "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n") { int type = 0; int flag = 0; int i; assert (argc > 0); /* Check packet type. */ if (strncmp (argv[0], "h", 1) == 0) type = OSPF_DEBUG_HELLO; else if (strncmp (argv[0], "d", 1) == 0) type = OSPF_DEBUG_DB_DESC; else if (strncmp (argv[0], "ls-r", 4) == 0) type = OSPF_DEBUG_LS_REQ; else if (strncmp (argv[0], "ls-u", 4) == 0) type = OSPF_DEBUG_LS_UPD; else if (strncmp (argv[0], "ls-a", 4) == 0) type = OSPF_DEBUG_LS_ACK; else if (strncmp (argv[0], "a", 1) == 0) type = OSPF_DEBUG_ALL; /* Default, both send and recv. */ if (argc == 1) flag = OSPF_DEBUG_SEND | OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL ; /* send or recv. */ if (argc == 2) { if (strncmp (argv[1], "s", 1) == 0) flag = OSPF_DEBUG_SEND | OSPF_DEBUG_DETAIL; else if (strncmp (argv[1], "r", 1) == 0) flag = OSPF_DEBUG_RECV | OSPF_DEBUG_DETAIL; else if (strncmp (argv[1], "d", 1) == 0) flag = OSPF_DEBUG_DETAIL; } /* detail. */ if (argc == 3) if (strncmp (argv[2], "d", 1) == 0) flag = OSPF_DEBUG_DETAIL; for (i = 0; i < 5; i++) if (type & (0x01 << i)) { if (vty->node == CONFIG_NODE) DEBUG_PACKET_OFF (i, flag); else TERM_DEBUG_PACKET_OFF (i, flag); } #ifdef DEBUG /* for (i = 0; i < 5; i++) zlog_debug ("flag[%d] = %d", i, ospf_debug_packet[i]); */ #endif /* DEBUG */ return CMD_SUCCESS; } ALIAS (no_debug_ospf_packet, no_debug_ospf_packet_send_recv_cmd, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv|detail)", NO_STR "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") ALIAS (no_debug_ospf_packet, no_debug_ospf_packet_send_recv_detail_cmd, "no debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) (detail|)", NO_STR "Debugging functions\n" "OSPF information\n" "OSPF packets\n" "OSPF Hello\n" "OSPF Database Description\n" "OSPF Link State Request\n" "OSPF Link State Update\n" "OSPF Link State Acknowledgment\n" "OSPF all packets\n" "Packet sent\n" "Packet received\n" "Detail Information\n") DEFUN (debug_ospf_ism, debug_ospf_ism_cmd, "debug ospf ism", DEBUG_STR OSPF_STR "OSPF Interface State Machine\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_ON (ism, ISM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) DEBUG_ON (ism, ISM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) DEBUG_ON (ism, ISM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) DEBUG_ON (ism, ISM_TIMERS); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_ON (ism, ISM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) TERM_DEBUG_ON (ism, ISM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) TERM_DEBUG_ON (ism, ISM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) TERM_DEBUG_ON (ism, ISM_TIMERS); } return CMD_SUCCESS; } ALIAS (debug_ospf_ism, debug_ospf_ism_sub_cmd, "debug ospf ism (status|events|timers)", DEBUG_STR OSPF_STR "OSPF Interface State Machine\n" "ISM Status Information\n" "ISM Event Information\n" "ISM TImer Information\n") DEFUN (no_debug_ospf_ism, no_debug_ospf_ism_cmd, "no debug ospf ism", NO_STR DEBUG_STR OSPF_STR "OSPF Interface State Machine") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_OFF (ism, ISM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) DEBUG_OFF (ism, ISM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) DEBUG_OFF (ism, ISM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) DEBUG_OFF (ism, ISM_TIMERS); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_OFF (ism, ISM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) TERM_DEBUG_OFF (ism, ISM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) TERM_DEBUG_OFF (ism, ISM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) TERM_DEBUG_OFF (ism, ISM_TIMERS); } return CMD_SUCCESS; } ALIAS (no_debug_ospf_ism, no_debug_ospf_ism_sub_cmd, "no debug ospf ism (status|events|timers)", NO_STR "Debugging functions\n" "OSPF information\n" "OSPF Interface State Machine\n" "ISM Status Information\n" "ISM Event Information\n" "ISM Timer Information\n") DEFUN (debug_ospf_nsm, debug_ospf_nsm_cmd, "debug ospf nsm", DEBUG_STR OSPF_STR "OSPF Neighbor State Machine\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_ON (nsm, NSM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) DEBUG_ON (nsm, NSM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) DEBUG_ON (nsm, NSM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) DEBUG_ON (nsm, NSM_TIMERS); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_ON (nsm, NSM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) TERM_DEBUG_ON (nsm, NSM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) TERM_DEBUG_ON (nsm, NSM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) TERM_DEBUG_ON (nsm, NSM_TIMERS); } return CMD_SUCCESS; } ALIAS (debug_ospf_nsm, debug_ospf_nsm_sub_cmd, "debug ospf nsm (status|events|timers)", DEBUG_STR OSPF_STR "OSPF Neighbor State Machine\n" "NSM Status Information\n" "NSM Event Information\n" "NSM Timer Information\n") DEFUN (no_debug_ospf_nsm, no_debug_ospf_nsm_cmd, "no debug ospf nsm", NO_STR DEBUG_STR OSPF_STR "OSPF Neighbor State Machine") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_OFF (nsm, NSM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) DEBUG_OFF (nsm, NSM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) DEBUG_OFF (nsm, NSM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) DEBUG_OFF (nsm, NSM_TIMERS); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_OFF (nsm, NSM); else if (argc == 1) { if (strncmp (argv[0], "s", 1) == 0) TERM_DEBUG_OFF (nsm, NSM_STATUS); else if (strncmp (argv[0], "e", 1) == 0) TERM_DEBUG_OFF (nsm, NSM_EVENTS); else if (strncmp (argv[0], "t", 1) == 0) TERM_DEBUG_OFF (nsm, NSM_TIMERS); } return CMD_SUCCESS; } ALIAS (no_debug_ospf_nsm, no_debug_ospf_nsm_sub_cmd, "no debug ospf nsm (status|events|timers)", NO_STR "Debugging functions\n" "OSPF information\n" "OSPF Interface State Machine\n" "NSM Status Information\n" "NSM Event Information\n" "NSM Timer Information\n") DEFUN (debug_ospf_lsa, debug_ospf_lsa_cmd, "debug ospf lsa", DEBUG_STR OSPF_STR "OSPF Link State Advertisement\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_ON (lsa, LSA); else if (argc == 1) { if (strncmp (argv[0], "g", 1) == 0) DEBUG_ON (lsa, LSA_GENERATE); else if (strncmp (argv[0], "f", 1) == 0) DEBUG_ON (lsa, LSA_FLOODING); else if (strncmp (argv[0], "i", 1) == 0) DEBUG_ON (lsa, LSA_INSTALL); else if (strncmp (argv[0], "r", 1) == 0) DEBUG_ON (lsa, LSA_REFRESH); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_ON (lsa, LSA); else if (argc == 1) { if (strncmp (argv[0], "g", 1) == 0) TERM_DEBUG_ON (lsa, LSA_GENERATE); else if (strncmp (argv[0], "f", 1) == 0) TERM_DEBUG_ON (lsa, LSA_FLOODING); else if (strncmp (argv[0], "i", 1) == 0) TERM_DEBUG_ON (lsa, LSA_INSTALL); else if (strncmp (argv[0], "r", 1) == 0) TERM_DEBUG_ON (lsa, LSA_REFRESH); } return CMD_SUCCESS; } ALIAS (debug_ospf_lsa, debug_ospf_lsa_sub_cmd, "debug ospf lsa (generate|flooding|install|refresh)", DEBUG_STR OSPF_STR "OSPF Link State Advertisement\n" "LSA Generation\n" "LSA Flooding\n" "LSA Install/Delete\n" "LSA Refresh\n") DEFUN (no_debug_ospf_lsa, no_debug_ospf_lsa_cmd, "no debug ospf lsa", NO_STR DEBUG_STR OSPF_STR "OSPF Link State Advertisement\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_OFF (lsa, LSA); else if (argc == 1) { if (strncmp (argv[0], "g", 1) == 0) DEBUG_OFF (lsa, LSA_GENERATE); else if (strncmp (argv[0], "f", 1) == 0) DEBUG_OFF (lsa, LSA_FLOODING); else if (strncmp (argv[0], "i", 1) == 0) DEBUG_OFF (lsa, LSA_INSTALL); else if (strncmp (argv[0], "r", 1) == 0) DEBUG_OFF (lsa, LSA_REFRESH); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_OFF (lsa, LSA); else if (argc == 1) { if (strncmp (argv[0], "g", 1) == 0) TERM_DEBUG_OFF (lsa, LSA_GENERATE); else if (strncmp (argv[0], "f", 1) == 0) TERM_DEBUG_OFF (lsa, LSA_FLOODING); else if (strncmp (argv[0], "i", 1) == 0) TERM_DEBUG_OFF (lsa, LSA_INSTALL); else if (strncmp (argv[0], "r", 1) == 0) TERM_DEBUG_OFF (lsa, LSA_REFRESH); } return CMD_SUCCESS; } ALIAS (no_debug_ospf_lsa, no_debug_ospf_lsa_sub_cmd, "no debug ospf lsa (generate|flooding|install|refresh)", NO_STR DEBUG_STR OSPF_STR "OSPF Link State Advertisement\n" "LSA Generation\n" "LSA Flooding\n" "LSA Install/Delete\n" "LSA Refres\n") DEFUN (debug_ospf_zebra, debug_ospf_zebra_cmd, "debug ospf zebra", DEBUG_STR OSPF_STR "OSPF Zebra information\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_ON (zebra, ZEBRA); else if (argc == 1) { if (strncmp (argv[0], "i", 1) == 0) DEBUG_ON (zebra, ZEBRA_INTERFACE); else if (strncmp (argv[0], "r", 1) == 0) DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_ON (zebra, ZEBRA); else if (argc == 1) { if (strncmp (argv[0], "i", 1) == 0) TERM_DEBUG_ON (zebra, ZEBRA_INTERFACE); else if (strncmp (argv[0], "r", 1) == 0) TERM_DEBUG_ON (zebra, ZEBRA_REDISTRIBUTE); } return CMD_SUCCESS; } ALIAS (debug_ospf_zebra, debug_ospf_zebra_sub_cmd, "debug ospf zebra (interface|redistribute)", DEBUG_STR OSPF_STR "OSPF Zebra information\n" "Zebra interface\n" "Zebra redistribute\n") DEFUN (no_debug_ospf_zebra, no_debug_ospf_zebra_cmd, "no debug ospf zebra", NO_STR DEBUG_STR OSPF_STR "OSPF Zebra information\n") { if (vty->node == CONFIG_NODE) { if (argc == 0) DEBUG_OFF (zebra, ZEBRA); else if (argc == 1) { if (strncmp (argv[0], "i", 1) == 0) DEBUG_OFF (zebra, ZEBRA_INTERFACE); else if (strncmp (argv[0], "r", 1) == 0) DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); } return CMD_SUCCESS; } /* ENABLE_NODE. */ if (argc == 0) TERM_DEBUG_OFF (zebra, ZEBRA); else if (argc == 1) { if (strncmp (argv[0], "i", 1) == 0) TERM_DEBUG_OFF (zebra, ZEBRA_INTERFACE); else if (strncmp (argv[0], "r", 1) == 0) TERM_DEBUG_OFF (zebra, ZEBRA_REDISTRIBUTE); } return CMD_SUCCESS; } ALIAS (no_debug_ospf_zebra, no_debug_ospf_zebra_sub_cmd, "no debug ospf zebra (interface|redistribute)", NO_STR DEBUG_STR OSPF_STR "OSPF Zebra information\n" "Zebra interface\n" "Zebra redistribute\n") DEFUN (debug_ospf_event, debug_ospf_event_cmd, "debug ospf event", DEBUG_STR OSPF_STR "OSPF event information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_ON (event, EVENT); TERM_DEBUG_ON (event, EVENT); return CMD_SUCCESS; } DEFUN (no_debug_ospf_event, no_debug_ospf_event_cmd, "no debug ospf event", NO_STR DEBUG_STR OSPF_STR "OSPF event information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF (event, EVENT); TERM_DEBUG_OFF (event, EVENT); return CMD_SUCCESS; } DEFUN (debug_ospf_nssa, debug_ospf_nssa_cmd, "debug ospf nssa", DEBUG_STR OSPF_STR "OSPF nssa information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_ON (nssa, NSSA); TERM_DEBUG_ON (nssa, NSSA); return CMD_SUCCESS; } DEFUN (no_debug_ospf_nssa, no_debug_ospf_nssa_cmd, "no debug ospf nssa", NO_STR DEBUG_STR OSPF_STR "OSPF nssa information\n") { if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF (nssa, NSSA); TERM_DEBUG_OFF (nssa, NSSA); return CMD_SUCCESS; } DEFUN (show_debugging_ospf, show_debugging_ospf_cmd, "show debugging ospf", SHOW_STR DEBUG_STR OSPF_STR) { int i; vty_out (vty, "OSPF debugging status:%s", VTY_NEWLINE); /* Show debug status for events. */ if (IS_DEBUG_OSPF(event,EVENT)) vty_out (vty, " OSPF event debugging is on%s", VTY_NEWLINE); /* Show debug status for ISM. */ if (IS_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) vty_out (vty, " OSPF ISM debugging is on%s", VTY_NEWLINE); else { if (IS_DEBUG_OSPF (ism, ISM_STATUS)) vty_out (vty, " OSPF ISM status debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) vty_out (vty, " OSPF ISM event debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) vty_out (vty, " OSPF ISM timer debugging is on%s", VTY_NEWLINE); } /* Show debug status for NSM. */ if (IS_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) vty_out (vty, " OSPF NSM debugging is on%s", VTY_NEWLINE); else { if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) vty_out (vty, " OSPF NSM status debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) vty_out (vty, " OSPF NSM event debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) vty_out (vty, " OSPF NSM timer debugging is on%s", VTY_NEWLINE); } /* Show debug status for OSPF Packets. */ for (i = 0; i < 5; i++) if (IS_DEBUG_OSPF_PACKET (i, SEND) && IS_DEBUG_OSPF_PACKET (i, RECV)) { vty_out (vty, " OSPF packet %s%s debugging is on%s", LOOKUP (ospf_packet_type_str, i + 1), IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", VTY_NEWLINE); } else { if (IS_DEBUG_OSPF_PACKET (i, SEND)) vty_out (vty, " OSPF packet %s send%s debugging is on%s", LOOKUP (ospf_packet_type_str, i + 1), IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", VTY_NEWLINE); if (IS_DEBUG_OSPF_PACKET (i, RECV)) vty_out (vty, " OSPF packet %s receive%s debugging is on%s", LOOKUP (ospf_packet_type_str, i + 1), IS_DEBUG_OSPF_PACKET (i, DETAIL) ? " detail" : "", VTY_NEWLINE); } /* Show debug status for OSPF LSAs. */ if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) vty_out (vty, " OSPF LSA debugging is on%s", VTY_NEWLINE); else { if (IS_DEBUG_OSPF (lsa, LSA_GENERATE)) vty_out (vty, " OSPF LSA generation debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (lsa, LSA_FLOODING)) vty_out (vty, " OSPF LSA flooding debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (lsa, LSA_INSTALL)) vty_out (vty, " OSPF LSA install debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (lsa, LSA_REFRESH)) vty_out (vty, " OSPF LSA refresh debugging is on%s", VTY_NEWLINE); } /* Show debug status for Zebra. */ if (IS_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) vty_out (vty, " OSPF Zebra debugging is on%s", VTY_NEWLINE); else { if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) vty_out (vty, " OSPF Zebra interface debugging is on%s", VTY_NEWLINE); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) vty_out (vty, " OSPF Zebra redistribute debugging is on%s", VTY_NEWLINE); } /* Show debug status for NSSA. */ if (IS_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) vty_out (vty, " OSPF NSSA debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", 1 /* VTYSH */ }; static int config_write_debug (struct vty *vty) { int write = 0; int i, r; const char *type_str[] = {"hello", "dd", "ls-request", "ls-update", "ls-ack"}; const char *detail_str[] = {"", " send", " recv", "", " detail", " send detail", " recv detail", " detail"}; /* debug ospf ism (status|events|timers). */ if (IS_CONF_DEBUG_OSPF (ism, ISM) == OSPF_DEBUG_ISM) vty_out (vty, "debug ospf ism%s", VTY_NEWLINE); else { if (IS_CONF_DEBUG_OSPF (ism, ISM_STATUS)) vty_out (vty, "debug ospf ism status%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (ism, ISM_EVENTS)) vty_out (vty, "debug ospf ism event%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (ism, ISM_TIMERS)) vty_out (vty, "debug ospf ism timer%s", VTY_NEWLINE); } /* debug ospf nsm (status|events|timers). */ if (IS_CONF_DEBUG_OSPF (nsm, NSM) == OSPF_DEBUG_NSM) vty_out (vty, "debug ospf nsm%s", VTY_NEWLINE); else { if (IS_CONF_DEBUG_OSPF (nsm, NSM_STATUS)) vty_out (vty, "debug ospf nsm status%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (nsm, NSM_EVENTS)) vty_out (vty, "debug ospf nsm event%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (nsm, NSM_TIMERS)) vty_out (vty, "debug ospf nsm timer%s", VTY_NEWLINE); } /* debug ospf lsa (generate|flooding|install|refresh). */ if (IS_CONF_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA) vty_out (vty, "debug ospf lsa%s", VTY_NEWLINE); else { if (IS_CONF_DEBUG_OSPF (lsa, LSA_GENERATE)) vty_out (vty, "debug ospf lsa generate%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (lsa, LSA_FLOODING)) vty_out (vty, "debug ospf lsa flooding%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (lsa, LSA_INSTALL)) vty_out (vty, "debug ospf lsa install%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (lsa, LSA_REFRESH)) vty_out (vty, "debug ospf lsa refresh%s", VTY_NEWLINE); write = 1; } /* debug ospf zebra (interface|redistribute). */ if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA) == OSPF_DEBUG_ZEBRA) vty_out (vty, "debug ospf zebra%s", VTY_NEWLINE); else { if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) vty_out (vty, "debug ospf zebra interface%s", VTY_NEWLINE); if (IS_CONF_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) vty_out (vty, "debug ospf zebra redistribute%s", VTY_NEWLINE); write = 1; } /* debug ospf event. */ if (IS_CONF_DEBUG_OSPF (event, EVENT) == OSPF_DEBUG_EVENT) { vty_out (vty, "debug ospf event%s", VTY_NEWLINE); write = 1; } /* debug ospf nssa. */ if (IS_CONF_DEBUG_OSPF (nssa, NSSA) == OSPF_DEBUG_NSSA) { vty_out (vty, "debug ospf nssa%s", VTY_NEWLINE); write = 1; } /* debug ospf packet all detail. */ r = OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL; for (i = 0; i < 5; i++) r &= conf_debug_ospf_packet[i] & (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL); if (r == (OSPF_DEBUG_SEND_RECV|OSPF_DEBUG_DETAIL)) { vty_out (vty, "debug ospf packet all detail%s", VTY_NEWLINE); return 1; } /* debug ospf packet all. */ r = OSPF_DEBUG_SEND_RECV; for (i = 0; i < 5; i++) r &= conf_debug_ospf_packet[i] & OSPF_DEBUG_SEND_RECV; if (r == OSPF_DEBUG_SEND_RECV) { vty_out (vty, "debug ospf packet all%s", VTY_NEWLINE); for (i = 0; i < 5; i++) if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL) vty_out (vty, "debug ospf packet %s detail%s", type_str[i], VTY_NEWLINE); return 1; } /* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack) (send|recv) (detail). */ for (i = 0; i < 5; i++) { if (conf_debug_ospf_packet[i] == 0) continue; vty_out (vty, "debug ospf packet %s%s%s", type_str[i], detail_str[conf_debug_ospf_packet[i]], VTY_NEWLINE); write = 1; } return write; } /* Initialize debug commands. */ void debug_init () { install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &show_debugging_ospf_cmd); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_detail_cmd); install_element (ENABLE_NODE, &debug_ospf_packet_send_recv_cmd); install_element (ENABLE_NODE, &debug_ospf_packet_all_cmd); install_element (ENABLE_NODE, &debug_ospf_ism_sub_cmd); install_element (ENABLE_NODE, &debug_ospf_ism_cmd); install_element (ENABLE_NODE, &debug_ospf_nsm_sub_cmd); install_element (ENABLE_NODE, &debug_ospf_nsm_cmd); install_element (ENABLE_NODE, &debug_ospf_lsa_sub_cmd); install_element (ENABLE_NODE, &debug_ospf_lsa_cmd); install_element (ENABLE_NODE, &debug_ospf_zebra_sub_cmd); install_element (ENABLE_NODE, &debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &debug_ospf_event_cmd); install_element (ENABLE_NODE, &debug_ospf_nssa_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (ENABLE_NODE, &no_debug_ospf_packet_all_cmd); install_element (ENABLE_NODE, &no_debug_ospf_ism_sub_cmd); install_element (ENABLE_NODE, &no_debug_ospf_ism_cmd); install_element (ENABLE_NODE, &no_debug_ospf_nsm_sub_cmd); install_element (ENABLE_NODE, &no_debug_ospf_nsm_cmd); install_element (ENABLE_NODE, &no_debug_ospf_lsa_sub_cmd); install_element (ENABLE_NODE, &no_debug_ospf_lsa_cmd); install_element (ENABLE_NODE, &no_debug_ospf_zebra_sub_cmd); install_element (ENABLE_NODE, &no_debug_ospf_zebra_cmd); install_element (ENABLE_NODE, &no_debug_ospf_event_cmd); install_element (ENABLE_NODE, &no_debug_ospf_nssa_cmd); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &debug_ospf_packet_send_recv_cmd); install_element (CONFIG_NODE, &debug_ospf_packet_all_cmd); install_element (CONFIG_NODE, &debug_ospf_ism_sub_cmd); install_element (CONFIG_NODE, &debug_ospf_ism_cmd); install_element (CONFIG_NODE, &debug_ospf_nsm_sub_cmd); install_element (CONFIG_NODE, &debug_ospf_nsm_cmd); install_element (CONFIG_NODE, &debug_ospf_lsa_sub_cmd); install_element (CONFIG_NODE, &debug_ospf_lsa_cmd); install_element (CONFIG_NODE, &debug_ospf_zebra_sub_cmd); install_element (CONFIG_NODE, &debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &debug_ospf_event_cmd); install_element (CONFIG_NODE, &debug_ospf_nssa_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_detail_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_send_recv_cmd); install_element (CONFIG_NODE, &no_debug_ospf_packet_all_cmd); install_element (CONFIG_NODE, &no_debug_ospf_ism_sub_cmd); install_element (CONFIG_NODE, &no_debug_ospf_ism_cmd); install_element (CONFIG_NODE, &no_debug_ospf_nsm_sub_cmd); install_element (CONFIG_NODE, &no_debug_ospf_nsm_cmd); install_element (CONFIG_NODE, &no_debug_ospf_lsa_sub_cmd); install_element (CONFIG_NODE, &no_debug_ospf_lsa_cmd); install_element (CONFIG_NODE, &no_debug_ospf_zebra_sub_cmd); install_element (CONFIG_NODE, &no_debug_ospf_zebra_cmd); install_element (CONFIG_NODE, &no_debug_ospf_event_cmd); install_element (CONFIG_NODE, &no_debug_ospf_nssa_cmd); } quagga-0.99.24.1/ospfd/ospf_nsm.c0000644000175000017500000007153712476520570013354 00000000000000/* * OSPF version 2 Neighbor State Machine * From RFC2328 [OSPF Version 2] * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "memory.h" #include "hash.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "stream.h" #include "table.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_snmp.h" static void nsm_clear_adj (struct ospf_neighbor *); /* OSPF NSM Timer functions. */ static int ospf_inactivity_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_inactivity = NULL; if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer); return 0; } static int ospf_db_desc_timer (struct thread *thread) { struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); nbr->t_db_desc = NULL; if (IS_DEBUG_OSPF (nsm, NSM_TIMERS)) zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)", IF_NAME (nbr->oi), inet_ntoa (nbr->src)); /* resent last send DD packet. */ assert (nbr->last_send); ospf_db_desc_resend (nbr); /* DD Retransmit timer set. */ OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); return 0; } /* Hook function called after ospf NSM event is occured. * * Set/clear any timers whose condition is implicit to the neighbour * state. There may be other timers which are set/unset according to other * state. * * We rely on this function to properly clear timers in lower states, * particularly before deleting a neighbour. */ static void nsm_timer_set (struct ospf_neighbor *nbr) { switch (nbr->state) { case NSM_Deleted: case NSM_Down: OSPF_NSM_TIMER_OFF (nbr->t_inactivity); OSPF_NSM_TIMER_OFF (nbr->t_hello_reply); case NSM_Attempt: case NSM_Init: case NSM_TwoWay: OSPF_NSM_TIMER_OFF (nbr->t_db_desc); OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); OSPF_NSM_TIMER_OFF (nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); OSPF_NSM_TIMER_OFF (nbr->t_ls_req); break; case NSM_Exchange: OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); if (!IS_SET_DD_MS (nbr->dd_flags)) OSPF_NSM_TIMER_OFF (nbr->t_db_desc); break; case NSM_Loading: case NSM_Full: default: OSPF_NSM_TIMER_OFF (nbr->t_db_desc); break; } } /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with * the given neighbour */ static int nsm_should_adj (struct ospf_neighbor *nbr) { struct ospf_interface *oi = nbr->oi; /* These network types must always form adjacencies. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || oi->type == OSPF_IFTYPE_VIRTUALLINK /* Router itself is the DRouter or the BDRouter. */ || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi)) || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi)) /* Neighboring Router is the DRouter or the BDRouter. */ || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi)) || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi))) return 1; return 0; } /* OSPF NSM functions. */ static int nsm_packet_received (struct ospf_neighbor *nbr) { /* Start or Restart Inactivity Timer. */ OSPF_NSM_TIMER_OFF (nbr->t_inactivity); OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, nbr->v_inactivity); if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma) OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); return 0; } static int nsm_start (struct ospf_neighbor *nbr) { if (nbr->nbr_nbma) OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll); OSPF_NSM_TIMER_OFF (nbr->t_inactivity); OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer, nbr->v_inactivity); return 0; } static int nsm_twoway_received (struct ospf_neighbor *nbr) { return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay); } int ospf_db_summary_count (struct ospf_neighbor *nbr) { return ospf_lsdb_count_all (&nbr->db_sum); } int ospf_db_summary_isempty (struct ospf_neighbor *nbr) { return ospf_lsdb_isempty (&nbr->db_sum); } static int ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { #ifdef HAVE_OPAQUE_LSA switch (lsa->data->type) { case OSPF_OPAQUE_LINK_LSA: /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */ if (nbr->oi && ospf_if_exists (lsa->oi) != nbr->oi) return 0; break; case OSPF_OPAQUE_AREA_LSA: /* * It is assured by the caller function "nsm_negotiation_done()" * that every given LSA belongs to the same area with "nbr". */ break; case OSPF_OPAQUE_AS_LSA: default: break; } #endif /* HAVE_OPAQUE_LSA */ /* Stay away from any Local Translated Type-7 LSAs */ if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT)) return 0; if (IS_LSA_MAXAGE (lsa)) ospf_ls_retransmit_add (nbr, lsa); else ospf_lsdb_add (&nbr->db_sum, lsa); return 0; } void ospf_db_summary_clear (struct ospf_neighbor *nbr) { struct ospf_lsdb *lsdb; int i; lsdb = &nbr->db_sum; for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { struct route_table *table = lsdb->type[i].db; struct route_node *rn; for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info) ospf_lsdb_delete (&nbr->db_sum, rn->info); } } /* The area link state database consists of the router-LSAs, network-LSAs and summary-LSAs contained in the area structure, along with the AS-external-LSAs contained in the global structure. AS-external-LSAs are omitted from a virtual neighbor's Database summary list. AS-external-LSAs are omitted from the Database summary list if the area has been configured as a stub. */ static int nsm_negotiation_done (struct ospf_neighbor *nbr) { struct ospf_area *area = nbr->oi->area; struct ospf_lsa *lsa; struct route_node *rn; LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); #ifdef HAVE_OPAQUE_LSA /* Process only if the neighbor is opaque capable. */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) { LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); } #endif /* HAVE_OPAQUE_LSA */ if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP)) { LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_db_summary_add (nbr, lsa); } if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT) LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O) && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK && area->external_routing == OSPF_AREA_DEFAULT)) LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa) ospf_db_summary_add (nbr, lsa); #endif /* HAVE_OPAQUE_LSA */ return 0; } static int nsm_exchange_done (struct ospf_neighbor *nbr) { if (ospf_ls_request_isempty (nbr)) return NSM_Full; /* Send Link State Request. */ ospf_ls_req_send (nbr); return NSM_Loading; } static int nsm_adj_ok (struct ospf_neighbor *nbr) { int next_state = nbr->state; int adj = nsm_should_adj (nbr); if (nbr->state == NSM_TwoWay && adj == 1) next_state = NSM_ExStart; else if (nbr->state >= NSM_ExStart && adj == 0) next_state = NSM_TwoWay; return next_state; } /* Clear adjacency related state for a neighbour, intended where nbr * transitions from > ExStart (i.e. a Full or forming adjacency) * to <= ExStart. */ static void nsm_clear_adj (struct ospf_neighbor *nbr) { /* Clear Database Summary list. */ if (!ospf_db_summary_isempty (nbr)) ospf_db_summary_clear (nbr); /* Clear Link State Request list. */ if (!ospf_ls_request_isempty (nbr)) ospf_ls_request_delete_all (nbr); /* Clear Link State Retransmission list. */ if (!ospf_ls_retransmit_isempty (nbr)) ospf_ls_retransmit_clear (nbr); #ifdef HAVE_OPAQUE_LSA if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) UNSET_FLAG (nbr->options, OSPF_OPTION_O); #endif /* HAVE_OPAQUE_LSA */ } static int nsm_kill_nbr (struct ospf_neighbor *nbr) { /* killing nbr_self is invalid */ if (nbr == nbr->oi->nbr_self) { assert (nbr != nbr->oi->nbr_self); return 0; } if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) { struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma; nbr_nbma->nbr = NULL; nbr_nbma->state_change = nbr->state_change; nbr->nbr_nbma = NULL; OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, nbr_nbma->v_poll); if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)", IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4)); } return 0; } /* Neighbor State Machine */ struct { int (*func) (struct ospf_neighbor *); int next_state; } NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = { { /* DependUpon: dummy state. */ { NULL, NSM_DependUpon }, /* NoEvent */ { NULL, NSM_DependUpon }, /* PacketReceived */ { NULL, NSM_DependUpon }, /* Start */ { NULL, NSM_DependUpon }, /* 2-WayReceived */ { NULL, NSM_DependUpon }, /* NegotiationDone */ { NULL, NSM_DependUpon }, /* ExchangeDone */ { NULL, NSM_DependUpon }, /* BadLSReq */ { NULL, NSM_DependUpon }, /* LoadingDone */ { NULL, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_DependUpon }, /* SeqNumberMismatch */ { NULL, NSM_DependUpon }, /* 1-WayReceived */ { NULL, NSM_DependUpon }, /* KillNbr */ { NULL, NSM_DependUpon }, /* InactivityTimer */ { NULL, NSM_DependUpon }, /* LLDown */ }, { /* Deleted: dummy state. */ { NULL, NSM_Deleted }, /* NoEvent */ { NULL, NSM_Deleted }, /* PacketReceived */ { NULL, NSM_Deleted }, /* Start */ { NULL, NSM_Deleted }, /* 2-WayReceived */ { NULL, NSM_Deleted }, /* NegotiationDone */ { NULL, NSM_Deleted }, /* ExchangeDone */ { NULL, NSM_Deleted }, /* BadLSReq */ { NULL, NSM_Deleted }, /* LoadingDone */ { NULL, NSM_Deleted }, /* AdjOK? */ { NULL, NSM_Deleted }, /* SeqNumberMismatch */ { NULL, NSM_Deleted }, /* 1-WayReceived */ { NULL, NSM_Deleted }, /* KillNbr */ { NULL, NSM_Deleted }, /* InactivityTimer */ { NULL, NSM_Deleted }, /* LLDown */ }, { /* Down: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { nsm_start, NSM_Attempt }, /* Start */ { NULL, NSM_Down }, /* 2-WayReceived */ { NULL, NSM_Down }, /* NegotiationDone */ { NULL, NSM_Down }, /* ExchangeDone */ { NULL, NSM_Down }, /* BadLSReq */ { NULL, NSM_Down }, /* LoadingDone */ { NULL, NSM_Down }, /* AdjOK? */ { NULL, NSM_Down }, /* SeqNumberMismatch */ { NULL, NSM_Down }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Attempt: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { NULL, NSM_Attempt }, /* Start */ { NULL, NSM_Attempt }, /* 2-WayReceived */ { NULL, NSM_Attempt }, /* NegotiationDone */ { NULL, NSM_Attempt }, /* ExchangeDone */ { NULL, NSM_Attempt }, /* BadLSReq */ { NULL, NSM_Attempt }, /* LoadingDone */ { NULL, NSM_Attempt }, /* AdjOK? */ { NULL, NSM_Attempt }, /* SeqNumberMismatch */ { NULL, NSM_Attempt }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Init: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Init }, /* PacketReceived */ { NULL, NSM_Init }, /* Start */ { nsm_twoway_received, NSM_DependUpon }, /* 2-WayReceived */ { NULL, NSM_Init }, /* NegotiationDone */ { NULL, NSM_Init }, /* ExchangeDone */ { NULL, NSM_Init }, /* BadLSReq */ { NULL, NSM_Init }, /* LoadingDone */ { NULL, NSM_Init }, /* AdjOK? */ { NULL, NSM_Init }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* 2-Way: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_TwoWay }, /* HelloReceived */ { NULL, NSM_TwoWay }, /* Start */ { NULL, NSM_TwoWay }, /* 2-WayReceived */ { NULL, NSM_TwoWay }, /* NegotiationDone */ { NULL, NSM_TwoWay }, /* ExchangeDone */ { NULL, NSM_TwoWay }, /* BadLSReq */ { NULL, NSM_TwoWay }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_TwoWay }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* ExStart: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_ExStart }, /* PacaketReceived */ { NULL, NSM_ExStart }, /* Start */ { NULL, NSM_ExStart }, /* 2-WayReceived */ { nsm_negotiation_done, NSM_Exchange }, /* NegotiationDone */ { NULL, NSM_ExStart }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_ExStart }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Exchange: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Exchange }, /* PacketReceived */ { NULL, NSM_Exchange }, /* Start */ { NULL, NSM_Exchange }, /* 2-WayReceived */ { NULL, NSM_Exchange }, /* NegotiationDone */ { nsm_exchange_done, NSM_DependUpon }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Exchange }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Loading: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Loading }, /* PacketReceived */ { NULL, NSM_Loading }, /* Start */ { NULL, NSM_Loading }, /* 2-WayReceived */ { NULL, NSM_Loading }, /* NegotiationDone */ { NULL, NSM_Loading }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Full }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, { /* Full: */ { NULL, NSM_DependUpon }, /* NoEvent */ { nsm_packet_received, NSM_Full }, /* PacketReceived */ { NULL, NSM_Full }, /* Start */ { NULL, NSM_Full }, /* 2-WayReceived */ { NULL, NSM_Full }, /* NegotiationDone */ { NULL, NSM_Full }, /* ExchangeDone */ { NULL, NSM_ExStart }, /* BadLSReq */ { NULL, NSM_Full }, /* LoadingDone */ { nsm_adj_ok, NSM_DependUpon }, /* AdjOK? */ { NULL, NSM_ExStart }, /* SeqNumberMismatch */ { NULL, NSM_Init }, /* 1-WayReceived */ { nsm_kill_nbr, NSM_Deleted }, /* KillNbr */ { nsm_kill_nbr, NSM_Deleted }, /* InactivityTimer */ { nsm_kill_nbr, NSM_Deleted }, /* LLDown */ }, }; static const char *ospf_nsm_event_str[] = { "NoEvent", "PacketReceived", "Start", "2-WayReceived", "NegotiationDone", "ExchangeDone", "BadLSReq", "LoadingDone", "AdjOK?", "SeqNumberMismatch", "1-WayReceived", "KillNbr", "InactivityTimer", "LLDown", }; static void nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event) { /* Logging change of status. */ if (IS_DEBUG_OSPF (nsm, NSM_STATUS)) zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), LOOKUP (ospf_nsm_state_msg, next_state), ospf_nsm_event_str [event]); /* Optionally notify about adjacency changes */ if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) || (next_state == NSM_Full) || (next_state < nbr->state))) zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)", inet_ntoa (nbr->router_id), IF_NAME (nbr->oi), LOOKUP (ospf_nsm_state_msg, nbr->state), LOOKUP (ospf_nsm_state_msg, next_state), ospf_nsm_event_str [event]); /* Advance in NSM */ if (next_state > nbr->state) nbr->ts_last_progress = recent_relative_time (); else /* regression in NSM */ { nbr->ts_last_regress = recent_relative_time (); nbr->last_regress_str = ospf_nsm_event_str [event]; } #ifdef HAVE_SNMP /* Terminal state or regression */ if ((next_state == NSM_Full) || (next_state == NSM_TwoWay) || (next_state < nbr->state)) { /* ospfVirtNbrStateChange */ if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK) ospfTrapVirtNbrStateChange(nbr); /* ospfNbrStateChange trap */ else /* To/From FULL, only managed by DR */ if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) || (nbr->oi->state == ISM_DR)) ospfTrapNbrStateChange(nbr); } #endif } static void nsm_change_state (struct ospf_neighbor *nbr, int state) { struct ospf_interface *oi = nbr->oi; struct ospf_area *vl_area = NULL; u_char old_state; int x; int force = 1; /* Preserve old status. */ old_state = nbr->state; /* Change to new status. */ nbr->state = state; /* Statistics. */ nbr->state_change++; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id); /* Generate NeighborChange ISM event. * * In response to NeighborChange, DR election is rerun. The information * from the election process is required by the router-lsa construction. * * Therefore, trigger the event prior to refreshing the LSAs. */ switch (oi->state) { case ISM_DROther: case ISM_Backup: case ISM_DR: if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) || (old_state >= NSM_TwoWay && state < NSM_TwoWay)) OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange); break; default: /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */ break; } /* One of the neighboring routers changes to/from the FULL state. */ if ((old_state != NSM_Full && state == NSM_Full) || (old_state == NSM_Full && state != NSM_Full)) { if (state == NSM_Full) { oi->full_nbrs++; oi->area->full_nbrs++; ospf_check_abr_status (oi->ospf); if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) if (++vl_area->full_vls == 1) ospf_schedule_abr_task (oi->ospf); /* kevinm: refresh any redistributions */ for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++) { if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6) continue; ospf_external_lsa_refresh_type (oi->ospf, x, force); } /* XXX: Clearly some thing is wrong with refresh of external LSAs * this added to hack around defaults not refreshing after a timer * jump. */ ospf_external_lsa_refresh_default (oi->ospf); } else { oi->full_nbrs--; oi->area->full_nbrs--; ospf_check_abr_status (oi->ospf); if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area) if (vl_area->full_vls > 0) if (--vl_area->full_vls == 0) ospf_schedule_abr_task (oi->ospf); } zlog_info ("nsm_change_state(%s, %s -> %s): " "scheduling new router-LSA origination", inet_ntoa (nbr->router_id), LOOKUP(ospf_nsm_state_msg, old_state), LOOKUP(ospf_nsm_state_msg, state)); ospf_router_lsa_update_area (oi->area); if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { struct ospf_area *vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id); if (vl_area) ospf_router_lsa_update_area (vl_area); } /* Originate network-LSA. */ if (oi->state == ISM_DR) { if (oi->network_lsa_self && oi->full_nbrs == 0) { ospf_lsa_flush_area (oi->network_lsa_self, oi->area); ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = NULL; } else ospf_network_lsa_update (oi); } } #ifdef HAVE_OPAQUE_LSA ospf_opaque_nsm_change (nbr, old_state); #endif /* HAVE_OPAQUE_LSA */ /* State changes from > ExStart to <= ExStart should clear any Exchange * or Full/LSA Update related lists and state. * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK? */ if ((old_state > NSM_ExStart) && (state <= NSM_ExStart)) nsm_clear_adj (nbr); /* Start DD exchange protocol */ if (state == NSM_ExStart) { if (nbr->dd_seqnum == 0) nbr->dd_seqnum = quagga_time (NULL); else nbr->dd_seqnum++; nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS; ospf_db_desc_send (nbr); } /* clear cryptographic sequence number */ if (state == NSM_Down) nbr->crypt_seqnum = 0; /* Preserve old status? */ } /* Execute NSM event process. */ int ospf_nsm_event (struct thread *thread) { int event; int next_state; struct ospf_neighbor *nbr; nbr = THREAD_ARG (thread); event = THREAD_VAL (thread); if (IS_DEBUG_OSPF (nsm, NSM_EVENTS)) zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event]); next_state = NSM [nbr->state][event].next_state; /* Call function. */ if (NSM [nbr->state][event].func != NULL) { int func_state = (*(NSM [nbr->state][event].func))(nbr); if (NSM [nbr->state][event].next_state == NSM_DependUpon) next_state = func_state; else if (func_state) { /* There's a mismatch between the FSM tables and what an FSM * action/state-change function returned. State changes which * do not have conditional/DependUpon next-states should not * try set next_state. */ zlog_warn ("NSM[%s:%s]: %s (%s): " "Warning: action tried to change next_state to %s", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id), LOOKUP (ospf_nsm_state_msg, nbr->state), ospf_nsm_event_str [event], LOOKUP (ospf_nsm_state_msg, func_state)); } } assert (next_state != NSM_DependUpon); /* If state is changed. */ if (next_state != nbr->state) { nsm_notice_state_change (nbr, next_state, event); nsm_change_state (nbr, next_state); } /* Make sure timer is set. */ nsm_timer_set (nbr); /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor * is deleted. * * Rather than encode knowledge here of which events lead to NBR * delete, we take our cue from the NSM table, via the dummy * 'Deleted' neighbour state. */ if (nbr->state == NSM_Deleted) ospf_nbr_delete (nbr); return 0; } /* Check loading state. */ void ospf_check_nbr_loading (struct ospf_neighbor *nbr) { if (nbr->state == NSM_Loading) { if (ospf_ls_request_isempty (nbr)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone); else if (nbr->ls_req_last == NULL) ospf_ls_req_event (nbr); } } quagga-0.99.24.1/ospfd/ospf_neighbor.c0000644000175000017500000002651412476520570014347 00000000000000/* * OSPF Neighbor functions. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "memory.h" #include "command.h" #include "thread.h" #include "stream.h" #include "table.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_dump.h" /* Fill in the the 'key' as appropriate to retrieve the entry for nbr * from the ospf_interface's nbrs table. Indexed by interface address * for all cases except Virtual-link interfaces, where neighbours are * indexed by router-ID instead. */ static void ospf_nbr_key (struct ospf_interface *oi, struct ospf_neighbor *nbr, struct prefix *key) { key->family = AF_INET; key->prefixlen = IPV4_MAX_BITLEN; /* vlinks are indexed by router-id */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) key->u.prefix4 = nbr->router_id; else key->u.prefix4 = nbr->src; return; } struct ospf_neighbor * ospf_nbr_new (struct ospf_interface *oi) { struct ospf_neighbor *nbr; /* Allcate new neighbor. */ nbr = XCALLOC (MTYPE_OSPF_NEIGHBOR, sizeof (struct ospf_neighbor)); /* Relate neighbor to the interface. */ nbr->oi = oi; /* Set default values. */ nbr->state = NSM_Down; /* Set inheritance values. */ nbr->v_inactivity = OSPF_IF_PARAM (oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM (oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM (oi, retransmit_interval); nbr->v_ls_upd = OSPF_IF_PARAM (oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ nbr->dd_flags = OSPF_DD_FLAG_MS|OSPF_DD_FLAG_M|OSPF_DD_FLAG_I; /* Last received and sent DD. */ nbr->last_send = NULL; nbr->nbr_nbma = NULL; ospf_lsdb_init (&nbr->db_sum); ospf_lsdb_init (&nbr->ls_rxmt); ospf_lsdb_init (&nbr->ls_req); nbr->crypt_seqnum = 0; return nbr; } void ospf_nbr_free (struct ospf_neighbor *nbr) { /* Free DB summary list. */ if (ospf_db_summary_count (nbr)) ospf_db_summary_clear (nbr); /* ospf_db_summary_delete_all (nbr); */ /* Free ls request list. */ if (ospf_ls_request_count (nbr)) ospf_ls_request_delete_all (nbr); /* Free retransmit list. */ if (ospf_ls_retransmit_count (nbr)) ospf_ls_retransmit_clear (nbr); /* Cleanup LSDBs. */ ospf_lsdb_cleanup (&nbr->db_sum); ospf_lsdb_cleanup (&nbr->ls_req); ospf_lsdb_cleanup (&nbr->ls_rxmt); /* Clear last send packet. */ if (nbr->last_send) ospf_packet_free (nbr->last_send); if (nbr->nbr_nbma) { nbr->nbr_nbma->nbr = NULL; nbr->nbr_nbma = NULL; } /* Cancel all timers. */ OSPF_NSM_TIMER_OFF (nbr->t_inactivity); OSPF_NSM_TIMER_OFF (nbr->t_db_desc); OSPF_NSM_TIMER_OFF (nbr->t_ls_req); OSPF_NSM_TIMER_OFF (nbr->t_ls_upd); /* Cancel all events. *//* Thread lookup cost would be negligible. */ thread_cancel_event (master, nbr); XFREE (MTYPE_OSPF_NEIGHBOR, nbr); } /* Delete specified OSPF neighbor from interface. */ void ospf_nbr_delete (struct ospf_neighbor *nbr) { struct ospf_interface *oi; struct route_node *rn; struct prefix p; oi = nbr->oi; /* get appropriate prefix 'key' */ ospf_nbr_key (oi, nbr, &p); rn = route_node_lookup (oi->nbrs, &p); if (rn) { /* If lookup for a NBR succeeds, the leaf route_node could * only exist because there is (or was) a nbr there. * If the nbr was deleted, the leaf route_node should have * lost its last refcount too, and be deleted. * Therefore a looked-up leaf route_node in nbrs table * should never have NULL info. */ assert (rn->info); if (rn->info) { rn->info = NULL; route_unlock_node (rn); } else zlog_info ("Can't find neighbor %s in the interface %s", inet_ntoa (nbr->src), IF_NAME (oi)); route_unlock_node (rn); } /* Free ospf_neighbor structure. */ ospf_nbr_free (nbr); } /* Check myself is in the neighbor list. */ int ospf_nbr_bidirectional (struct in_addr *router_id, struct in_addr *neighbors, int size) { int i; int max; max = size / sizeof (struct in_addr); for (i = 0; i < max; i ++) if (IPV4_ADDR_SAME (router_id, &neighbors[i])) return 1; return 0; } /* Add self to nbr list. */ void ospf_nbr_add_self (struct ospf_interface *oi) { struct prefix p; struct route_node *rn; /* Initial state */ oi->nbr_self->address = *oi->address; oi->nbr_self->priority = OSPF_IF_PARAM (oi, priority); oi->nbr_self->router_id = oi->ospf->router_id; oi->nbr_self->src = oi->address->u.prefix4; oi->nbr_self->state = NSM_TwoWay; switch (oi->area->external_routing) { case OSPF_AREA_DEFAULT: SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); break; case OSPF_AREA_STUB: UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); break; case OSPF_AREA_NSSA: UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); break; } /* Add nbr_self to nbrs table */ ospf_nbr_key (oi, oi->nbr_self, &p); rn = route_node_get (oi->nbrs, &p); if (rn->info) { /* There is already pseudo neighbor. */ assert (oi->nbr_self == rn->info); route_unlock_node (rn); } else rn->info = oi->nbr_self; } /* Get neighbor count by status. Specify status = 0, get all neighbor other than myself. */ int ospf_nbr_count (struct ospf_interface *oi, int state) { struct ospf_neighbor *nbr; struct route_node *rn; int count = 0; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) if (state == 0 || nbr->state == state) count++; return count; } #ifdef HAVE_OPAQUE_LSA int ospf_nbr_count_opaque_capable (struct ospf_interface *oi) { struct ospf_neighbor *nbr; struct route_node *rn; int count = 0; for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info)) if (!IPV4_ADDR_SAME (&nbr->router_id, &oi->ospf->router_id)) if (nbr->state == NSM_Full) if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)) count++; return count; } #endif /* HAVE_OPAQUE_LSA */ /* lookup nbr by address - use this only if you know you must * otherwise use the ospf_nbr_lookup() wrapper, which deals * with virtual link neighbours */ struct ospf_neighbor * ospf_nbr_lookup_by_addr (struct route_table *nbrs, struct in_addr *addr) { struct prefix p; struct route_node *rn; struct ospf_neighbor *nbr; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = *addr; rn = route_node_lookup (nbrs, &p); if (! rn) return NULL; /* See comment in ospf_nbr_delete */ assert (rn->info); if (rn->info == NULL) { route_unlock_node (rn); return NULL; } nbr = (struct ospf_neighbor *) rn->info; route_unlock_node (rn); return nbr; } struct ospf_neighbor * ospf_nbr_lookup_by_routerid (struct route_table *nbrs, struct in_addr *id) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (IPV4_ADDR_SAME (&nbr->router_id, id)) { route_unlock_node(rn); return nbr; } return NULL; } void ospf_renegotiate_optional_capabilities (struct ospf *top) { struct listnode *node; struct ospf_interface *oi; struct route_table *nbrs; struct route_node *rn; struct ospf_neighbor *nbr; /* At first, flush self-originated LSAs from routing domain. */ ospf_flush_self_originated_lsas_now (top); /* Revert all neighbor status to ExStart. */ for (ALL_LIST_ELEMENTS_RO (top->oiflist, node, oi)) { if ((nbrs = oi->nbrs) == NULL) continue; for (rn = route_top (nbrs); rn; rn = route_next (rn)) { if ((nbr = rn->info) == NULL || nbr == oi->nbr_self) continue; if (nbr->state < NSM_ExStart) continue; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Renegotiate optional capabilities with neighbor(%s)", inet_ntoa (nbr->router_id)); OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch); } } return; } struct ospf_neighbor * ospf_nbr_lookup (struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh) { if (oi->type == OSPF_IFTYPE_VIRTUALLINK) return (ospf_nbr_lookup_by_routerid (oi->nbrs, &ospfh->router_id)); else return (ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src)); } static struct ospf_neighbor * ospf_nbr_add (struct ospf_interface *oi, struct ospf_header *ospfh, struct prefix *p) { struct ospf_neighbor *nbr; nbr = ospf_nbr_new (oi); nbr->state = NSM_Down; nbr->src = p->u.prefix4; memcpy (&nbr->address, p, sizeof (struct prefix)); nbr->nbr_nbma = NULL; if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_nbr_nbma *nbr_nbma; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (oi->nbr_nbma, node, nbr_nbma)) { if (IPV4_ADDR_SAME(&nbr_nbma->addr, &nbr->src)) { nbr_nbma->nbr = nbr; nbr->nbr_nbma = nbr_nbma; if (nbr_nbma->t_poll) OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); nbr->state_change = nbr_nbma->state_change + 1; } } } /* New nbr, save the crypto sequence number if necessary */ if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC) nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("NSM[%s:%s]: start", IF_NAME (nbr->oi), inet_ntoa (nbr->router_id)); return nbr; } struct ospf_neighbor * ospf_nbr_get (struct ospf_interface *oi, struct ospf_header *ospfh, struct ip *iph, struct prefix *p) { struct route_node *rn; struct prefix key; struct ospf_neighbor *nbr; key.family = AF_INET; key.prefixlen = IPV4_MAX_BITLEN; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) key.u.prefix4 = ospfh->router_id; /* index vlink nbrs by router-id */ else key.u.prefix4 = iph->ip_src; rn = route_node_get (oi->nbrs, &key); if (rn->info) { route_unlock_node (rn); nbr = rn->info; if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt) { nbr->src = iph->ip_src; memcpy (&nbr->address, p, sizeof (struct prefix)); } } else { rn->info = nbr = ospf_nbr_add (oi, ospfh, p); } nbr->router_id = ospfh->router_id; return nbr; } quagga-0.99.24.1/ospfd/ospf_ism.c0000644000175000017500000004422612476520570013342 00000000000000/* * OSPF version 2 Interface State Machine * From RFC2328 [OSPF Version 2] * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_snmp.h" /* elect DR and BDR. Refer to RFC2319 section 9.4 */ static struct ospf_neighbor * ospf_dr_election_sub (struct list *routers) { struct listnode *node; struct ospf_neighbor *nbr, *max = NULL; /* Choose highest router priority. In case of tie, choose highest Router ID. */ for (ALL_LIST_ELEMENTS_RO (routers, node, nbr)) { if (max == NULL) max = nbr; else { if (max->priority < nbr->priority) max = nbr; else if (max->priority == nbr->priority) if (IPV4_ADDR_CMP (&max->router_id, &nbr->router_id) < 0) max = nbr; } } return max; } static struct ospf_neighbor * ospf_elect_dr (struct ospf_interface *oi, struct list *el_list) { struct list *dr_list; struct listnode *node; struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL; dr_list = list_new (); /* Add neighbors to the list. */ for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr)) { /* neighbor declared to be DR. */ if (NBR_IS_DR (nbr)) listnode_add (dr_list, nbr); /* Preserve neighbor BDR. */ if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4)) bdr = nbr; } /* Elect Designated Router. */ if (listcount (dr_list) > 0) dr = ospf_dr_election_sub (dr_list); else dr = bdr; /* Set DR to interface. */ if (dr) DR (oi) = dr->address.u.prefix4; else DR (oi).s_addr = 0; list_delete (dr_list); return dr; } static struct ospf_neighbor * ospf_elect_bdr (struct ospf_interface *oi, struct list *el_list) { struct list *bdr_list, *no_dr_list; struct listnode *node; struct ospf_neighbor *nbr, *bdr = NULL; bdr_list = list_new (); no_dr_list = list_new (); /* Add neighbors to the list. */ for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr)) { /* neighbor declared to be DR. */ if (NBR_IS_DR (nbr)) continue; /* neighbor declared to be BDR. */ if (NBR_IS_BDR (nbr)) listnode_add (bdr_list, nbr); listnode_add (no_dr_list, nbr); } /* Elect Backup Designated Router. */ if (listcount (bdr_list) > 0) bdr = ospf_dr_election_sub (bdr_list); else bdr = ospf_dr_election_sub (no_dr_list); /* Set BDR to interface. */ if (bdr) BDR (oi) = bdr->address.u.prefix4; else BDR (oi).s_addr = 0; list_delete (bdr_list); list_delete (no_dr_list); return bdr; } static int ospf_ism_state (struct ospf_interface *oi) { if (IPV4_ADDR_SAME (&DR (oi), &oi->address->u.prefix4)) return ISM_DR; else if (IPV4_ADDR_SAME (&BDR (oi), &oi->address->u.prefix4)) return ISM_Backup; else return ISM_DROther; } static void ospf_dr_eligible_routers (struct route_table *nbrs, struct list *el_list) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) /* Ignore 0.0.0.0 node*/ if (nbr->router_id.s_addr != 0) /* Is neighbor eligible? */ if (nbr->priority > 0) /* Is neighbor upper 2-Way? */ if (nbr->state >= NSM_TwoWay) listnode_add (el_list, nbr); } /* Generate AdjOK? NSM event. */ static void ospf_dr_change (struct ospf *ospf, struct route_table *nbrs) { struct route_node *rn; struct ospf_neighbor *nbr; for (rn = route_top (nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) /* Ignore 0.0.0.0 node*/ if (nbr->router_id.s_addr != 0) /* Is neighbor upper 2-Way? */ if (nbr->state >= NSM_TwoWay) /* Ignore myself. */ if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf->router_id)) OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_AdjOK); } static int ospf_dr_election (struct ospf_interface *oi) { struct in_addr old_dr, old_bdr; int old_state, new_state; struct list *el_list; /* backup current values. */ old_dr = DR (oi); old_bdr = BDR (oi); old_state = oi->state; el_list = list_new (); /* List eligible routers. */ ospf_dr_eligible_routers (oi->nbrs, el_list); /* First election of DR and BDR. */ ospf_elect_bdr (oi, el_list); ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); zlog_debug ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi))); zlog_debug ("DR-Election[1st]: DR %s", inet_ntoa (DR (oi))); if (new_state != old_state && !(new_state == ISM_DROther && old_state < ISM_DROther)) { ospf_elect_bdr (oi, el_list); ospf_elect_dr (oi, el_list); new_state = ospf_ism_state (oi); zlog_debug ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi))); zlog_debug ("DR-Election[2nd]: DR %s", inet_ntoa (DR (oi))); } list_delete (el_list); /* if DR or BDR changes, cause AdjOK? neighbor event. */ if (!IPV4_ADDR_SAME (&old_dr, &DR (oi)) || !IPV4_ADDR_SAME (&old_bdr, &BDR (oi))) ospf_dr_change (oi->ospf, oi->nbrs); return new_state; } int ospf_hello_timer (struct thread *thread) { struct ospf_interface *oi; oi = THREAD_ARG (thread); oi->t_hello = NULL; if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Hello timer expire)", IF_NAME (oi)); /* Sending hello packet. */ ospf_hello_send (oi); /* Hello timer set. */ OSPF_HELLO_TIMER_ON (oi); return 0; } static int ospf_wait_timer (struct thread *thread) { struct ospf_interface *oi; oi = THREAD_ARG (thread); oi->t_wait = NULL; if (IS_DEBUG_OSPF (ism, ISM_TIMERS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Wait timer expire)", IF_NAME (oi)); OSPF_ISM_EVENT_SCHEDULE (oi, ISM_WaitTimer); return 0; } /* Hook function called after ospf ISM event is occured. And vty's network command invoke this function after making interface structure. */ static void ism_timer_set (struct ospf_interface *oi) { switch (oi->state) { case ISM_Down: /* First entry point of ospf interface state machine. In this state interface parameters must be set to initial values, and timers are reset also. */ OSPF_ISM_TIMER_OFF (oi->t_hello); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_OFF (oi->t_ls_ack); break; case ISM_Loopback: /* In this state, the interface may be looped back and will be unavailable for regular data traffic. */ OSPF_ISM_TIMER_OFF (oi->t_hello); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_OFF (oi->t_ls_ack); break; case ISM_Waiting: /* The router is trying to determine the identity of DRouter and BDRouter. The router begin to receive and send Hello Packets. */ /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON (oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM (oi, v_wait)); OSPF_ISM_TIMER_OFF (oi->t_ls_ack); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network or virtual link. The router attempts to form an adjacency with neighboring router. Hello packets are also sent. */ /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA network, and the router itself is neither Designated Router nor Backup Designated Router. */ OSPF_HELLO_TIMER_ON (oi); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA network, and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON (oi); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA network, and the router is Designated Router. */ OSPF_HELLO_TIMER_ON (oi); OSPF_ISM_TIMER_OFF (oi->t_wait); OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); break; } } static int ism_interface_up (struct ospf_interface *oi) { int next_state = 0; /* if network type is point-to-point, Point-to-MultiPoint or virtual link, the state transitions to Point-to-Point. */ if (oi->type == OSPF_IFTYPE_POINTOPOINT || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT || oi->type == OSPF_IFTYPE_VIRTUALLINK) next_state = ISM_PointToPoint; /* Else if the router is not eligible to DR, the state transitions to DROther. */ else if (PRIORITY (oi) == 0) /* router is eligible? */ next_state = ISM_DROther; else /* Otherwise, the state transitions to Waiting. */ next_state = ISM_Waiting; if (oi->type == OSPF_IFTYPE_NBMA) ospf_nbr_nbma_if_update (oi->ospf, oi); /* ospf_ism_event (t); */ return next_state; } static int ism_loop_ind (struct ospf_interface *oi) { int ret = 0; /* call ism_interface_down. */ /* ret = ism_interface_down (oi); */ return ret; } /* Interface down event handler. */ static int ism_interface_down (struct ospf_interface *oi) { ospf_if_cleanup (oi); return 0; } static int ism_backup_seen (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_wait_timer (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_neighbor_change (struct ospf_interface *oi) { return ospf_dr_election (oi); } static int ism_ignore (struct ospf_interface *oi) { if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: ism_ignore called", IF_NAME (oi)); return 0; } /* Interface State Machine */ struct { int (*func) (struct ospf_interface *); int next_state; } ISM [OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] = { { /* DependUpon: dummy state. */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_DependUpon }, /* InterfaceUp */ { ism_ignore, ISM_DependUpon }, /* WaitTimer */ { ism_ignore, ISM_DependUpon }, /* BackupSeen */ { ism_ignore, ISM_DependUpon }, /* NeighborChange */ { ism_ignore, ISM_DependUpon }, /* LoopInd */ { ism_ignore, ISM_DependUpon }, /* UnloopInd */ { ism_ignore, ISM_DependUpon }, /* InterfaceDown */ }, { /* Down:*/ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_interface_up, ISM_DependUpon }, /* InterfaceUp */ { ism_ignore, ISM_Down }, /* WaitTimer */ { ism_ignore, ISM_Down }, /* BackupSeen */ { ism_ignore, ISM_Down }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_Down }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* Loopback: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_Loopback }, /* InterfaceUp */ { ism_ignore, ISM_Loopback }, /* WaitTimer */ { ism_ignore, ISM_Loopback }, /* BackupSeen */ { ism_ignore, ISM_Loopback }, /* NeighborChange */ { ism_ignore, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_Down }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* Waiting: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_Waiting }, /* InterfaceUp */ { ism_wait_timer, ISM_DependUpon }, /* WaitTimer */ { ism_backup_seen, ISM_DependUpon }, /* BackupSeen */ { ism_ignore, ISM_Waiting }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_Waiting }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* Point-to-Point: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_PointToPoint }, /* InterfaceUp */ { ism_ignore, ISM_PointToPoint }, /* WaitTimer */ { ism_ignore, ISM_PointToPoint }, /* BackupSeen */ { ism_ignore, ISM_PointToPoint }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_PointToPoint }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* DROther: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_DROther }, /* InterfaceUp */ { ism_ignore, ISM_DROther }, /* WaitTimer */ { ism_ignore, ISM_DROther }, /* BackupSeen */ { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_DROther }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* Backup: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_Backup }, /* InterfaceUp */ { ism_ignore, ISM_Backup }, /* WaitTimer */ { ism_ignore, ISM_Backup }, /* BackupSeen */ { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_Backup }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, { /* DR: */ { ism_ignore, ISM_DependUpon }, /* NoEvent */ { ism_ignore, ISM_DR }, /* InterfaceUp */ { ism_ignore, ISM_DR }, /* WaitTimer */ { ism_ignore, ISM_DR }, /* BackupSeen */ { ism_neighbor_change, ISM_DependUpon }, /* NeighborChange */ { ism_loop_ind, ISM_Loopback }, /* LoopInd */ { ism_ignore, ISM_DR }, /* UnloopInd */ { ism_interface_down, ISM_Down }, /* InterfaceDown */ }, }; static const char *ospf_ism_event_str[] = { "NoEvent", "InterfaceUp", "WaitTimer", "BackupSeen", "NeighborChange", "LoopInd", "UnLoopInd", "InterfaceDown", }; static void ism_change_state (struct ospf_interface *oi, int state) { int old_state; struct ospf_lsa *lsa; /* Logging change of state. */ if (IS_DEBUG_OSPF (ism, ISM_STATUS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: State change %s -> %s", IF_NAME (oi), LOOKUP (ospf_ism_state_msg, oi->state), LOOKUP (ospf_ism_state_msg, state)); old_state = oi->state; oi->state = state; oi->state_change++; #ifdef HAVE_SNMP /* Terminal state or regression */ if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) || (state == ISM_PointToPoint) || (state < old_state)) { /* ospfVirtIfStateChange */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) ospfTrapVirtIfStateChange (oi); /* ospfIfStateChange */ else ospfTrapIfStateChange (oi); } #endif /* Set multicast memberships appropriately for new state. */ ospf_if_set_multicast(oi); if (old_state == ISM_Down || state == ISM_Down) ospf_check_abr_status (oi->ospf); /* Originate router-LSA. */ if (state == ISM_Down) { if (oi->area->act_ints > 0) oi->area->act_ints--; } else if (old_state == ISM_Down) oi->area->act_ints++; /* schedule router-LSA originate. */ ospf_router_lsa_update_area (oi->area); /* Originate network-LSA. */ if (old_state != ISM_DR && state == ISM_DR) ospf_network_lsa_update (oi); else if (old_state == ISM_DR && state != ISM_DR) { /* Free self originated network LSA. */ lsa = oi->network_lsa_self; if (lsa) ospf_lsa_flush_area (lsa, oi->area); ospf_lsa_unlock (&oi->network_lsa_self); oi->network_lsa_self = NULL; } #ifdef HAVE_OPAQUE_LSA ospf_opaque_ism_change (oi, old_state); #endif /* HAVE_OPAQUE_LSA */ /* Check area border status. */ ospf_check_abr_status (oi->ospf); } /* Execute ISM event process. */ int ospf_ism_event (struct thread *thread) { int event; int next_state; struct ospf_interface *oi; oi = THREAD_ARG (thread); event = THREAD_VAL (thread); /* Call function. */ next_state = (*(ISM [oi->state][event].func))(oi); if (! next_state) next_state = ISM [oi->state][event].next_state; if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog (NULL, LOG_DEBUG, "ISM[%s]: %s (%s)", IF_NAME (oi), LOOKUP (ospf_ism_state_msg, oi->state), ospf_ism_event_str[event]); /* If state is changed. */ if (next_state != oi->state) ism_change_state (oi, next_state); /* Make sure timer is set. */ ism_timer_set (oi); return 0; } quagga-0.99.24.1/ospfd/ospf_interface.c0000644000175000017500000007553012476520570014514 00000000000000/* * OSPF Interface functions. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "linklist.h" #include "prefix.h" #include "if.h" #include "table.h" #include "memory.h" #include "command.h" #include "stream.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_dump.h" #ifdef HAVE_SNMP #include "ospfd/ospf_snmp.h" #endif /* HAVE_SNMP */ int ospf_if_get_output_cost (struct ospf_interface *oi) { /* If all else fails, use default OSPF cost */ u_int32_t cost; u_int32_t bw, refbw; bw = oi->ifp->bandwidth ? oi->ifp->bandwidth : OSPF_DEFAULT_BANDWIDTH; refbw = oi->ospf->ref_bandwidth; /* A specifed ip ospf cost overrides a calculated one. */ if (OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (oi->ifp), output_cost_cmd) || OSPF_IF_PARAM_CONFIGURED (oi->params, output_cost_cmd)) cost = OSPF_IF_PARAM (oi, output_cost_cmd); /* See if a cost can be calculated from the zebra processes interface bandwidth field. */ else { cost = (u_int32_t) ((double)refbw / (double)bw + (double)0.5); if (cost < 1) cost = 1; else if (cost > 65535) cost = 65535; } return cost; } void ospf_if_recalculate_output_cost (struct interface *ifp) { u_int32_t newcost; struct route_node *rn; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi; if ( (oi = rn->info) == NULL) continue; newcost = ospf_if_get_output_cost (oi); /* Is actual output cost changed? */ if (oi->output_cost != newcost) { oi->output_cost = newcost; ospf_router_lsa_update_area (oi->area); } } } /* Simulate down/up on the interface. This is needed, for example, when the MTU changes. */ void ospf_if_reset(struct interface *ifp) { struct route_node *rn; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { struct ospf_interface *oi; if ( (oi = rn->info) == NULL) continue; ospf_if_down(oi); ospf_if_up(oi); } } void ospf_if_reset_variables (struct ospf_interface *oi) { /* Set default values. */ /* don't clear this flag. oi->flag = OSPF_IF_DISABLE; */ if (oi->vl_data) oi->type = OSPF_IFTYPE_VIRTUALLINK; else /* preserve network-type */ if (oi->type != OSPF_IFTYPE_NBMA) oi->type = OSPF_IFTYPE_BROADCAST; oi->state = ISM_Down; oi->crypt_seqnum = 0; /* This must be short, (less than RxmtInterval) - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being held back for too long - MAG */ oi->v_ls_ack = 1; } /* lookup oi for specified prefix/ifp */ struct ospf_interface * ospf_if_table_lookup (struct interface *ifp, struct prefix *prefix) { struct prefix p; struct route_node *rn; struct ospf_interface *rninfo = NULL; p = *prefix; p.prefixlen = IPV4_MAX_PREFIXLEN; /* route_node_get implicitely locks */ if ((rn = route_node_lookup (IF_OIFS (ifp), &p))) { rninfo = (struct ospf_interface *) rn->info; route_unlock_node (rn); } return rninfo; } static void ospf_add_to_if (struct interface *ifp, struct ospf_interface *oi) { struct route_node *rn; struct prefix p; p = *oi->address; p.prefixlen = IPV4_MAX_PREFIXLEN; rn = route_node_get (IF_OIFS (ifp), &p); /* rn->info should either be NULL or equal to this oi * as route_node_get may return an existing node */ assert (!rn->info || rn->info == oi); rn->info = oi; } static void ospf_delete_from_if (struct interface *ifp, struct ospf_interface *oi) { struct route_node *rn; struct prefix p; p = *oi->address; p.prefixlen = IPV4_MAX_PREFIXLEN; rn = route_node_lookup (IF_OIFS (oi->ifp), &p); assert (rn); assert (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } struct ospf_interface * ospf_if_new (struct ospf *ospf, struct interface *ifp, struct prefix *p) { struct ospf_interface *oi; if ((oi = ospf_if_table_lookup (ifp, p)) == NULL) { oi = XCALLOC (MTYPE_OSPF_IF, sizeof (struct ospf_interface)); memset (oi, 0, sizeof (struct ospf_interface)); } else return oi; /* Set zebra interface pointer. */ oi->ifp = ifp; oi->address = p; ospf_add_to_if (ifp, oi); listnode_add (ospf->oiflist, oi); /* Initialize neighbor list. */ oi->nbrs = route_table_init (); /* Initialize static neighbor list. */ oi->nbr_nbma = list_new (); /* Initialize Link State Acknowledgment list. */ oi->ls_ack = list_new (); oi->ls_ack_direct.ls_ack = list_new (); /* Set default values. */ ospf_if_reset_variables (oi); /* Add pseudo neighbor. */ oi->nbr_self = ospf_nbr_new (oi); oi->ls_upd_queue = route_table_init (); oi->t_ls_upd_event = NULL; oi->t_ls_ack_direct = NULL; oi->crypt_seqnum = time (NULL); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_init (oi); #endif /* HAVE_OPAQUE_LSA */ oi->ospf = ospf; return oi; } /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup (struct ospf_interface *oi) { struct route_node *rn; struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ for (ALL_LIST_ELEMENTS (oi->nbr_nbma, node, nnode, nbr_nbma)) { OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); if (nbr_nbma->nbr) { nbr_nbma->nbr->nbr_nbma = NULL; nbr_nbma->nbr = NULL; } nbr_nbma->oi = NULL; listnode_delete (oi->nbr_nbma, nbr_nbma); } /* send Neighbor event KillNbr to all associated neighbors. */ for (rn = route_top (oi->nbrs); rn; rn = route_next (rn)) if ((nbr = rn->info) != NULL) if (nbr != oi->nbr_self) OSPF_NSM_EVENT_EXECUTE (nbr, NSM_KillNbr); /* Cleanup Link State Acknowlegdment list. */ for (ALL_LIST_ELEMENTS (oi->ls_ack, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* oi->ls_ack */ list_delete_all_node (oi->ls_ack); oi->crypt_seqnum = 0; /* Empty link state update queue */ ospf_ls_upd_queue_empty (oi); /* Reset pseudo neighbor. */ ospf_nbr_delete (oi->nbr_self); oi->nbr_self = ospf_nbr_new (oi); ospf_nbr_add_self (oi); } void ospf_if_free (struct ospf_interface *oi) { ospf_if_down (oi); assert (oi->state == ISM_Down); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type9_lsa_term (oi); #endif /* HAVE_OPAQUE_LSA */ /* Free Pseudo Neighbour */ ospf_nbr_delete (oi->nbr_self); route_table_finish (oi->nbrs); route_table_finish (oi->ls_upd_queue); /* Free any lists that should be freed */ list_free (oi->nbr_nbma); list_free (oi->ls_ack); list_free (oi->ls_ack_direct.ls_ack); ospf_delete_from_if (oi->ifp, oi); listnode_delete (oi->ospf->oiflist, oi); listnode_delete (oi->area->oiflist, oi); thread_cancel_event (master, oi); memset (oi, 0, sizeof (*oi)); XFREE (MTYPE_OSPF_IF, oi); } /* * check if interface with given address is configured and * return it if yes. special treatment for PtP networks. */ struct ospf_interface * ospf_if_is_configured (struct ospf *ospf, struct in_addr *address) { struct listnode *node, *nnode; struct ospf_interface *oi; struct prefix_ipv4 addr; addr.family = AF_INET; addr.prefix = *address; addr.prefixlen = IPV4_MAX_PREFIXLEN; for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) { if (oi->type == OSPF_IFTYPE_POINTOPOINT) { /* special leniency: match if addr is anywhere on peer subnet */ if (prefix_match(CONNECTED_PREFIX(oi->connected), (struct prefix *)&addr)) return oi; } else { if (IPV4_ADDR_SAME (address, &oi->address->u.prefix4)) return oi; } } return NULL; } int ospf_if_is_up (struct ospf_interface *oi) { return if_is_up (oi->ifp); } struct ospf_interface * ospf_if_exists (struct ospf_interface *oic) { struct listnode *node; struct ospf *ospf; struct ospf_interface *oi; if ((ospf = ospf_lookup ()) == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (oi == oic) return oi; return NULL; } /* Lookup OSPF interface by router LSA posistion */ struct ospf_interface * ospf_if_lookup_by_lsa_pos (struct ospf_area *area, int lsa_pos) { struct listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) { if (lsa_pos >= oi->lsa_pos_beg && lsa_pos < oi->lsa_pos_end) return oi; } return NULL; } struct ospf_interface * ospf_if_lookup_by_local_addr (struct ospf *ospf, struct interface *ifp, struct in_addr address) { struct listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (oi->type != OSPF_IFTYPE_VIRTUALLINK) { if (ifp && oi->ifp != ifp) continue; if (IPV4_ADDR_SAME (&address, &oi->address->u.prefix4)) return oi; } return NULL; } struct ospf_interface * ospf_if_lookup_by_prefix (struct ospf *ospf, struct prefix_ipv4 *p) { struct listnode *node; struct ospf_interface *oi; /* Check each Interface. */ for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { if (oi->type != OSPF_IFTYPE_VIRTUALLINK) { struct prefix ptmp; prefix_copy (&ptmp, CONNECTED_PREFIX(oi->connected)); apply_mask (&ptmp); if (prefix_same (&ptmp, (struct prefix *) p)) return oi; } } return NULL; } /* determine receiving interface by ifp and source address */ struct ospf_interface * ospf_if_lookup_recv_if (struct ospf *ospf, struct in_addr src, struct interface *ifp) { struct route_node *rn; struct prefix_ipv4 addr; struct ospf_interface *oi, *match; addr.family = AF_INET; addr.prefix = src; addr.prefixlen = IPV4_MAX_BITLEN; match = NULL; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { oi = rn->info; if (!oi) /* oi can be NULL for PtP aliases */ continue; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; if (if_is_loopback (oi->ifp)) continue; if (prefix_match (CONNECTED_PREFIX(oi->connected), (struct prefix *) &addr)) { if ( (match == NULL) || (match->address->prefixlen < oi->address->prefixlen) ) match = oi; } } return match; } void ospf_if_stream_set (struct ospf_interface *oi) { /* set output fifo queue. */ if (oi->obuf == NULL) oi->obuf = ospf_fifo_new (); } void ospf_if_stream_unset (struct ospf_interface *oi) { struct ospf *ospf = oi->ospf; if (oi->obuf) { ospf_fifo_free (oi->obuf); oi->obuf = NULL; if (oi->on_write_q) { listnode_delete (ospf->oi_write_q, oi); if (list_isempty(ospf->oi_write_q)) OSPF_TIMER_OFF (ospf->t_write); oi->on_write_q = 0; } } } static struct ospf_if_params * ospf_new_if_params (void) { struct ospf_if_params *oip; oip = XCALLOC (MTYPE_OSPF_IF_PARAMS, sizeof (struct ospf_if_params)); if (!oip) return NULL; UNSET_IF_PARAM (oip, output_cost_cmd); UNSET_IF_PARAM (oip, transmit_delay); UNSET_IF_PARAM (oip, retransmit_interval); UNSET_IF_PARAM (oip, passive_interface); UNSET_IF_PARAM (oip, v_hello); UNSET_IF_PARAM (oip, fast_hello); UNSET_IF_PARAM (oip, v_wait); UNSET_IF_PARAM (oip, priority); UNSET_IF_PARAM (oip, type); UNSET_IF_PARAM (oip, auth_simple); UNSET_IF_PARAM (oip, auth_crypt); UNSET_IF_PARAM (oip, auth_type); oip->auth_crypt = list_new (); oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER); return oip; } void ospf_del_if_params (struct ospf_if_params *oip) { list_delete (oip->auth_crypt); XFREE (MTYPE_OSPF_IF_PARAMS, oip); } void ospf_free_if_params (struct interface *ifp, struct in_addr addr) { struct ospf_if_params *oip; struct prefix_ipv4 p; struct route_node *rn; p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = addr; rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); if (!rn || !rn->info) return; oip = rn->info; route_unlock_node (rn); if (!OSPF_IF_PARAM_CONFIGURED (oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED (oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED (oip, retransmit_interval) && !OSPF_IF_PARAM_CONFIGURED (oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED (oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED (oip, fast_hello) && !OSPF_IF_PARAM_CONFIGURED (oip, v_wait) && !OSPF_IF_PARAM_CONFIGURED (oip, priority) && !OSPF_IF_PARAM_CONFIGURED (oip, type) && !OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) && !OSPF_IF_PARAM_CONFIGURED (oip, auth_type) && listcount (oip->auth_crypt) == 0 && ntohl (oip->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { ospf_del_if_params (oip); rn->info = NULL; route_unlock_node (rn); } } struct ospf_if_params * ospf_lookup_if_params (struct interface *ifp, struct in_addr addr) { struct prefix_ipv4 p; struct route_node *rn; p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = addr; rn = route_node_lookup (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); if (rn) { route_unlock_node (rn); return rn->info; } return NULL; } struct ospf_if_params * ospf_get_if_params (struct interface *ifp, struct in_addr addr) { struct prefix_ipv4 p; struct route_node *rn; p.family = AF_INET; p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = addr; rn = route_node_get (IF_OIFS_PARAMS (ifp), (struct prefix*)&p); if (rn->info == NULL) rn->info = ospf_new_if_params (); else route_unlock_node (rn); return rn->info; } void ospf_if_update_params (struct interface *ifp, struct in_addr addr) { struct route_node *rn; struct ospf_interface *oi; for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { if ((oi = rn->info) == NULL) continue; if (IPV4_ADDR_SAME (&oi->address->u.prefix4, &addr)) oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); } } int ospf_if_new_hook (struct interface *ifp) { int rc = 0; ifp->info = XCALLOC (MTYPE_OSPF_IF_INFO, sizeof (struct ospf_if_info)); IF_OIFS (ifp) = route_table_init (); IF_OIFS_PARAMS (ifp) = route_table_init (); IF_DEF_PARAMS (ifp) = ospf_new_if_params (); SET_IF_PARAM (IF_DEF_PARAMS (ifp), transmit_delay); IF_DEF_PARAMS (ifp)->transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), retransmit_interval); IF_DEF_PARAMS (ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), priority); IF_DEF_PARAMS (ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; IF_DEF_PARAMS (ifp)->mtu_ignore = OSPF_MTU_IGNORE_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_hello); IF_DEF_PARAMS (ifp)->v_hello = OSPF_HELLO_INTERVAL_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), fast_hello); IF_DEF_PARAMS (ifp)->fast_hello = OSPF_FAST_HELLO_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), v_wait); IF_DEF_PARAMS (ifp)->v_wait = OSPF_ROUTER_DEAD_INTERVAL_DEFAULT; SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_simple); memset (IF_DEF_PARAMS (ifp)->auth_simple, 0, OSPF_AUTH_SIMPLE_SIZE); SET_IF_PARAM (IF_DEF_PARAMS (ifp), auth_type); IF_DEF_PARAMS (ifp)->auth_type = OSPF_AUTH_NOTSET; #ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_new_if (ifp); #endif /* HAVE_OPAQUE_LSA */ return rc; } static int ospf_if_delete_hook (struct interface *ifp) { int rc = 0; struct route_node *rn; #ifdef HAVE_OPAQUE_LSA rc = ospf_opaque_del_if (ifp); #endif /* HAVE_OPAQUE_LSA */ route_table_finish (IF_OIFS (ifp)); for (rn = route_top (IF_OIFS_PARAMS (ifp)); rn; rn = route_next (rn)) if (rn->info) ospf_del_if_params (rn->info); route_table_finish (IF_OIFS_PARAMS (ifp)); ospf_del_if_params ((struct ospf_if_params *) IF_DEF_PARAMS (ifp)); XFREE (MTYPE_OSPF_IF_INFO, ifp->info); ifp->info = NULL; return rc; } int ospf_if_is_enable (struct ospf_interface *oi) { if (!if_is_loopback (oi->ifp)) if (if_is_up (oi->ifp)) return 1; return 0; } void ospf_if_set_multicast(struct ospf_interface *oi) { if ((oi->state > ISM_Loopback) && (oi->type != OSPF_IFTYPE_LOOPBACK) && (oi->type != OSPF_IFTYPE_VIRTUALLINK) && (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_ACTIVE)) { /* The interface should belong to the OSPF-all-routers group. */ if (!OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) && (ospf_if_add_allspfrouters(oi->ospf, oi->address, oi->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join succeeded. */ OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS); } else { /* The interface should NOT belong to the OSPF-all-routers group. */ if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { /* Only actually drop if this is the last reference */ if (OI_MEMBER_COUNT(oi, MEMBER_ALLROUTERS) == 1) ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave the group succeeded, since it's much safer to assume that we are not a member. */ OI_MEMBER_LEFT(oi,MEMBER_ALLROUTERS); } } if (((oi->type == OSPF_IFTYPE_BROADCAST) || (oi->type == OSPF_IFTYPE_POINTOPOINT)) && ((oi->state == ISM_DR) || (oi->state == ISM_Backup)) && (OSPF_IF_PASSIVE_STATUS(oi) == OSPF_IF_ACTIVE)) { /* The interface should belong to the OSPF-designated-routers group. */ if (!OI_MEMBER_CHECK(oi, MEMBER_DROUTERS) && (ospf_if_add_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex) >= 0)) /* Set the flag only if the system call to join succeeded. */ OI_MEMBER_JOINED(oi, MEMBER_DROUTERS); } else { /* The interface should NOT belong to the OSPF-designated-routers group */ if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { /* drop only if last reference */ if (OI_MEMBER_COUNT(oi, MEMBER_DROUTERS) == 1) ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex); /* Unset the flag regardless of whether the system call to leave the group succeeded, since it's much safer to assume that we are not a member. */ OI_MEMBER_LEFT(oi, MEMBER_DROUTERS); } } } int ospf_if_up (struct ospf_interface *oi) { if (oi == NULL) return 0; if (oi->type == OSPF_IFTYPE_LOOPBACK) OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd); else { struct ospf *ospf = ospf_lookup (); if (ospf != NULL) ospf_adjust_sndbuflen (ospf, oi->ifp->mtu); else zlog_warn ("%s: ospf_lookup() returned NULL", __func__); ospf_if_stream_set (oi); OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp); } return 1; } int ospf_if_down (struct ospf_interface *oi) { if (oi == NULL) return 0; OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); /* delete position in router LSA */ oi->lsa_pos_beg = 0; oi->lsa_pos_end = 0; /* Shutdown packet reception and sending */ ospf_if_stream_unset (oi); return 1; } /* Virtual Link related functions. */ struct ospf_vl_data * ospf_vl_data_new (struct ospf_area *area, struct in_addr vl_peer) { struct ospf_vl_data *vl_data; vl_data = XCALLOC (MTYPE_OSPF_VL_DATA, sizeof (struct ospf_vl_data)); vl_data->vl_peer.s_addr = vl_peer.s_addr; vl_data->vl_area_id = area->area_id; vl_data->format = area->format; return vl_data; } void ospf_vl_data_free (struct ospf_vl_data *vl_data) { XFREE (MTYPE_OSPF_VL_DATA, vl_data); } u_int vlink_count = 0; struct ospf_interface * ospf_vl_new (struct ospf *ospf, struct ospf_vl_data *vl_data) { struct ospf_interface * voi; struct interface * vi; char ifname[INTERFACE_NAMSIZ + 1]; struct ospf_area *area; struct in_addr area_id; struct connected *co; struct prefix_ipv4 *p; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Start"); if (vlink_count == OSPF_VL_MAX_COUNT) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Alarm: " "cannot create more than OSPF_MAX_VL_COUNT virtual links"); return NULL; } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): creating pseudo zebra interface"); snprintf (ifname, sizeof(ifname), "VLINK%d", vlink_count); vi = if_create (ifname, strnlen(ifname, sizeof(ifname))); co = connected_new (); co->ifp = vi; listnode_add (vi->connected, co); p = prefix_ipv4_new (); p->family = AF_INET; p->prefix.s_addr = 0; p->prefixlen = 0; co->address = (struct prefix *)p; voi = ospf_if_new (ospf, vi, co->address); if (voi == NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Alarm: OSPF int structure is not created"); return NULL; } voi->connected = co; voi->vl_data = vl_data; voi->ifp->mtu = OSPF_VL_MTU; voi->type = OSPF_IFTYPE_VIRTUALLINK; vlink_count++; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Created name: %s", ifname); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): set if->name to %s", vi->name); area_id.s_addr = 0; area = ospf_area_get (ospf, area_id, OSPF_AREA_ID_FORMAT_ADDRESS); voi->area = area; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): set associated area to the backbone"); ospf_nbr_add_self (voi); ospf_area_add_if (voi->area, voi); ospf_if_stream_set (voi); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_new(): Stop"); return voi; } static void ospf_vl_if_delete (struct ospf_vl_data *vl_data) { struct interface *ifp = vl_data->vl_oi->ifp; vl_data->vl_oi->address->u.prefix4.s_addr = 0; vl_data->vl_oi->address->prefixlen = 0; ospf_if_free (vl_data->vl_oi); if_delete (ifp); vlink_count--; } /* Look up vl_data for given peer, optionally qualified to be in the * specified area. NULL area returns first found.. */ struct ospf_vl_data * ospf_vl_lookup (struct ospf *ospf, struct ospf_area *area, struct in_addr vl_peer) { struct ospf_vl_data *vl_data; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("%s: Looking for %s", __func__, inet_ntoa (vl_peer)); if (area) zlog_debug ("%s: in area %s", __func__, inet_ntoa (area->area_id)); } for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: VL %s, peer %s", __func__, vl_data->vl_oi->ifp->name, inet_ntoa (vl_data->vl_peer)); if (area && !IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) continue; if (IPV4_ADDR_SAME (&vl_data->vl_peer, &vl_peer)) return vl_data; } return NULL; } static void ospf_vl_shutdown (struct ospf_vl_data *vl_data) { struct ospf_interface *oi; if ((oi = vl_data->vl_oi) == NULL) return; oi->address->u.prefix4.s_addr = 0; oi->address->prefixlen = 0; UNSET_FLAG (oi->ifp->flags, IFF_UP); /* OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceDown); */ OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown); } void ospf_vl_add (struct ospf *ospf, struct ospf_vl_data *vl_data) { listnode_add (ospf->vlinks, vl_data); #ifdef HAVE_SNMP ospf_snmp_vl_add (vl_data); #endif /* HAVE_SNMP */ } void ospf_vl_delete (struct ospf *ospf, struct ospf_vl_data *vl_data) { ospf_vl_shutdown (vl_data); ospf_vl_if_delete (vl_data); #ifdef HAVE_SNMP ospf_snmp_vl_delete (vl_data); #endif /* HAVE_SNMP */ listnode_delete (ospf->vlinks, vl_data); ospf_vl_data_free (vl_data); } static int ospf_vl_set_params (struct ospf_vl_data *vl_data, struct vertex *v) { int changed = 0; struct ospf_interface *voi; struct listnode *node; struct vertex_parent *vp = NULL; int i; struct router_lsa *rl; voi = vl_data->vl_oi; if (voi->output_cost != v->distance) { voi->output_cost = v->distance; changed = 1; } for (ALL_LIST_ELEMENTS_RO (v->parents, node, vp)) { vl_data->nexthop.oi = vp->nexthop->oi; vl_data->nexthop.router = vp->nexthop->router; if (!IPV4_ADDR_SAME(&voi->address->u.prefix4, &vl_data->nexthop.oi->address->u.prefix4)) changed = 1; voi->address->u.prefix4 = vl_data->nexthop.oi->address->u.prefix4; voi->address->prefixlen = vl_data->nexthop.oi->address->prefixlen; break; /* We take the first interface. */ } rl = (struct router_lsa *)v->lsa; /* use SPF determined backlink index in struct vertex * for virtual link destination address */ if (vp && vp->backlink >= 0) { if (!IPV4_ADDR_SAME (&vl_data->peer_addr, &rl->link[vp->backlink].link_data)) changed = 1; vl_data->peer_addr = rl->link[vp->backlink].link_data; } else { /* This is highly odd, there is no backlink index * there should be due to the ospf_spf_has_link() check * in SPF. Lets warn and try pick a link anyway. */ zlog_warn ("ospf_vl_set_params: No backlink for %s!", vl_data->vl_oi->ifp->name); for (i = 0; i < ntohs (rl->links); i++) { switch (rl->link[i].type) { case LSA_LINK_TYPE_VIRTUALLINK: if (IS_DEBUG_OSPF_EVENT) zlog_debug ("found back link through VL"); case LSA_LINK_TYPE_TRANSIT: case LSA_LINK_TYPE_POINTOPOINT: if (!IPV4_ADDR_SAME (&vl_data->peer_addr, &rl->link[i].link_data)) changed = 1; vl_data->peer_addr = rl->link[i].link_data; } } } if (IS_DEBUG_OSPF_EVENT) zlog_debug ("%s: %s peer address: %s, cost: %d,%schanged", __func__, vl_data->vl_oi->ifp->name, inet_ntoa(vl_data->peer_addr), voi->output_cost, (changed ? " " : " un")); return changed; } void ospf_vl_up_check (struct ospf_area *area, struct in_addr rid, struct vertex *v) { struct ospf *ospf = area->ospf; struct listnode *node; struct ospf_vl_data *vl_data; struct ospf_interface *oi; if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("ospf_vl_up_check(): Start"); zlog_debug ("ospf_vl_up_check(): Router ID is %s", inet_ntoa (rid)); zlog_debug ("ospf_vl_up_check(): Area is %s", inet_ntoa (area->area_id)); } for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("%s: considering VL, %s in area %s", __func__, vl_data->vl_oi->ifp->name, inet_ntoa (vl_data->vl_area_id)); zlog_debug ("%s: peer ID: %s", __func__, inet_ntoa (vl_data->vl_peer)); } if (IPV4_ADDR_SAME (&vl_data->vl_peer, &rid) && IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) { oi = vl_data->vl_oi; SET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_up_check(): this VL matched"); if (oi->state == ISM_Down) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("ospf_vl_up_check(): VL is down, waking it up"); SET_FLAG (oi->ifp->flags, IFF_UP); OSPF_ISM_EVENT_EXECUTE(oi,ISM_InterfaceUp); } if (ospf_vl_set_params (vl_data, v)) { if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog_debug ("ospf_vl_up_check: VL cost change," " scheduling router lsa refresh"); if (ospf->backbone) ospf_router_lsa_update_area (ospf->backbone); else if (IS_DEBUG_OSPF (ism, ISM_EVENTS)) zlog_debug ("ospf_vl_up_check: VL cost change, no backbone!"); } } } } void ospf_vl_unapprove (struct ospf *ospf) { struct listnode *node; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data)) UNSET_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED); } void ospf_vl_shut_unapproved (struct ospf *ospf) { struct listnode *node, *nnode; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) if (!CHECK_FLAG (vl_data->flags, OSPF_VL_FLAG_APPROVED)) ospf_vl_shutdown (vl_data); } int ospf_full_virtual_nbrs (struct ospf_area *area) { if (IS_DEBUG_OSPF_EVENT) { zlog_debug ("counting fully adjacent virtual neighbors in area %s", inet_ntoa (area->area_id)); zlog_debug ("there are %d of them", area->full_vls); } return area->full_vls; } int ospf_vls_in_area (struct ospf_area *area) { struct listnode *node; struct ospf_vl_data *vl_data; int c = 0; for (ALL_LIST_ELEMENTS_RO (area->ospf->vlinks, node, vl_data)) if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) c++; return c; } struct crypt_key * ospf_crypt_key_new () { return XCALLOC (MTYPE_OSPF_CRYPT_KEY, sizeof (struct crypt_key)); } void ospf_crypt_key_add (struct list *crypt, struct crypt_key *ck) { listnode_add (crypt, ck); } struct crypt_key * ospf_crypt_key_lookup (struct list *auth_crypt, u_char key_id) { struct listnode *node; struct crypt_key *ck; for (ALL_LIST_ELEMENTS_RO (auth_crypt, node, ck)) if (ck->key_id == key_id) return ck; return NULL; } int ospf_crypt_key_delete (struct list *auth_crypt, u_char key_id) { struct listnode *node, *nnode; struct crypt_key *ck; for (ALL_LIST_ELEMENTS (auth_crypt, node, nnode, ck)) { if (ck->key_id == key_id) { listnode_delete (auth_crypt, ck); XFREE (MTYPE_OSPF_CRYPT_KEY, ck); return 1; } } return 0; } u_char ospf_default_iftype(struct interface *ifp) { if (if_is_pointopoint (ifp)) return OSPF_IFTYPE_POINTOPOINT; else if (if_is_loopback (ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; } void ospf_if_init () { /* Initialize Zebra interface data structure. */ if_init (); om->iflist = iflist; if_add_hook (IF_NEW_HOOK, ospf_if_new_hook); if_add_hook (IF_DELETE_HOOK, ospf_if_delete_hook); } quagga-0.99.24.1/ospfd/ospf_zebra.c0000644000175000017500000010503312476520570013647 00000000000000/* * Zebra connect library for OSPFd * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "command.h" #include "network.h" #include "prefix.h" #include "routemap.h" #include "table.h" #include "stream.h" #include "memory.h" #include "zclient.h" #include "filter.h" #include "plist.h" #include "log.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_zebra.h" #ifdef HAVE_SNMP #include "ospfd/ospf_snmp.h" #endif /* HAVE_SNMP */ /* Zebra structure to hold current status. */ struct zclient *zclient = NULL; /* For registering threads. */ extern struct thread_master *master; struct in_addr router_id_zebra; /* Router-id update message from zebra. */ static int ospf_router_id_update_zebra (int command, struct zclient *zclient, zebra_size_t length) { struct ospf *ospf; struct prefix router_id; zebra_router_id_update_read(zclient->ibuf,&router_id); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(&router_id, buf, sizeof(buf)); zlog_debug("Zebra rcvd: router id update %s", buf); } router_id_zebra = router_id.u.prefix4; ospf = ospf_lookup (); if (ospf != NULL) ospf_router_id_update (ospf); return 0; } /* Inteface addition message from zebra. */ static int ospf_interface_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: interface add %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); assert (ifp->info); if (!OSPF_IF_PARAM_CONFIGURED (IF_DEF_PARAMS (ifp), type)) { SET_IF_PARAM (IF_DEF_PARAMS (ifp), type); IF_DEF_PARAMS (ifp)->type = ospf_default_iftype(ifp); } ospf_if_update (NULL, ifp); #ifdef HAVE_SNMP ospf_snmp_if_update (ifp); #endif /* HAVE_SNMP */ return 0; } static int ospf_interface_delete (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct stream *s; struct route_node *rn; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; if (if_is_up (ifp)) zlog_warn ("Zebra: got delete of %s, but interface is still up", ifp->name); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: interface delete %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); #ifdef HAVE_SNMP ospf_snmp_if_delete (ifp); #endif /* HAVE_SNMP */ for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) if (rn->info) ospf_if_free ((struct ospf_interface *) rn->info); ifp->ifindex = IFINDEX_INTERNAL; return 0; } static struct interface * zebra_interface_if_lookup (struct stream *s) { char ifname_tmp[INTERFACE_NAMSIZ]; /* Read interface name. */ stream_get (ifname_tmp, s, INTERFACE_NAMSIZ); /* And look it up. */ return if_lookup_by_name_len(ifname_tmp, strnlen(ifname_tmp, INTERFACE_NAMSIZ)); } static int ospf_interface_state_up (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; ifp = zebra_interface_if_lookup (zclient->ibuf); if (ifp == NULL) return 0; /* Interface is already up. */ if (if_is_operative (ifp)) { /* Temporarily keep ifp values. */ struct interface if_tmp; memcpy (&if_tmp, ifp, sizeof (struct interface)); zebra_interface_if_set_value (zclient->ibuf, ifp); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] state update.", ifp->name); if (if_tmp.bandwidth != ifp->bandwidth) { if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] bandwidth change %d -> %d.", ifp->name, if_tmp.bandwidth, ifp->bandwidth); ospf_if_recalculate_output_cost (ifp); } if (if_tmp.mtu != ifp->mtu) { if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] MTU change %u -> %u.", ifp->name, if_tmp.mtu, ifp->mtu); /* Must reset the interface (simulate down/up) when MTU changes. */ ospf_if_reset(ifp); } return 0; } zebra_interface_if_set_value (zclient->ibuf, ifp); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] state change to up.", ifp->name); for (rn = route_top (IF_OIFS (ifp)); rn; rn = route_next (rn)) { if ((oi = rn->info) == NULL) continue; ospf_if_up (oi); } return 0; } static int ospf_interface_state_down (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct ospf_interface *oi; struct route_node *node; ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("Zebra: Interface[%s] state change to down.", ifp->name); for (node = route_top (IF_OIFS (ifp)); node; node = route_next (node)) { if ((oi = node->info) == NULL) continue; ospf_if_down (oi); } return 0; } static int ospf_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; c = zebra_interface_address_read (command, zclient->ibuf); if (c == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address add %s", c->ifp->name, buf); } ospf_if_update (NULL, c->ifp); #ifdef HAVE_SNMP ospf_snmp_if_update (c->ifp); #endif /* HAVE_SNMP */ return 0; } static int ospf_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; struct interface *ifp; struct ospf_interface *oi; struct route_node *rn; struct prefix p; c = zebra_interface_address_read (command, zclient->ibuf); if (c == NULL) return 0; if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) { char buf[128]; prefix2str(c->address, buf, sizeof(buf)); zlog_debug("Zebra: interface %s address delete %s", c->ifp->name, buf); } ifp = c->ifp; p = *c->address; p.prefixlen = IPV4_MAX_PREFIXLEN; rn = route_node_lookup (IF_OIFS (ifp), &p); if (!rn) { connected_free (c); return 0; } assert (rn->info); oi = rn->info; /* Call interface hook functions to clean up */ ospf_if_free (oi); #ifdef HAVE_SNMP ospf_snmp_if_update (c->ifp); #endif /* HAVE_SNMP */ connected_free (c); return 0; } void ospf_zebra_add (struct prefix_ipv4 *p, struct ospf_route *or) { u_char message; u_char distance; u_char flags; int psize; struct stream *s; struct ospf_path *path; struct listnode *node; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { message = 0; flags = 0; /* OSPF pass nexthop and metric */ SET_FLAG (message, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (message, ZAPI_MESSAGE_METRIC); /* Distance value. */ distance = ospf_distance_apply (p, or); if (distance) SET_FLAG (message, ZAPI_MESSAGE_DISTANCE); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_ADD); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); stream_putw (s, SAFI_UNICAST); /* Put prefix information. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *) & p->prefix, psize); /* Nexthop count. */ stream_putc (s, or->paths->count); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { stream_putc (s, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (s, &path->nexthop); } else { stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); if (path->ifindex) stream_putl (s, path->ifindex); else stream_putl (s, 0); } if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra: Route add %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); } } if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (s, distance); if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) { if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) stream_putl (s, or->cost + or->u.ext.type2_cost); else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) stream_putl (s, or->u.ext.type2_cost); else stream_putl (s, or->cost); } stream_putw_at (s, 0, stream_get_endp (s)); zclient_send_message(zclient); } } void ospf_zebra_delete (struct prefix_ipv4 *p, struct ospf_route *or) { u_char message; u_char distance; u_char flags; int psize; struct stream *s; struct ospf_path *path; struct listnode *node; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { message = 0; flags = 0; /* Distance value. */ distance = ospf_distance_apply (p, or); /* Make packet. */ s = zclient->obuf; stream_reset (s); /* Put command, type, flags, message. */ zclient_create_header (s, ZEBRA_IPV4_ROUTE_DELETE); stream_putc (s, ZEBRA_ROUTE_OSPF); stream_putc (s, flags); stream_putc (s, message); stream_putw (s, SAFI_UNICAST); /* Put prefix information. */ psize = PSIZE (p->prefixlen); stream_putc (s, p->prefixlen); stream_write (s, (u_char *) & p->prefix, psize); /* Nexthop count. */ stream_putc (s, or->paths->count); /* Nexthop, ifindex, distance and metric information. */ for (ALL_LIST_ELEMENTS_RO (or->paths, node, path)) { if (path->nexthop.s_addr != INADDR_ANY && path->ifindex != 0) { stream_putc (s, ZEBRA_NEXTHOP_IPV4_IFINDEX); stream_put_in_addr (s, &path->nexthop); stream_putl (s, path->ifindex); } else if (path->nexthop.s_addr != INADDR_ANY) { stream_putc (s, ZEBRA_NEXTHOP_IPV4); stream_put_in_addr (s, &path->nexthop); } else { stream_putc (s, ZEBRA_NEXTHOP_IFINDEX); stream_putl (s, path->ifindex); } if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra: Route delete %s/%d nexthop %s", inet_ntop(AF_INET, &p->prefix, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, &path->nexthop, buf[1], sizeof(buf[1]))); } } if (CHECK_FLAG (message, ZAPI_MESSAGE_DISTANCE)) stream_putc (s, distance); if (CHECK_FLAG (message, ZAPI_MESSAGE_METRIC)) { if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL) stream_putl (s, or->cost + or->u.ext.type2_cost); else if (or->path_type == OSPF_PATH_TYPE2_EXTERNAL) stream_putl (s, or->u.ext.type2_cost); else stream_putl (s, or->cost); } stream_putw_at (s, 0, stream_get_endp (s)); zclient_send_message(zclient); } } void ospf_zebra_add_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, p, &api); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Zebra: Route add discard %s/%d", inet_ntoa (p->prefix), p->prefixlen); } } void ospf_zebra_delete_discard (struct prefix_ipv4 *p) { struct zapi_ipv4 api; if (zclient->redist[ZEBRA_ROUTE_OSPF]) { api.type = ZEBRA_ROUTE_OSPF; api.flags = ZEBRA_FLAG_BLACKHOLE; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 0; api.ifindex_num = 0; zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, p, &api); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Zebra: Route delete discard %s/%d", inet_ntoa (p->prefix), p->prefixlen); } } int ospf_is_type_redistributed (int type) { return (DEFAULT_ROUTE_TYPE (type)) ? zclient->default_information : zclient->redist[type]; } int ospf_redistribute_set (struct ospf *ospf, int type, int mtype, int mvalue) { int force = 0; if (ospf_is_type_redistributed (type)) { if (mtype != ospf->dmetric[type].type) { ospf->dmetric[type].type = mtype; force = LSA_REFRESH_FORCE; } if (mvalue != ospf->dmetric[type].value) { ospf->dmetric[type].value = mvalue; force = LSA_REFRESH_FORCE; } ospf_external_lsa_refresh_type (ospf, type, force); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", ospf_redist_string(type), metric_type (ospf, type), metric_value (ospf, type)); return CMD_SUCCESS; } ospf->dmetric[type].type = mtype; ospf->dmetric[type].value = mvalue; zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Start Type[%d], Metric[%d]", ospf_redist_string(type), metric_type (ospf, type), metric_value (ospf, type)); ospf_asbr_status_update (ospf, ++ospf->redistribute); return CMD_SUCCESS; } int ospf_redistribute_unset (struct ospf *ospf, int type) { if (type == zclient->redist_default) return CMD_SUCCESS; if (!ospf_is_type_redistributed (type)) return CMD_SUCCESS; zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Stop", ospf_redist_string(type)); ospf->dmetric[type].type = -1; ospf->dmetric[type].value = -1; /* Remove the routes from OSPF table. */ ospf_redistribute_withdraw (ospf, type); ospf_asbr_status_update (ospf, --ospf->redistribute); return CMD_SUCCESS; } int ospf_redistribute_default_set (struct ospf *ospf, int originate, int mtype, int mvalue) { ospf->default_originate = originate; ospf->dmetric[DEFAULT_ROUTE].type = mtype; ospf->dmetric[DEFAULT_ROUTE].value = mvalue; if (ospf_is_type_redistributed (DEFAULT_ROUTE)) { /* if ospf->default_originate changes value, is calling ospf_external_lsa_refresh_default sufficient to implement the change? */ ospf_external_lsa_refresh_default (ospf); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: Refresh Type[%d], Metric[%d]", ospf_redist_string(DEFAULT_ROUTE), metric_type (ospf, DEFAULT_ROUTE), metric_value (ospf, DEFAULT_ROUTE)); return CMD_SUCCESS; } zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD, zclient); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[DEFAULT]: Start Type[%d], Metric[%d]", metric_type (ospf, DEFAULT_ROUTE), metric_value (ospf, DEFAULT_ROUTE)); if (ospf->router_id.s_addr == 0) ospf->external_origin |= (1 << DEFAULT_ROUTE); else thread_add_timer (master, ospf_default_originate_timer, ospf, 1); ospf_asbr_status_update (ospf, ++ospf->redistribute); return CMD_SUCCESS; } int ospf_redistribute_default_unset (struct ospf *ospf) { if (!ospf_is_type_redistributed (DEFAULT_ROUTE)) return CMD_SUCCESS; ospf->default_originate = DEFAULT_ORIGINATE_NONE; ospf->dmetric[DEFAULT_ROUTE].type = -1; ospf->dmetric[DEFAULT_ROUTE].value = -1; zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE, zclient); if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[DEFAULT]: Stop"); ospf_asbr_status_update (ospf, --ospf->redistribute); return CMD_SUCCESS; } static int ospf_external_lsa_originate_check (struct ospf *ospf, struct external_info *ei) { /* If prefix is multicast, then do not originate LSA. */ if (IN_MULTICAST (htonl (ei->p.prefix.s_addr))) { zlog_info ("LSA[Type5:%s]: Not originate AS-external-LSA, " "Prefix belongs multicast", inet_ntoa (ei->p.prefix)); return 0; } /* Take care of default-originate. */ if (is_prefix_default (&ei->p)) if (ospf->default_originate == DEFAULT_ORIGINATE_NONE) { zlog_info ("LSA[Type5:0.0.0.0]: Not originate AS-external-LSA " "for default"); return 0; } return 1; } /* If connected prefix is OSPF enable interface, then do not announce. */ int ospf_distribute_check_connected (struct ospf *ospf, struct external_info *ei) { struct listnode *node; struct ospf_interface *oi; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) if (prefix_match (oi->address, (struct prefix *) &ei->p)) return 0; return 1; } /* return 1 if external LSA must be originated, 0 otherwise */ int ospf_redistribute_check (struct ospf *ospf, struct external_info *ei, int *changed) { struct route_map_set_values save_values; struct prefix_ipv4 *p = &ei->p; u_char type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type; if (changed) *changed = 0; if (!ospf_external_lsa_originate_check (ospf, ei)) return 0; /* Take care connected route. */ if (type == ZEBRA_ROUTE_CONNECT && !ospf_distribute_check_connected (ospf, ei)) return 0; if (!DEFAULT_ROUTE_TYPE (type) && DISTRIBUTE_NAME (ospf, type)) /* distirbute-list exists, but access-list may not? */ if (DISTRIBUTE_LIST (ospf, type)) if (access_list_apply (DISTRIBUTE_LIST (ospf, type), p) == FILTER_DENY) { if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: %s/%d filtered by ditribute-list.", ospf_redist_string(type), inet_ntoa (p->prefix), p->prefixlen); return 0; } save_values = ei->route_map_set; ospf_reset_route_map_set_values (&ei->route_map_set); /* apply route-map if needed */ if (ROUTEMAP_NAME (ospf, type)) { int ret; ret = route_map_apply (ROUTEMAP (ospf, type), (struct prefix *) p, RMAP_OSPF, ei); if (ret == RMAP_DENYMATCH) { ei->route_map_set = save_values; if (IS_DEBUG_OSPF (zebra, ZEBRA_REDISTRIBUTE)) zlog_debug ("Redistribute[%s]: %s/%d filtered by route-map.", ospf_redist_string(type), inet_ntoa (p->prefix), p->prefixlen); return 0; } /* check if 'route-map set' changed something */ if (changed) *changed = !ospf_route_map_set_compare (&ei->route_map_set, &save_values); } return 1; } /* OSPF route-map set for redistribution */ void ospf_routemap_set (struct ospf *ospf, int type, const char *name) { if (ROUTEMAP_NAME (ospf, type)) free (ROUTEMAP_NAME (ospf, type)); ROUTEMAP_NAME (ospf, type) = strdup (name); ROUTEMAP (ospf, type) = route_map_lookup_by_name (name); } void ospf_routemap_unset (struct ospf *ospf, int type) { if (ROUTEMAP_NAME (ospf, type)) free (ROUTEMAP_NAME (ospf, type)); ROUTEMAP_NAME (ospf, type) = NULL; ROUTEMAP (ospf, type) = NULL; } /* Zebra route add and delete treatment. */ static int ospf_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; struct external_info *ei; struct ospf *ospf; s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); if (IPV4_NET127(ntohl(p.prefix.s_addr))) return 0; /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop.s_addr = stream_get_ipv4 (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); /* XXX assert(api.ifindex_num == 1); */ ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); ospf = ospf_lookup (); if (ospf == NULL) return 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { /* XXX|HACK|TODO|FIXME: * Maybe we should ignore reject/blackhole routes? Testing shows that * there is no problems though and this is only way to "summarize" * routes in ASBR at the moment. Maybe we need just a better generalised * solution for these types? * * if ( CHECK_FLAG (api.flags, ZEBRA_FLAG_BLACKHOLE) * || CHECK_FLAG (api.flags, ZEBRA_FLAG_REJECT)) * return 0; */ ei = ospf_external_info_add (api.type, p, ifindex, nexthop); if (ospf->router_id.s_addr == 0) /* Set flags to generate AS-external-LSA originate event for each redistributed protocols later. */ ospf->external_origin |= (1 << api.type); else { if (ei) { if (is_prefix_default (&p)) ospf_external_lsa_refresh_default (ospf); else { struct ospf_lsa *current; current = ospf_external_info_find_lsa (ospf, &ei->p); if (!current) ospf_external_lsa_originate (ospf, ei); else if (IS_LSA_MAXAGE (current)) ospf_external_lsa_refresh (ospf, current, ei, LSA_REFRESH_FORCE); else zlog_warn ("ospf_zebra_read_ipv4() : %s already exists", inet_ntoa (p.prefix)); } } } } else /* if (command == ZEBRA_IPV4_ROUTE_DELETE) */ { ospf_external_info_delete (api.type, p); if (is_prefix_default (&p)) ospf_external_lsa_refresh_default (ospf); else ospf_external_lsa_flush (ospf, api.type, &p, ifindex /*, nexthop */); } return 0; } int ospf_distribute_list_out_set (struct ospf *ospf, int type, const char *name) { /* Lookup access-list for distribute-list. */ DISTRIBUTE_LIST (ospf, type) = access_list_lookup (AFI_IP, name); /* Clear previous distribute-name. */ if (DISTRIBUTE_NAME (ospf, type)) free (DISTRIBUTE_NAME (ospf, type)); /* Set distribute-name. */ DISTRIBUTE_NAME (ospf, type) = strdup (name); /* If access-list have been set, schedule update timer. */ if (DISTRIBUTE_LIST (ospf, type)) ospf_distribute_list_update (ospf, type); return CMD_SUCCESS; } int ospf_distribute_list_out_unset (struct ospf *ospf, int type, const char *name) { /* Schedule update timer. */ if (DISTRIBUTE_LIST (ospf, type)) ospf_distribute_list_update (ospf, type); /* Unset distribute-list. */ DISTRIBUTE_LIST (ospf, type) = NULL; /* Clear distribute-name. */ if (DISTRIBUTE_NAME (ospf, type)) free (DISTRIBUTE_NAME (ospf, type)); DISTRIBUTE_NAME (ospf, type) = NULL; return CMD_SUCCESS; } /* distribute-list update timer. */ static int ospf_distribute_list_update_timer (struct thread *thread) { struct route_node *rn; struct external_info *ei; struct route_table *rt; struct ospf_lsa *lsa; int type, default_refresh = 0; struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) return 0; ospf->t_distribute_update = NULL; zlog_info ("Zebra[Redistribute]: distribute-list update timer fired!"); /* foreach all external info. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { rt = EXTERNAL_INFO (type); if (!rt) continue; for (rn = route_top (rt); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) { if (is_prefix_default (&ei->p)) default_refresh = 1; else if ((lsa = ospf_external_info_find_lsa (ospf, &ei->p))) ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_IF_CHANGED); else ospf_external_lsa_originate (ospf, ei); } } if (default_refresh) ospf_external_lsa_refresh_default (ospf); return 0; } #define OSPF_DISTRIBUTE_UPDATE_DELAY 5 /* Update distribute-list and set timer to apply access-list. */ void ospf_distribute_list_update (struct ospf *ospf, uintptr_t type) { struct route_table *rt; /* External info does not exist. */ if (!(rt = EXTERNAL_INFO (type))) return; /* If exists previously invoked thread, then let it continue. */ if (ospf->t_distribute_update) return; /* Set timer. */ ospf->t_distribute_update = thread_add_timer (master, ospf_distribute_list_update_timer, (void *) type, OSPF_DISTRIBUTE_UPDATE_DELAY); } /* If access-list is updated, apply some check. */ static void ospf_filter_update (struct access_list *access) { struct ospf *ospf; int type; int abr_inv = 0; struct ospf_area *area; struct listnode *node; /* If OSPF instatnce does not exist, return right now. */ ospf = ospf_lookup (); if (ospf == NULL) return; /* Update distribute-list, and apply filter. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (ROUTEMAP (ospf, type) != NULL) { /* if route-map is not NULL it may be using this access list */ ospf_distribute_list_update (ospf, type); continue; } /* There is place for route-map for default-information (ZEBRA_ROUTE_MAX), * but no distribute list. */ if (type == ZEBRA_ROUTE_MAX) break; if (DISTRIBUTE_NAME (ospf, type)) { /* Keep old access-list for distribute-list. */ struct access_list *old = DISTRIBUTE_LIST (ospf, type); /* Update access-list for distribute-list. */ DISTRIBUTE_LIST (ospf, type) = access_list_lookup (AFI_IP, DISTRIBUTE_NAME (ospf, type)); /* No update for this distribute type. */ if (old == NULL && DISTRIBUTE_LIST (ospf, type) == NULL) continue; /* Schedule distribute-list update timer. */ if (DISTRIBUTE_LIST (ospf, type) == NULL || strcmp (DISTRIBUTE_NAME (ospf, type), access->name) == 0) ospf_distribute_list_update (ospf, type); } } /* Update Area access-list. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { if (EXPORT_NAME (area)) { EXPORT_LIST (area) = NULL; abr_inv++; } if (IMPORT_NAME (area)) { IMPORT_LIST (area) = NULL; abr_inv++; } } /* Schedule ABR tasks -- this will be changed -- takada. */ if (IS_OSPF_ABR (ospf) && abr_inv) ospf_schedule_abr_task (ospf); } /* If prefix-list is updated, do some updates. */ void ospf_prefix_list_update (struct prefix_list *plist) { struct ospf *ospf; int type; int abr_inv = 0; struct ospf_area *area; struct listnode *node; /* If OSPF instatnce does not exist, return right now. */ ospf = ospf_lookup (); if (ospf == NULL) return; /* Update all route-maps which are used as redistribution filters. * They might use prefix-list. */ for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { if (ROUTEMAP (ospf, type) != NULL) { /* If route-map is not NULL it may be using this prefix list */ ospf_distribute_list_update (ospf, type); continue; } } /* Update area filter-lists. */ for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) { /* Update filter-list in. */ if (PREFIX_NAME_IN (area)) if (strcmp (PREFIX_NAME_IN (area), plist->name) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_IN (area)); abr_inv++; } /* Update filter-list out. */ if (PREFIX_NAME_OUT (area)) if (strcmp (PREFIX_NAME_OUT (area), plist->name) == 0) { PREFIX_LIST_IN (area) = prefix_list_lookup (AFI_IP, PREFIX_NAME_OUT (area)); abr_inv++; } } /* Schedule ABR task. */ if (IS_OSPF_ABR (ospf) && abr_inv) ospf_schedule_abr_task (ospf); } static struct ospf_distance * ospf_distance_new (void) { return XCALLOC (MTYPE_OSPF_DISTANCE, sizeof (struct ospf_distance)); } static void ospf_distance_free (struct ospf_distance *odistance) { XFREE (MTYPE_OSPF_DISTANCE, odistance); } int ospf_distance_set (struct vty *vty, struct ospf *ospf, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; u_char distance; struct route_node *rn; struct ospf_distance *odistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); /* Get OSPF distance node. */ rn = route_node_get (ospf->distance_table, (struct prefix *) &p); if (rn->info) { odistance = rn->info; route_unlock_node (rn); } else { odistance = ospf_distance_new (); rn->info = odistance; } /* Set distance value. */ odistance->distance = distance; /* Reset access-list configuration. */ if (odistance->access_list) { free (odistance->access_list); odistance->access_list = NULL; } if (access_list_str) odistance->access_list = strdup (access_list_str); return CMD_SUCCESS; } int ospf_distance_unset (struct vty *vty, struct ospf *ospf, const char *distance_str, const char *ip_str, char const *access_list_str) { int ret; struct prefix_ipv4 p; struct route_node *rn; struct ospf_distance *odistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } rn = route_node_lookup (ospf->distance_table, (struct prefix *) &p); if (!rn) { vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } odistance = rn->info; if (odistance->access_list) free (odistance->access_list); ospf_distance_free (odistance); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); return CMD_SUCCESS; } void ospf_distance_reset (struct ospf *ospf) { struct route_node *rn; struct ospf_distance *odistance; for (rn = route_top (ospf->distance_table); rn; rn = route_next (rn)) if ((odistance = rn->info) != NULL) { if (odistance->access_list) free (odistance->access_list); ospf_distance_free (odistance); rn->info = NULL; route_unlock_node (rn); } } u_char ospf_distance_apply (struct prefix_ipv4 *p, struct ospf_route *or) { struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) return 0; if (ospf->distance_intra) if (or->path_type == OSPF_PATH_INTRA_AREA) return ospf->distance_intra; if (ospf->distance_inter) if (or->path_type == OSPF_PATH_INTER_AREA) return ospf->distance_inter; if (ospf->distance_external) if (or->path_type == OSPF_PATH_TYPE1_EXTERNAL || or->path_type == OSPF_PATH_TYPE2_EXTERNAL) return ospf->distance_external; if (ospf->distance_all) return ospf->distance_all; return 0; } void ospf_zebra_init () { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_OSPF); zclient->router_id_update = ospf_router_id_update_zebra; zclient->interface_add = ospf_interface_add; zclient->interface_delete = ospf_interface_delete; zclient->interface_up = ospf_interface_state_up; zclient->interface_down = ospf_interface_state_down; zclient->interface_address_add = ospf_interface_address_add; zclient->interface_address_delete = ospf_interface_address_delete; zclient->ipv4_route_add = ospf_zebra_read_ipv4; zclient->ipv4_route_delete = ospf_zebra_read_ipv4; access_list_add_hook (ospf_filter_update); access_list_delete_hook (ospf_filter_update); prefix_list_add_hook (ospf_prefix_list_update); prefix_list_delete_hook (ospf_prefix_list_update); } quagga-0.99.24.1/ospfd/ospfd.c0000644000175000017500000012034212476520570012630 00000000000000/* OSPF version 2 daemon program. Copyright (C) 1999, 2000 Toshiaki Takada This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "vty.h" #include "command.h" #include "linklist.h" #include "prefix.h" #include "table.h" #include "if.h" #include "memory.h" #include "stream.h" #include "log.h" #include "sockunion.h" /* for inet_aton () */ #include "zclient.h" #include "plist.h" #include "sockopt.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_network.h" #include "ospfd/ospf_interface.h" #include "ospfd/ospf_ism.h" #include "ospfd/ospf_asbr.h" #include "ospfd/ospf_lsa.h" #include "ospfd/ospf_lsdb.h" #include "ospfd/ospf_neighbor.h" #include "ospfd/ospf_nsm.h" #include "ospfd/ospf_spf.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_dump.h" #include "ospfd/ospf_zebra.h" #include "ospfd/ospf_abr.h" #include "ospfd/ospf_flood.h" #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" /* OSPF process wide configuration. */ static struct ospf_master ospf_master; /* OSPF process wide configuration pointer to export. */ struct ospf_master *om; extern struct zclient *zclient; extern struct in_addr router_id_zebra; static void ospf_remove_vls_through_area (struct ospf *, struct ospf_area *); static void ospf_network_free (struct ospf *, struct ospf_network *); static void ospf_area_free (struct ospf_area *); static void ospf_network_run (struct prefix *, struct ospf_area *); static void ospf_network_run_interface (struct prefix *, struct ospf_area *, struct interface *); static int ospf_network_match_iface (const struct connected *, const struct prefix *); static void ospf_finish_final (struct ospf *); #define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 void ospf_router_id_update (struct ospf *ospf) { struct in_addr router_id, router_id_old; struct ospf_interface *oi; struct interface *ifp; struct listnode *node; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Router-ID[OLD:%s]: Update", inet_ntoa (ospf->router_id)); router_id_old = ospf->router_id; /* Select the router ID based on these priorities: 1. Statically assigned router ID is always the first choice. 2. If there is no statically assigned router ID, then try to stick with the most recent value, since changing router ID's is very disruptive. 3. Last choice: just go with whatever the zebra daemon recommends. */ if (ospf->router_id_static.s_addr != 0) router_id = ospf->router_id_static; else if (ospf->router_id.s_addr != 0) router_id = ospf->router_id; else router_id = router_id_zebra; ospf->router_id = router_id; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Router-ID[NEW:%s]: Update", inet_ntoa (ospf->router_id)); if (!IPV4_ADDR_SAME (&router_id_old, &router_id)) { for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) /* Update self-neighbor's router_id. */ oi->nbr_self->router_id = router_id; /* If AS-external-LSA is queued, then flush those LSAs. */ if (router_id_old.s_addr == 0 && ospf->external_origin) { int type; /* Originate each redistributed external route. */ for (type = 0; type < ZEBRA_ROUTE_MAX; type++) if (ospf->external_origin & (1 << type)) thread_add_event (master, ospf_external_lsa_originate_timer, ospf, type); /* Originate Deafult. */ if (ospf->external_origin & (1 << ZEBRA_ROUTE_MAX)) thread_add_event (master, ospf_default_originate_timer, ospf, 0); ospf->external_origin = 0; } /* update router-lsa's for each area */ ospf_router_lsa_update (ospf); /* update ospf_interface's */ for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_if_update (ospf, ifp); } } /* For OSPF area sort by area id. */ static int ospf_area_id_cmp (struct ospf_area *a1, struct ospf_area *a2) { if (ntohl (a1->area_id.s_addr) > ntohl (a2->area_id.s_addr)) return 1; if (ntohl (a1->area_id.s_addr) < ntohl (a2->area_id.s_addr)) return -1; return 0; } /* Allocate new ospf structure. */ static struct ospf * ospf_new (void) { int i; struct ospf *new = XCALLOC (MTYPE_OSPF_TOP, sizeof (struct ospf)); new->router_id.s_addr = htonl (0); new->router_id_static.s_addr = htonl (0); new->abr_type = OSPF_ABR_DEFAULT; new->oiflist = list_new (); new->vlinks = list_new (); new->areas = list_new (); new->areas->cmp = (int (*)(void *, void *)) ospf_area_id_cmp; new->networks = route_table_init (); new->nbr_nbma = route_table_init (); new->lsdb = ospf_lsdb_new (); new->default_originate = DEFAULT_ORIGINATE_NONE; new->passive_interface_default = OSPF_IF_ACTIVE; new->new_external_route = route_table_init (); new->old_external_route = route_table_init (); new->external_lsas = route_table_init (); new->stub_router_startup_time = OSPF_STUB_ROUTER_UNCONFIGURED; new->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; new->stub_router_admin_set = OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET; /* Distribute parameter init. */ for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { new->dmetric[i].type = -1; new->dmetric[i].value = -1; } new->default_metric = -1; new->ref_bandwidth = OSPF_DEFAULT_REF_BANDWIDTH; /* SPF timer value init. */ new->spf_delay = OSPF_SPF_DELAY_DEFAULT; new->spf_holdtime = OSPF_SPF_HOLDTIME_DEFAULT; new->spf_max_holdtime = OSPF_SPF_MAX_HOLDTIME_DEFAULT; new->spf_hold_multiplier = 1; /* MaxAge init. */ new->maxage_delay = OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT; new->maxage_lsa = route_table_init(); new->t_maxage_walker = thread_add_timer (master, ospf_lsa_maxage_walker, new, OSPF_LSA_MAXAGE_CHECK_INTERVAL); /* Distance table init. */ new->distance_table = route_table_init (); new->lsa_refresh_queue.index = 0; new->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; new->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, new, new->lsa_refresh_interval); new->lsa_refresher_started = quagga_time (NULL); if ((new->fd = ospf_sock_init()) < 0) { zlog_err("ospf_new: fatal error: ospf_sock_init was unable to open " "a socket"); exit(1); } new->maxsndbuflen = getsockopt_so_sendbuf (new->fd); if (IS_DEBUG_OSPF (zebra, ZEBRA_INTERFACE)) zlog_debug ("%s: starting with OSPF send buffer size %u", __func__, new->maxsndbuflen); if ((new->ibuf = stream_new(OSPF_MAX_PACKET_SIZE+1)) == NULL) { zlog_err("ospf_new: fatal error: stream_new(%u) failed allocating ibuf", OSPF_MAX_PACKET_SIZE+1); exit(1); } new->t_read = thread_add_read (master, ospf_read, new, new->fd); new->oi_write_q = list_new (); return new; } struct ospf * ospf_lookup () { if (listcount (om->ospf) == 0) return NULL; return listgetdata (listhead (om->ospf)); } static void ospf_add (struct ospf *ospf) { listnode_add (om->ospf, ospf); } static void ospf_delete (struct ospf *ospf) { listnode_delete (om->ospf, ospf); } struct ospf * ospf_get () { struct ospf *ospf; ospf = ospf_lookup (); if (ospf == NULL) { ospf = ospf_new (); ospf_add (ospf); if (ospf->router_id_static.s_addr == 0) ospf_router_id_update (ospf); #ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_init (ospf); #endif /* HAVE_OPAQUE_LSA */ } return ospf; } /* Handle the second half of deferred shutdown. This is called either * from the deferred-shutdown timer thread, or directly through * ospf_deferred_shutdown_check. * * Function is to cleanup G-R state, if required then call ospf_finish_final * to complete shutdown of this ospf instance. Possibly exit if the * whole process is being shutdown and this was the last OSPF instance. */ static void ospf_deferred_shutdown_finish (struct ospf *ospf) { ospf->stub_router_shutdown_time = OSPF_STUB_ROUTER_UNCONFIGURED; OSPF_TIMER_OFF (ospf->t_deferred_shutdown); ospf_finish_final (ospf); /* *ospf is now invalid */ /* ospfd being shut-down? If so, was this the last ospf instance? */ if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN) && (listcount (om->ospf) == 0)) exit (0); return; } /* Timer thread for G-R */ static int ospf_deferred_shutdown_timer (struct thread *t) { struct ospf *ospf = THREAD_ARG(t); ospf_deferred_shutdown_finish (ospf); return 0; } /* Check whether deferred-shutdown must be scheduled, otherwise call * down directly into second-half of instance shutdown. */ static void ospf_deferred_shutdown_check (struct ospf *ospf) { unsigned long timeout; struct listnode *ln; struct ospf_area *area; /* deferred shutdown already running? */ if (ospf->t_deferred_shutdown) return; /* Should we try push out max-metric LSAs? */ if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED) { for (ALL_LIST_ELEMENTS_RO (ospf->areas, ln, area)) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED)) ospf_router_lsa_update_area (area); } timeout = ospf->stub_router_shutdown_time; } else { /* No timer needed */ ospf_deferred_shutdown_finish (ospf); return; } OSPF_TIMER_ON (ospf->t_deferred_shutdown, ospf_deferred_shutdown_timer, timeout); return; } /* Shut down the entire process */ void ospf_terminate (void) { struct ospf *ospf; struct listnode *node, *nnode; /* shutdown already in progress */ if (CHECK_FLAG (om->options, OSPF_MASTER_SHUTDOWN)) return; SET_FLAG (om->options, OSPF_MASTER_SHUTDOWN); /* exit immediately if OSPF not actually running */ if (listcount(om->ospf) == 0) exit(0); for (ALL_LIST_ELEMENTS (om->ospf, node, nnode, ospf)) ospf_finish (ospf); /* Deliberately go back up, hopefully to thread scheduler, as * One or more ospf_finish()'s may have deferred shutdown to a timer * thread */ } void ospf_finish (struct ospf *ospf) { /* let deferred shutdown decide */ ospf_deferred_shutdown_check (ospf); /* if ospf_deferred_shutdown returns, then ospf_finish_final is * deferred to expiry of G-S timer thread. Return back up, hopefully * to thread scheduler. */ return; } /* Final cleanup of ospf instance */ static void ospf_finish_final (struct ospf *ospf) { struct route_node *rn; struct ospf_nbr_nbma *nbr_nbma; struct ospf_lsa *lsa; struct ospf_interface *oi; struct ospf_area *area; struct ospf_vl_data *vl_data; struct listnode *node, *nnode; int i; #ifdef HAVE_OPAQUE_LSA ospf_opaque_type11_lsa_term (ospf); #endif /* HAVE_OPAQUE_LSA */ /* be nice if this worked, but it doesn't */ /*ospf_flush_self_originated_lsas_now (ospf);*/ /* Unregister redistribution */ for (i = 0; i < ZEBRA_ROUTE_MAX; i++) ospf_redistribute_unset (ospf, i); ospf_redistribute_default_unset (ospf); for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) ospf_remove_vls_through_area (ospf, area); for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) ospf_vl_delete (ospf, vl_data); list_delete (ospf->vlinks); /* Reset interface. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) ospf_if_free (oi); /* Clear static neighbors */ for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) if ((nbr_nbma = rn->info)) { OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll); if (nbr_nbma->nbr) { nbr_nbma->nbr->nbr_nbma = NULL; nbr_nbma->nbr = NULL; } if (nbr_nbma->oi) { listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); nbr_nbma->oi = NULL; } XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); } route_table_finish (ospf->nbr_nbma); /* Clear networks and Areas. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) { struct ospf_network *network; if ((network = rn->info) != NULL) { ospf_network_free (ospf, network); rn->info = NULL; route_unlock_node (rn); } } for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area)) { listnode_delete (ospf->areas, area); ospf_area_free (area); } /* Cancel all timers. */ OSPF_TIMER_OFF (ospf->t_external_lsa); OSPF_TIMER_OFF (ospf->t_spf_calc); OSPF_TIMER_OFF (ospf->t_ase_calc); OSPF_TIMER_OFF (ospf->t_maxage); OSPF_TIMER_OFF (ospf->t_maxage_walker); OSPF_TIMER_OFF (ospf->t_abr_task); OSPF_TIMER_OFF (ospf->t_asbr_check); OSPF_TIMER_OFF (ospf->t_distribute_update); OSPF_TIMER_OFF (ospf->t_lsa_refresher); OSPF_TIMER_OFF (ospf->t_read); OSPF_TIMER_OFF (ospf->t_write); #ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (ospf->t_opaque_lsa_self); #endif close (ospf->fd); stream_free(ospf->ibuf); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AS_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); #endif /* HAVE_OPAQUE_LSA */ LSDB_LOOP (EXTERNAL_LSDB (ospf), rn, lsa) ospf_discard_from_db (ospf, ospf->lsdb, lsa); ospf_lsdb_delete_all (ospf->lsdb); ospf_lsdb_free (ospf->lsdb); for (rn = route_top (ospf->maxage_lsa); rn; rn = route_next (rn)) { struct ospf_lsa *lsa; if ((lsa = rn->info) != NULL) { ospf_lsa_unlock (&lsa); rn->info = NULL; } route_unlock_node (rn); } route_table_finish (ospf->maxage_lsa); if (ospf->old_table) ospf_route_table_free (ospf->old_table); if (ospf->new_table) { ospf_route_delete (ospf->new_table); ospf_route_table_free (ospf->new_table); } if (ospf->old_rtrs) ospf_rtrs_free (ospf->old_rtrs); if (ospf->new_rtrs) ospf_rtrs_free (ospf->new_rtrs); if (ospf->new_external_route) { ospf_route_delete (ospf->new_external_route); ospf_route_table_free (ospf->new_external_route); } if (ospf->old_external_route) { ospf_route_delete (ospf->old_external_route); ospf_route_table_free (ospf->old_external_route); } if (ospf->external_lsas) { ospf_ase_external_lsas_finish (ospf->external_lsas); } list_delete (ospf->areas); for (i = ZEBRA_ROUTE_SYSTEM; i <= ZEBRA_ROUTE_MAX; i++) if (EXTERNAL_INFO (i) != NULL) for (rn = route_top (EXTERNAL_INFO (i)); rn; rn = route_next (rn)) { if (rn->info == NULL) continue; XFREE (MTYPE_OSPF_EXTERNAL_INFO, rn->info); rn->info = NULL; route_unlock_node (rn); } ospf_distance_reset (ospf); route_table_finish (ospf->distance_table); ospf_delete (ospf); XFREE (MTYPE_OSPF_TOP, ospf); } /* allocate new OSPF Area object */ static struct ospf_area * ospf_area_new (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *new; /* Allocate new config_network. */ new = XCALLOC (MTYPE_OSPF_AREA, sizeof (struct ospf_area)); new->ospf = ospf; new->area_id = area_id; new->external_routing = OSPF_AREA_DEFAULT; new->default_cost = 1; new->auth_type = OSPF_AUTH_NULL; /* New LSDB init. */ new->lsdb = ospf_lsdb_new (); /* Self-originated LSAs initialize. */ new->router_lsa_self = NULL; #ifdef HAVE_OPAQUE_LSA ospf_opaque_type10_lsa_init (new); #endif /* HAVE_OPAQUE_LSA */ new->oiflist = list_new (); new->ranges = route_table_init (); if (area_id.s_addr == OSPF_AREA_BACKBONE) ospf->backbone = new; return new; } static void ospf_area_free (struct ospf_area *area) { struct route_node *rn; struct ospf_lsa *lsa; /* Free LSDBs. */ LSDB_LOOP (ROUTER_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (NETWORK_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (NSSA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); #ifdef HAVE_OPAQUE_LSA LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa) ospf_discard_from_db (area->ospf, area->lsdb, lsa); #endif /* HAVE_OPAQUE_LSA */ ospf_lsdb_delete_all (area->lsdb); ospf_lsdb_free (area->lsdb); ospf_lsa_unlock (&area->router_lsa_self); route_table_finish (area->ranges); list_delete (area->oiflist); if (EXPORT_NAME (area)) free (EXPORT_NAME (area)); if (IMPORT_NAME (area)) free (IMPORT_NAME (area)); /* Cancel timer. */ OSPF_TIMER_OFF (area->t_stub_router); #ifdef HAVE_OPAQUE_LSA OSPF_TIMER_OFF (area->t_opaque_lsa_self); #endif /* HAVE_OPAQUE_LSA */ if (OSPF_IS_AREA_BACKBONE (area)) area->ospf->backbone = NULL; XFREE (MTYPE_OSPF_AREA, area); } void ospf_area_check_free (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area && listcount (area->oiflist) == 0 && area->ranges->top == NULL && area->shortcut_configured == OSPF_SHORTCUT_DEFAULT && area->external_routing == OSPF_AREA_DEFAULT && area->no_summary == 0 && area->default_cost == 1 && EXPORT_NAME (area) == NULL && IMPORT_NAME (area) == NULL && area->auth_type == OSPF_AUTH_NULL) { listnode_delete (ospf->areas, area); ospf_area_free (area); } } struct ospf_area * ospf_area_get (struct ospf *ospf, struct in_addr area_id, int format) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (!area) { area = ospf_area_new (ospf, area_id); area->format = format; listnode_add_sort (ospf->areas, area); ospf_check_abr_status (ospf); if (ospf->stub_router_admin_set == OSPF_STUB_ROUTER_ADMINISTRATIVE_SET) { SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED); } } return area; } struct ospf_area * ospf_area_lookup_by_area_id (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (ospf->areas, node, area)) if (IPV4_ADDR_SAME (&area->area_id, &area_id)) return area; return NULL; } void ospf_area_add_if (struct ospf_area *area, struct ospf_interface *oi) { listnode_add (area->oiflist, oi); } void ospf_area_del_if (struct ospf_area *area, struct ospf_interface *oi) { listnode_delete (area->oiflist, oi); } /* Config network statement related functions. */ static struct ospf_network * ospf_network_new (struct in_addr area_id, int format) { struct ospf_network *new; new = XCALLOC (MTYPE_OSPF_NETWORK, sizeof (struct ospf_network)); new->area_id = area_id; new->format = format; return new; } static void ospf_network_free (struct ospf *ospf, struct ospf_network *network) { ospf_area_check_free (ospf, network->area_id); ospf_schedule_abr_task (ospf); XFREE (MTYPE_OSPF_NETWORK, network); } int ospf_network_set (struct ospf *ospf, struct prefix_ipv4 *p, struct in_addr area_id) { struct ospf_network *network; struct ospf_area *area; struct route_node *rn; struct external_info *ei; int ret = OSPF_AREA_ID_FORMAT_ADDRESS; rn = route_node_get (ospf->networks, (struct prefix *)p); if (rn->info) { /* There is already same network statement. */ route_unlock_node (rn); return 0; } rn->info = network = ospf_network_new (area_id, ret); area = ospf_area_get (ospf, area_id, ret); /* Run network config now. */ ospf_network_run ((struct prefix *)p, area); /* Update connected redistribute. */ if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) if (ospf_external_info_find_lsa (ospf, &ei->p)) if (!ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_flush (ospf, ei->type, &ei->p, ei->ifindex /*, ei->nexthop */); ospf_area_check_free (ospf, area_id); return 1; } int ospf_network_unset (struct ospf *ospf, struct prefix_ipv4 *p, struct in_addr area_id) { struct route_node *rn; struct ospf_network *network; struct external_info *ei; struct listnode *node, *nnode; struct ospf_interface *oi; rn = route_node_lookup (ospf->networks, (struct prefix *)p); if (rn == NULL) return 0; network = rn->info; route_unlock_node (rn); if (!IPV4_ADDR_SAME (&area_id, &network->area_id)) return 0; ospf_network_free (ospf, rn->info); rn->info = NULL; route_unlock_node (rn); /* initial reference */ /* Find interfaces that not configured already. */ for (ALL_LIST_ELEMENTS (ospf->oiflist, node, nnode, oi)) { int found = 0; struct connected *co = oi->connected; if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) { if (rn->info == NULL) continue; if (ospf_network_match_iface(co,&rn->p)) { found = 1; route_unlock_node (rn); break; } } if (found == 0) { ospf_if_free (oi); ospf_area_check_free (ospf, area_id); } } /* Update connected redistribute. */ if (ospf_is_type_redistributed (ZEBRA_ROUTE_CONNECT)) if (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)) for (rn = route_top (EXTERNAL_INFO (ZEBRA_ROUTE_CONNECT)); rn; rn = route_next (rn)) if ((ei = rn->info) != NULL) if (!ospf_external_info_find_lsa (ospf, &ei->p)) if (ospf_distribute_check_connected (ospf, ei)) ospf_external_lsa_originate (ospf, ei); return 1; } /* Check whether interface matches given network * returns: 1, true. 0, false */ static int ospf_network_match_iface(const struct connected *co, const struct prefix *net) { /* new approach: more elegant and conceptually clean */ return prefix_match(net, CONNECTED_PREFIX(co)); } static void ospf_network_run_interface (struct prefix *p, struct ospf_area *area, struct interface *ifp) { struct listnode *cnode; struct connected *co; if (memcmp (ifp->name, "VLINK", 5) == 0) return; /* if interface prefix is match specified prefix, then create socket and join multicast group. */ for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, co)) { if (CHECK_FLAG(co->flags,ZEBRA_IFA_SECONDARY)) continue; if (p->family == co->address->family && ! ospf_if_table_lookup(ifp, co->address) && ospf_network_match_iface(co,p)) { struct ospf_interface *oi; oi = ospf_if_new (area->ospf, ifp, co->address); oi->connected = co; oi->area = area; oi->params = ospf_lookup_if_params (ifp, oi->address->u.prefix4); oi->output_cost = ospf_if_get_output_cost (oi); /* Add pseudo neighbor. */ ospf_nbr_add_self (oi); /* Relate ospf interface to ospf instance. */ oi->ospf = area->ospf; /* update network type as interface flag */ /* If network type is specified previously, skip network type setting. */ oi->type = IF_DEF_PARAMS (ifp)->type; ospf_area_add_if (oi->area, oi); /* if router_id is not configured, dont bring up * interfaces. * ospf_router_id_update() will call ospf_if_update * whenever r-id is configured instead. */ if ((area->ospf->router_id.s_addr != 0) && if_is_operative (ifp)) ospf_if_up (oi); } } } static void ospf_network_run (struct prefix *p, struct ospf_area *area) { struct interface *ifp; struct listnode *node; /* Schedule Router ID Update. */ if (area->ospf->router_id.s_addr == 0) ospf_router_id_update (area->ospf); /* Get target interface. */ for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp)) ospf_network_run_interface (p, area, ifp); } void ospf_ls_upd_queue_empty (struct ospf_interface *oi) { struct route_node *rn; struct listnode *node, *nnode; struct list *lst; struct ospf_lsa *lsa; /* empty ls update queue */ for (rn = route_top (oi->ls_upd_queue); rn; rn = route_next (rn)) if ((lst = (struct list *) rn->info)) { for (ALL_LIST_ELEMENTS (lst, node, nnode, lsa)) ospf_lsa_unlock (&lsa); /* oi->ls_upd_queue */ list_free (lst); rn->info = NULL; } /* remove update event */ if (oi->t_ls_upd_event) { thread_cancel (oi->t_ls_upd_event); oi->t_ls_upd_event = NULL; } } void ospf_if_update (struct ospf *ospf, struct interface *ifp) { struct route_node *rn; struct ospf_network *network; struct ospf_area *area; if (!ospf) ospf = ospf_lookup (); /* OSPF must be on and Router-ID must be configured. */ if (!ospf || ospf->router_id.s_addr == 0) return; /* Run each netowrk for this interface. */ for (rn = route_top (ospf->networks); rn; rn = route_next (rn)) if (rn->info != NULL) { network = (struct ospf_network *) rn->info; area = ospf_area_get (ospf, network->area_id, network->format); ospf_network_run_interface (&rn->p, area, ifp); } } void ospf_remove_vls_through_area (struct ospf *ospf, struct ospf_area *area) { struct listnode *node, *nnode; struct ospf_vl_data *vl_data; for (ALL_LIST_ELEMENTS (ospf->vlinks, node, nnode, vl_data)) if (IPV4_ADDR_SAME (&vl_data->vl_area_id, &area->area_id)) ospf_vl_delete (ospf, vl_data); } static const struct message ospf_area_type_msg[] = { { OSPF_AREA_DEFAULT, "Default" }, { OSPF_AREA_STUB, "Stub" }, { OSPF_AREA_NSSA, "NSSA" }, }; static const int ospf_area_type_msg_max = OSPF_AREA_TYPE_MAX; static void ospf_area_type_set (struct ospf_area *area, int type) { struct listnode *node; struct ospf_interface *oi; if (area->external_routing == type) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Area[%s]: Types are the same, ignored.", inet_ntoa (area->area_id)); return; } area->external_routing = type; if (IS_DEBUG_OSPF_EVENT) zlog_debug ("Area[%s]: Configured as %s", inet_ntoa (area->area_id), LOOKUP (ospf_area_type_msg, type)); switch (area->external_routing) { case OSPF_AREA_DEFAULT: for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); SET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); } break; case OSPF_AREA_STUB: for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { if (IS_DEBUG_OSPF_EVENT) zlog_debug ("setting options on %s accordingly", IF_NAME (oi)); UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); if (IS_DEBUG_OSPF_EVENT) zlog_debug ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); } break; case OSPF_AREA_NSSA: for (ALL_LIST_ELEMENTS_RO (area->oiflist, node, oi)) if (oi->nbr_self != NULL) { zlog_debug ("setting nssa options on %s accordingly", IF_NAME (oi)); UNSET_FLAG (oi->nbr_self->options, OSPF_OPTION_E); SET_FLAG (oi->nbr_self->options, OSPF_OPTION_NP); zlog_debug ("options set on %s: %x", IF_NAME (oi), OPTIONS (oi)); } break; default: break; } ospf_router_lsa_update_area (area); ospf_schedule_abr_task (area->ospf); } int ospf_area_shortcut_set (struct ospf *ospf, struct ospf_area *area, int mode) { if (area->shortcut_configured == mode) return 0; area->shortcut_configured = mode; ospf_router_lsa_update_area (area); ospf_schedule_abr_task (ospf); ospf_area_check_free (ospf, area->area_id); return 1; } int ospf_area_shortcut_unset (struct ospf *ospf, struct ospf_area *area) { area->shortcut_configured = OSPF_SHORTCUT_DEFAULT; ospf_router_lsa_update_area (area); ospf_area_check_free (ospf, area->area_id); ospf_schedule_abr_task (ospf); return 1; } static int ospf_area_vlink_count (struct ospf *ospf, struct ospf_area *area) { struct ospf_vl_data *vl; struct listnode *node; int count = 0; for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl)) if (IPV4_ADDR_SAME (&vl->vl_area_id, &area->area_id)) count++; return count; } int ospf_area_stub_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); if (ospf_area_vlink_count (ospf, area)) return 0; if (area->external_routing != OSPF_AREA_STUB) ospf_area_type_set (area, OSPF_AREA_STUB); return 1; } int ospf_area_stub_unset (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 1; if (area->external_routing == OSPF_AREA_STUB) ospf_area_type_set (area, OSPF_AREA_DEFAULT); ospf_area_check_free (ospf, area_id); return 1; } int ospf_area_no_summary_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); area->no_summary = 1; return 1; } int ospf_area_no_summary_unset (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; area->no_summary = 0; ospf_area_check_free (ospf, area_id); return 1; } int ospf_area_nssa_set (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; int format = OSPF_AREA_ID_FORMAT_ADDRESS; area = ospf_area_get (ospf, area_id, format); if (ospf_area_vlink_count (ospf, area)) return 0; if (area->external_routing != OSPF_AREA_NSSA) { ospf_area_type_set (area, OSPF_AREA_NSSA); ospf->anyNSSA++; } /* set NSSA area defaults */ area->no_summary = 0; area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; area->NSSATranslatorState = OSPF_NSSA_TRANSLATE_DISABLED; area->NSSATranslatorStabilityInterval = OSPF_NSSA_TRANS_STABLE_DEFAULT; return 1; } int ospf_area_nssa_unset (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; if (area->external_routing == OSPF_AREA_NSSA) { ospf->anyNSSA--; ospf_area_type_set (area, OSPF_AREA_DEFAULT); } ospf_area_check_free (ospf, area_id); return 1; } int ospf_area_nssa_translator_role_set (struct ospf *ospf, struct in_addr area_id, int role) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; area->NSSATranslatorRole = role; return 1; } #if 0 /* XXX: unused? Leave for symmetry? */ static int ospf_area_nssa_translator_role_unset (struct ospf *ospf, struct in_addr area_id) { struct ospf_area *area; area = ospf_area_lookup_by_area_id (ospf, area_id); if (area == NULL) return 0; area->NSSATranslatorRole = OSPF_NSSA_ROLE_CANDIDATE; ospf_area_check_free (ospf, area_id); return 1; } #endif int ospf_area_export_list_set (struct ospf *ospf, struct ospf_area *area, const char *list_name) { struct access_list *list; list = access_list_lookup (AFI_IP, list_name); EXPORT_LIST (area) = list; if (EXPORT_NAME (area)) free (EXPORT_NAME (area)); EXPORT_NAME (area) = strdup (list_name); ospf_schedule_abr_task (ospf); return 1; } int ospf_area_export_list_unset (struct ospf *ospf, struct ospf_area * area) { EXPORT_LIST (area) = 0; if (EXPORT_NAME (area)) free (EXPORT_NAME (area)); EXPORT_NAME (area) = NULL; ospf_area_check_free (ospf, area->area_id); ospf_schedule_abr_task (ospf); return 1; } int ospf_area_import_list_set (struct ospf *ospf, struct ospf_area *area, const char *name) { struct access_list *list; list = access_list_lookup (AFI_IP, name); IMPORT_LIST (area) = list; if (IMPORT_NAME (area)) free (IMPORT_NAME (area)); IMPORT_NAME (area) = strdup (name); ospf_schedule_abr_task (ospf); return 1; } int ospf_area_import_list_unset (struct ospf *ospf, struct ospf_area * area) { IMPORT_LIST (area) = 0; if (IMPORT_NAME (area)) free (IMPORT_NAME (area)); IMPORT_NAME (area) = NULL; ospf_area_check_free (ospf, area->area_id); ospf_schedule_abr_task (ospf); return 1; } int ospf_timers_refresh_set (struct ospf *ospf, int interval) { int time_left; if (ospf->lsa_refresh_interval == interval) return 1; time_left = ospf->lsa_refresh_interval - (quagga_time (NULL) - ospf->lsa_refresher_started); if (time_left > interval) { OSPF_TIMER_OFF (ospf->t_lsa_refresher); ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, interval); } ospf->lsa_refresh_interval = interval; return 1; } int ospf_timers_refresh_unset (struct ospf *ospf) { int time_left; time_left = ospf->lsa_refresh_interval - (quagga_time (NULL) - ospf->lsa_refresher_started); if (time_left > OSPF_LSA_REFRESH_INTERVAL_DEFAULT) { OSPF_TIMER_OFF (ospf->t_lsa_refresher); ospf->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker, ospf, OSPF_LSA_REFRESH_INTERVAL_DEFAULT); } ospf->lsa_refresh_interval = OSPF_LSA_REFRESH_INTERVAL_DEFAULT; return 1; } static struct ospf_nbr_nbma * ospf_nbr_nbma_new (void) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = XCALLOC (MTYPE_OSPF_NEIGHBOR_STATIC, sizeof (struct ospf_nbr_nbma)); nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; return nbr_nbma; } static void ospf_nbr_nbma_free (struct ospf_nbr_nbma *nbr_nbma) { XFREE (MTYPE_OSPF_NEIGHBOR_STATIC, nbr_nbma); } static void ospf_nbr_nbma_delete (struct ospf *ospf, struct ospf_nbr_nbma *nbr_nbma) { struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefix = nbr_nbma->addr; p.prefixlen = IPV4_MAX_BITLEN; rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); if (rn) { ospf_nbr_nbma_free (rn->info); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } static void ospf_nbr_nbma_down (struct ospf_nbr_nbma *nbr_nbma) { OSPF_TIMER_OFF (nbr_nbma->t_poll); if (nbr_nbma->nbr) { nbr_nbma->nbr->nbr_nbma = NULL; OSPF_NSM_EVENT_EXECUTE (nbr_nbma->nbr, NSM_KillNbr); } if (nbr_nbma->oi) listnode_delete (nbr_nbma->oi->nbr_nbma, nbr_nbma); } static void ospf_nbr_nbma_add (struct ospf_nbr_nbma *nbr_nbma, struct ospf_interface *oi) { struct ospf_neighbor *nbr; struct route_node *rn; struct prefix p; if (oi->type != OSPF_IFTYPE_NBMA) return; if (nbr_nbma->nbr != NULL) return; if (IPV4_ADDR_SAME (&oi->nbr_self->address.u.prefix4, &nbr_nbma->addr)) return; nbr_nbma->oi = oi; listnode_add (oi->nbr_nbma, nbr_nbma); /* Get neighbor information from table. */ p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = nbr_nbma->addr; rn = route_node_get (oi->nbrs, (struct prefix *)&p); if (rn->info) { nbr = rn->info; nbr->nbr_nbma = nbr_nbma; nbr_nbma->nbr = nbr; route_unlock_node (rn); } else { nbr = rn->info = ospf_nbr_new (oi); nbr->state = NSM_Down; nbr->src = nbr_nbma->addr; nbr->nbr_nbma = nbr_nbma; nbr->priority = nbr_nbma->priority; nbr->address = p; nbr_nbma->nbr = nbr; OSPF_NSM_EVENT_EXECUTE (nbr, NSM_Start); } } void ospf_nbr_nbma_if_update (struct ospf *ospf, struct ospf_interface *oi) { struct ospf_nbr_nbma *nbr_nbma; struct route_node *rn; struct prefix_ipv4 p; if (oi->type != OSPF_IFTYPE_NBMA) return; for (rn = route_top (ospf->nbr_nbma); rn; rn = route_next (rn)) if ((nbr_nbma = rn->info)) if (nbr_nbma->oi == NULL && nbr_nbma->nbr == NULL) { p.family = AF_INET; p.prefix = nbr_nbma->addr; p.prefixlen = IPV4_MAX_BITLEN; if (prefix_match (oi->address, (struct prefix *)&p)) ospf_nbr_nbma_add (nbr_nbma, oi); } } struct ospf_nbr_nbma * ospf_nbr_nbma_lookup (struct ospf *ospf, struct in_addr nbr_addr) { struct route_node *rn; struct prefix_ipv4 p; p.family = AF_INET; p.prefix = nbr_addr; p.prefixlen = IPV4_MAX_BITLEN; rn = route_node_lookup (ospf->nbr_nbma, (struct prefix *)&p); if (rn) { route_unlock_node (rn); return rn->info; } return NULL; } struct ospf_nbr_nbma * ospf_nbr_nbma_lookup_next (struct ospf *ospf, struct in_addr *addr, int first) { #if 0 struct ospf_nbr_nbma *nbr_nbma; struct listnode *node; #endif if (ospf == NULL) return NULL; #if 0 for (ALL_LIST_ELEMENTS_RO (ospf->nbr_nbma, node, nbr_nbma)) { if (first) { *addr = nbr_nbma->addr; return nbr_nbma; } else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (addr->s_addr)) { *addr = nbr_nbma->addr; return nbr_nbma; } } #endif return NULL; } int ospf_nbr_nbma_set (struct ospf *ospf, struct in_addr nbr_addr) { struct ospf_nbr_nbma *nbr_nbma; struct ospf_interface *oi; struct prefix_ipv4 p; struct route_node *rn; struct listnode *node; nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); if (nbr_nbma) return 0; nbr_nbma = ospf_nbr_nbma_new (); nbr_nbma->addr = nbr_addr; p.family = AF_INET; p.prefix = nbr_addr; p.prefixlen = IPV4_MAX_BITLEN; rn = route_node_get (ospf->nbr_nbma, (struct prefix *)&p); rn->info = nbr_nbma; for (ALL_LIST_ELEMENTS_RO (ospf->oiflist, node, oi)) { if (oi->type == OSPF_IFTYPE_NBMA) if (prefix_match (oi->address, (struct prefix *)&p)) { ospf_nbr_nbma_add (nbr_nbma, oi); break; } } return 1; } int ospf_nbr_nbma_unset (struct ospf *ospf, struct in_addr nbr_addr) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); if (nbr_nbma == NULL) return 0; ospf_nbr_nbma_down (nbr_nbma); ospf_nbr_nbma_delete (ospf, nbr_nbma); return 1; } int ospf_nbr_nbma_priority_set (struct ospf *ospf, struct in_addr nbr_addr, u_char priority) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); if (nbr_nbma == NULL) return 0; if (nbr_nbma->priority != priority) nbr_nbma->priority = priority; return 1; } int ospf_nbr_nbma_priority_unset (struct ospf *ospf, struct in_addr nbr_addr) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); if (nbr_nbma == NULL) return 0; if (nbr_nbma != OSPF_NEIGHBOR_PRIORITY_DEFAULT) nbr_nbma->priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; return 1; } int ospf_nbr_nbma_poll_interval_set (struct ospf *ospf, struct in_addr nbr_addr, unsigned int interval) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = ospf_nbr_nbma_lookup (ospf, nbr_addr); if (nbr_nbma == NULL) return 0; if (nbr_nbma->v_poll != interval) { nbr_nbma->v_poll = interval; if (nbr_nbma->oi && ospf_if_is_up (nbr_nbma->oi)) { OSPF_TIMER_OFF (nbr_nbma->t_poll); OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer, nbr_nbma->v_poll); } } return 1; } int ospf_nbr_nbma_poll_interval_unset (struct ospf *ospf, struct in_addr addr) { struct ospf_nbr_nbma *nbr_nbma; nbr_nbma = ospf_nbr_nbma_lookup (ospf, addr); if (nbr_nbma == NULL) return 0; if (nbr_nbma->v_poll != OSPF_POLL_INTERVAL_DEFAULT) nbr_nbma->v_poll = OSPF_POLL_INTERVAL_DEFAULT; return 1; } void ospf_master_init () { memset (&ospf_master, 0, sizeof (struct ospf_master)); om = &ospf_master; om->ospf = list_new (); om->master = thread_master_create (); om->start_time = quagga_time (NULL); } quagga-0.99.24.1/ospfd/ospfd.h0000644000175000017500000004645612476520570012652 00000000000000/* * OSPFd main header. * Copyright (C) 1998, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPFD_H #define _ZEBRA_OSPFD_H #include #include "libospf.h" #include "filter.h" #include "log.h" #define OSPF_VERSION 2 /* VTY port number. */ #define OSPF_VTY_PORT 2604 /* IP TTL for OSPF protocol. */ #define OSPF_IP_TTL 1 #define OSPF_VL_IP_TTL 100 /* Default configuration file name for ospfd. */ #define OSPF_DEFAULT_CONFIG "ospfd.conf" #define OSPF_NSSA_TRANS_STABLE_DEFAULT 40 #define OSPF_ALLSPFROUTERS 0xe0000005 /* 224.0.0.5 */ #define OSPF_ALLDROUTERS 0xe0000006 /* 224.0.0.6 */ /* OSPF Authentication Type. */ #define OSPF_AUTH_NULL 0 #define OSPF_AUTH_SIMPLE 1 #define OSPF_AUTH_CRYPTOGRAPHIC 2 /* For Interface authentication setting default */ #define OSPF_AUTH_NOTSET -1 /* For the consumption and sanity of the command handler */ /* DO NIOT REMOVE!!! Need to detect whether a value has been given or not in VLink command handlers */ #define OSPF_AUTH_CMD_NOTSEEN -2 /* OSPF options. */ #define OSPF_OPTION_T 0x01 /* TOS. */ #define OSPF_OPTION_E 0x02 #define OSPF_OPTION_MC 0x04 #define OSPF_OPTION_NP 0x08 #define OSPF_OPTION_EA 0x10 #define OSPF_OPTION_DC 0x20 #define OSPF_OPTION_O 0x40 /* OSPF Database Description flags. */ #define OSPF_DD_FLAG_MS 0x01 #define OSPF_DD_FLAG_M 0x02 #define OSPF_DD_FLAG_I 0x04 #define OSPF_DD_FLAG_ALL 0x07 #define OSPF_LS_REFRESH_SHIFT (60 * 15) #define OSPF_LS_REFRESH_JITTER 60 /* OSPF master for system wide configuration and variables. */ struct ospf_master { /* OSPF instance. */ struct list *ospf; /* OSPF thread master. */ struct thread_master *master; /* Zebra interface list. */ struct list *iflist; /* Redistributed external information. */ struct route_table *external_info[ZEBRA_ROUTE_MAX + 1]; #define EXTERNAL_INFO(T) om->external_info[T] /* OSPF start time. */ time_t start_time; /* Various OSPF global configuration. */ u_char options; #define OSPF_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */ }; /* OSPF instance structure. */ struct ospf { /* OSPF Router ID. */ struct in_addr router_id; /* Configured automatically. */ struct in_addr router_id_static; /* Configured manually. */ /* ABR/ASBR internal flags. */ u_char flags; #define OSPF_FLAG_ABR 0x0001 #define OSPF_FLAG_ASBR 0x0002 /* ABR type. */ u_char abr_type; #define OSPF_ABR_UNKNOWN 0 #define OSPF_ABR_STAND 1 #define OSPF_ABR_IBM 2 #define OSPF_ABR_CISCO 3 #define OSPF_ABR_SHORTCUT 4 #define OSPF_ABR_DEFAULT OSPF_ABR_CISCO /* NSSA ABR */ u_char anyNSSA; /* Bump for every NSSA attached. */ /* Configured variables. */ u_char config; #define OSPF_RFC1583_COMPATIBLE (1 << 0) #define OSPF_OPAQUE_CAPABLE (1 << 2) #define OSPF_LOG_ADJACENCY_CHANGES (1 << 3) #define OSPF_LOG_ADJACENCY_DETAIL (1 << 4) #ifdef HAVE_OPAQUE_LSA /* Opaque-LSA administrative flags. */ u_char opaque; #define OPAQUE_OPERATION_READY_BIT (1 << 0) #define OPAQUE_BLOCK_TYPE_09_LSA_BIT (1 << 1) #define OPAQUE_BLOCK_TYPE_10_LSA_BIT (1 << 2) #define OPAQUE_BLOCK_TYPE_11_LSA_BIT (1 << 3) #endif /* HAVE_OPAQUE_LSA */ /* RFC3137 stub router. Configured time to stay stub / max-metric */ unsigned int stub_router_startup_time; /* seconds */ unsigned int stub_router_shutdown_time; /* seconds */ #define OSPF_STUB_ROUTER_UNCONFIGURED 0 u_char stub_router_admin_set; #define OSPF_STUB_ROUTER_ADMINISTRATIVE_SET 1 #define OSPF_STUB_ROUTER_ADMINISTRATIVE_UNSET 0 #define OSPF_STUB_MAX_METRIC_SUMMARY_COST 0x00ff0000 /* SPF parameters */ unsigned int spf_delay; /* SPF delay time. */ unsigned int spf_holdtime; /* SPF hold time. */ unsigned int spf_max_holdtime; /* SPF maximum-holdtime */ unsigned int spf_hold_multiplier; /* Adaptive multiplier for hold time */ int default_originate; /* Default information originate. */ #define DEFAULT_ORIGINATE_NONE 0 #define DEFAULT_ORIGINATE_ZEBRA 1 #define DEFAULT_ORIGINATE_ALWAYS 2 u_int32_t ref_bandwidth; /* Reference Bandwidth (Kbps). */ struct route_table *networks; /* OSPF config networks. */ struct list *vlinks; /* Configured Virtual-Links. */ struct list *areas; /* OSPF areas. */ struct route_table *nbr_nbma; struct ospf_area *backbone; /* Pointer to the Backbone Area. */ struct list *oiflist; /* ospf interfaces */ u_char passive_interface_default; /* passive-interface default */ /* LSDB of AS-external-LSAs. */ struct ospf_lsdb *lsdb; /* Flags. */ int external_origin; /* AS-external-LSA origin flag. */ int ase_calc; /* ASE calculation flag. */ #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-11 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ /* Routing tables. */ struct route_table *old_table; /* Old routing table. */ struct route_table *new_table; /* Current routing table. */ struct route_table *old_rtrs; /* Old ABR/ASBR RT. */ struct route_table *new_rtrs; /* New ABR/ASBR RT. */ struct route_table *new_external_route; /* New External Route. */ struct route_table *old_external_route; /* Old External Route. */ struct route_table *external_lsas; /* Database of external LSAs, prefix is LSA's adv. network*/ /* Time stamps */ struct timeval ts_spf; /* SPF calculation time stamp. */ struct timeval ts_spf_duration; /* Execution time of last SPF */ struct route_table *maxage_lsa; /* List of MaxAge LSA for deletion. */ int redistribute; /* Num of redistributed protocols. */ /* Threads. */ struct thread *t_abr_task; /* ABR task timer. */ struct thread *t_asbr_check; /* ASBR check timer. */ struct thread *t_distribute_update; /* Distirbute list update timer. */ struct thread *t_spf_calc; /* SPF calculation timer. */ struct thread *t_ase_calc; /* ASE calculation timer. */ struct thread *t_external_lsa; /* AS-external-LSA origin timer. */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */ #endif /* HAVE_OPAQUE_LSA */ unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */ struct thread *t_maxage; /* MaxAge LSA remover timer. */ struct thread *t_maxage_walker; /* MaxAge LSA checking timer. */ struct thread *t_deferred_shutdown; /* deferred/stub-router shutdown timer*/ struct thread *t_write; struct thread *t_read; int fd; unsigned int maxsndbuflen; struct stream *ibuf; struct list *oi_write_q; /* Distribute lists out of other route sources. */ struct { char *name; struct access_list *list; } dlist[ZEBRA_ROUTE_MAX]; #define DISTRIBUTE_NAME(O,T) (O)->dlist[T].name #define DISTRIBUTE_LIST(O,T) (O)->dlist[T].list /* Redistribute metric info. */ struct { int type; /* External metric type (E1 or E2). */ int value; /* Value for static metric (24-bit). -1 means metric value is not set. */ } dmetric [ZEBRA_ROUTE_MAX + 1]; /* For redistribute route map. */ struct { char *name; struct route_map *map; } route_map [ZEBRA_ROUTE_MAX + 1]; /* +1 is for default-information */ #define ROUTEMAP_NAME(O,T) (O)->route_map[T].name #define ROUTEMAP(O,T) (O)->route_map[T].map int default_metric; /* Default metric for redistribute. */ #define OSPF_LSA_REFRESHER_GRANULARITY 10 #define OSPF_LSA_REFRESHER_SLOTS ((OSPF_LS_REFRESH_TIME + \ OSPF_LS_REFRESH_SHIFT)/10 + 1) struct { u_int16_t index; struct list *qs[OSPF_LSA_REFRESHER_SLOTS]; } lsa_refresh_queue; struct thread *t_lsa_refresher; time_t lsa_refresher_started; #define OSPF_LSA_REFRESH_INTERVAL_DEFAULT 10 u_int16_t lsa_refresh_interval; /* Distance parameter. */ u_char distance_all; u_char distance_intra; u_char distance_inter; u_char distance_external; /* Statistics for LSA origination. */ u_int32_t lsa_originate_count; /* Statistics for LSA used for new instantiation. */ u_int32_t rx_lsa_count; struct route_table *distance_table; }; /* OSPF area structure. */ struct ospf_area { /* OSPF instance. */ struct ospf *ospf; /* Zebra interface list belonging to the area. */ struct list *oiflist; /* Area ID. */ struct in_addr area_id; /* Area ID format. */ char format; #define OSPF_AREA_ID_FORMAT_ADDRESS 1 #define OSPF_AREA_ID_FORMAT_DECIMAL 2 /* Address range. */ struct list *address_range; /* Configured variables. */ int external_routing; /* ExternalRoutingCapability. */ #define OSPF_AREA_DEFAULT 0 #define OSPF_AREA_STUB 1 #define OSPF_AREA_NSSA 2 #define OSPF_AREA_TYPE_MAX 3 int no_summary; /* Don't inject summaries into stub.*/ int shortcut_configured; /* Area configured as shortcut. */ #define OSPF_SHORTCUT_DEFAULT 0 #define OSPF_SHORTCUT_ENABLE 1 #define OSPF_SHORTCUT_DISABLE 2 int shortcut_capability; /* Other ABRs agree on S-bit */ u_int32_t default_cost; /* StubDefaultCost. */ int auth_type; /* Authentication type. */ u_char NSSATranslatorRole; /* NSSA configured role */ #define OSPF_NSSA_ROLE_NEVER 0 #define OSPF_NSSA_ROLE_CANDIDATE 1 #define OSPF_NSSA_ROLE_ALWAYS 2 u_char NSSATranslatorState; /* NSSA operational role */ #define OSPF_NSSA_TRANSLATE_DISABLED 0 #define OSPF_NSSA_TRANSLATE_ENABLED 1 int NSSATranslatorStabilityInterval; u_char transit; /* TransitCapability. */ #define OSPF_TRANSIT_FALSE 0 #define OSPF_TRANSIT_TRUE 1 struct route_table *ranges; /* Configured Area Ranges. */ /* RFC3137 stub router state flags for area */ u_char stub_router_state; #define OSPF_AREA_ADMIN_STUB_ROUTED (1 << 0) /* admin stub-router set */ #define OSPF_AREA_IS_STUB_ROUTED (1 << 1) /* stub-router active */ #define OSPF_AREA_WAS_START_STUB_ROUTED (1 << 2) /* startup SR was done */ /* Area related LSDBs[Type1-4]. */ struct ospf_lsdb *lsdb; /* Self-originated LSAs. */ struct ospf_lsa *router_lsa_self; #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-10 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ /* Area announce list. */ struct { char *name; struct access_list *list; } _export; #define EXPORT_NAME(A) (A)->_export.name #define EXPORT_LIST(A) (A)->_export.list /* Area acceptance list. */ struct { char *name; struct access_list *list; } import; #define IMPORT_NAME(A) (A)->import.name #define IMPORT_LIST(A) (A)->import.list /* Type 3 LSA Area prefix-list. */ struct { char *name; struct prefix_list *list; } plist_in; #define PREFIX_LIST_IN(A) (A)->plist_in.list #define PREFIX_NAME_IN(A) (A)->plist_in.name struct { char *name; struct prefix_list *list; } plist_out; #define PREFIX_LIST_OUT(A) (A)->plist_out.list #define PREFIX_NAME_OUT(A) (A)->plist_out.name /* Shortest Path Tree. */ struct vertex *spf; /* Threads. */ struct thread *t_stub_router; /* Stub-router timer */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-10 Opaque-LSAs origin. */ #endif /* HAVE_OPAQUE_LSA */ /* Statistics field. */ u_int32_t spf_calculation; /* SPF Calculation Count. */ /* Time stamps. */ struct timeval ts_spf; /* SPF calculation time stamp. */ /* Router count. */ u_int32_t abr_count; /* ABR router in this area. */ u_int32_t asbr_count; /* ASBR router in this area. */ /* Counters. */ u_int32_t act_ints; /* Active interfaces. */ u_int32_t full_nbrs; /* Fully adjacent neighbors. */ u_int32_t full_vls; /* Fully adjacent virtual neighbors. */ }; /* OSPF config network structure. */ struct ospf_network { /* Area ID. */ struct in_addr area_id; int format; }; /* OSPF NBMA neighbor structure. */ struct ospf_nbr_nbma { /* Neighbor IP address. */ struct in_addr addr; /* OSPF interface. */ struct ospf_interface *oi; /* OSPF neighbor structure. */ struct ospf_neighbor *nbr; /* Neighbor priority. */ u_char priority; /* Poll timer value. */ u_int32_t v_poll; /* Poll timer thread. */ struct thread *t_poll; /* State change. */ u_int32_t state_change; }; /* Macro. */ #define OSPF_AREA_SAME(X,Y) \ (memcmp ((X->area_id), (Y->area_id), IPV4_MAX_BYTELEN) == 0) #define IS_OSPF_ABR(O) ((O)->flags & OSPF_FLAG_ABR) #define IS_OSPF_ASBR(O) ((O)->flags & OSPF_FLAG_ASBR) #define OSPF_IS_AREA_ID_BACKBONE(I) ((I).s_addr == OSPF_AREA_BACKBONE) #define OSPF_IS_AREA_BACKBONE(A) OSPF_IS_AREA_ID_BACKBONE ((A)->area_id) #ifdef roundup # define ROUNDUP(val, gran) roundup(val, gran) #else /* roundup */ # define ROUNDUP(val, gran) (((val) - 1 | (gran) - 1) + 1) #endif /* roundup */ #define LSA_OPTIONS_GET(area) \ (((area)->external_routing == OSPF_AREA_DEFAULT) ? OSPF_OPTION_E : 0) #define LSA_OPTIONS_NSSA_GET(area) \ (((area)->external_routing == OSPF_AREA_NSSA) ? OSPF_OPTION_NP : 0) #define OSPF_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), ospf, (V)); \ } while (0) #define OSPF_AREA_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), area, (V)); \ } while (0) #define OSPF_POLL_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), nbr_nbma, (V)); \ } while (0) #define OSPF_POLL_TIMER_OFF(X) OSPF_TIMER_OFF((X)) #define OSPF_TIMER_OFF(X) \ do { \ if (X) \ { \ thread_cancel (X); \ (X) = NULL; \ } \ } while (0) /* Extern variables. */ extern struct ospf_master *om; extern const struct message ospf_ism_state_msg[]; extern const struct message ospf_nsm_state_msg[]; extern const struct message ospf_lsa_type_msg[]; extern const struct message ospf_link_state_id_type_msg[]; extern const struct message ospf_network_type_msg[]; extern const int ospf_ism_state_msg_max; extern const int ospf_nsm_state_msg_max; extern const int ospf_lsa_type_msg_max; extern const int ospf_link_state_id_type_msg_max; extern const int ospf_redistributed_proto_max; extern const int ospf_network_type_msg_max; extern struct zclient *zclient; extern struct thread_master *master; extern int ospf_zlog; /* Prototypes. */ extern const char *ospf_redist_string(u_int route_type); extern struct ospf *ospf_lookup (void); extern struct ospf *ospf_get (void); extern void ospf_finish (struct ospf *); extern void ospf_router_id_update (struct ospf *ospf); extern int ospf_network_set (struct ospf *, struct prefix_ipv4 *, struct in_addr); extern int ospf_network_unset (struct ospf *, struct prefix_ipv4 *, struct in_addr); extern int ospf_area_stub_set (struct ospf *, struct in_addr); extern int ospf_area_stub_unset (struct ospf *, struct in_addr); extern int ospf_area_no_summary_set (struct ospf *, struct in_addr); extern int ospf_area_no_summary_unset (struct ospf *, struct in_addr); extern int ospf_area_nssa_set (struct ospf *, struct in_addr); extern int ospf_area_nssa_unset (struct ospf *, struct in_addr); extern int ospf_area_nssa_translator_role_set (struct ospf *, struct in_addr, int); extern int ospf_area_export_list_set (struct ospf *, struct ospf_area *, const char *); extern int ospf_area_export_list_unset (struct ospf *, struct ospf_area *); extern int ospf_area_import_list_set (struct ospf *, struct ospf_area *, const char *); extern int ospf_area_import_list_unset (struct ospf *, struct ospf_area *); extern int ospf_area_shortcut_set (struct ospf *, struct ospf_area *, int); extern int ospf_area_shortcut_unset (struct ospf *, struct ospf_area *); extern int ospf_timers_refresh_set (struct ospf *, int); extern int ospf_timers_refresh_unset (struct ospf *); extern int ospf_nbr_nbma_set (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_unset (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_priority_set (struct ospf *, struct in_addr, u_char); extern int ospf_nbr_nbma_priority_unset (struct ospf *, struct in_addr); extern int ospf_nbr_nbma_poll_interval_set (struct ospf *, struct in_addr, unsigned int); extern int ospf_nbr_nbma_poll_interval_unset (struct ospf *, struct in_addr); extern void ospf_prefix_list_update (struct prefix_list *); extern void ospf_init (void); extern void ospf_if_update (struct ospf *, struct interface *); extern void ospf_ls_upd_queue_empty (struct ospf_interface *); extern void ospf_terminate (void); extern void ospf_nbr_nbma_if_update (struct ospf *, struct ospf_interface *); extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup (struct ospf *, struct in_addr); extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next (struct ospf *, struct in_addr *, int); extern int ospf_oi_count (struct interface *); extern struct ospf_area *ospf_area_get (struct ospf *, struct in_addr, int); extern void ospf_area_check_free (struct ospf *, struct in_addr); extern struct ospf_area *ospf_area_lookup_by_area_id (struct ospf *, struct in_addr); extern void ospf_area_add_if (struct ospf_area *, struct ospf_interface *); extern void ospf_area_del_if (struct ospf_area *, struct ospf_interface *); extern void ospf_route_map_init (void); extern void ospf_snmp_init (void); extern void ospf_master_init (void); #endif /* _ZEBRA_OSPFD_H */ quagga-0.99.24.1/ospfd/ospf_opaque.h0000644000175000017500000001421312476520570014042 00000000000000/* * This is an implementation of rfc2370. * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_OPAQUE_H #define _ZEBRA_OSPF_OPAQUE_H #include "vty.h" #define IS_OPAQUE_LSA(type) \ ((type) == OSPF_OPAQUE_LINK_LSA || \ (type) == OSPF_OPAQUE_AREA_LSA || \ (type) == OSPF_OPAQUE_AS_LSA) /* * Usage of Opaque-LSA administrative flags in "struct ospf". * * 7 6 5 4 3 2 1 0 * +---+---+---+---+---+---+---+---+ * |///|///|///|///|B11|B10|B09| O | * +---+---+---+---+---+---+---+---+ * |<--------->| A * | +--- Operation status (operational = 1) * +----------- Blocking status for each LSA type */ #define IS_OPAQUE_LSA_ORIGINATION_BLOCKED(V) \ CHECK_FLAG((V), (OPAQUE_BLOCK_TYPE_09_LSA_BIT | \ OPAQUE_BLOCK_TYPE_10_LSA_BIT | \ OPAQUE_BLOCK_TYPE_11_LSA_BIT)) /* * Opaque LSA's link state ID is redefined as follows. * * 24 16 8 0 * +--------+--------+--------+--------+ * |tttttttt|........|........|........| * +--------+--------+--------+--------+ * |<-Type->|<------- Opaque ID ------>| */ #define LSID_OPAQUE_TYPE_MASK 0xff000000 /* 8 bits */ #define LSID_OPAQUE_ID_MASK 0x00ffffff /* 24 bits */ #define GET_OPAQUE_TYPE(lsid) \ (((u_int32_t)(lsid) & LSID_OPAQUE_TYPE_MASK) >> 24) #define GET_OPAQUE_ID(lsid) \ ((u_int32_t)(lsid) & LSID_OPAQUE_ID_MASK) #define SET_OPAQUE_LSID(type, id) \ ((((type) << 24) & LSID_OPAQUE_TYPE_MASK) \ | ((id) & LSID_OPAQUE_ID_MASK)) /* * Opaque LSA types will be assigned by IANA. * */ #define OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA 1 #define OPAQUE_TYPE_SYCAMORE_OPTICAL_TOPOLOGY_DESC 2 #define OPAQUE_TYPE_GRACE_LSA 3 /* Followings types are proposed in internet-draft documents. */ #define OPAQUE_TYPE_8021_QOSPF 129 #define OPAQUE_TYPE_SECONDARY_NEIGHBOR_DISCOVERY 224 #define OPAQUE_TYPE_FLOODGATE 225 /* Ugly hack to make use of an unallocated value for wildcard matching! */ #define OPAQUE_TYPE_WILDCARD 0 #define OPAQUE_TYPE_RANGE_UNASSIGNED(type) \ ( 4 <= (type) && (type) <= 127) #define OPAQUE_TYPE_RANGE_RESERVED(type) \ (127 < (type) && (type) <= 255) #define VALID_OPAQUE_INFO_LEN(lsahdr) \ ((ntohs((lsahdr)->length) >= sizeof (struct lsa_header)) && \ ((ntohs((lsahdr)->length) % sizeof (u_int32_t)) == 0)) /* Prototypes. */ extern void ospf_opaque_init (void); extern void ospf_opaque_term (void); extern int ospf_opaque_type9_lsa_init (struct ospf_interface *oi); extern void ospf_opaque_type9_lsa_term (struct ospf_interface *oi); extern int ospf_opaque_type10_lsa_init (struct ospf_area *area); extern void ospf_opaque_type10_lsa_term (struct ospf_area *area); extern int ospf_opaque_type11_lsa_init (struct ospf *ospf); extern void ospf_opaque_type11_lsa_term (struct ospf *ospf); extern int ospf_register_opaque_functab ( u_char lsa_type, u_char opaque_type, int (* new_if_hook)(struct interface *ifp), int (* del_if_hook)(struct interface *ifp), void (* ism_change_hook)(struct ospf_interface *oi, int old_status), void (* nsm_change_hook)(struct ospf_neighbor *nbr, int old_status), void (* config_write_router)(struct vty *vty), void (* config_write_if )(struct vty *vty, struct interface *ifp), void (* config_write_debug )(struct vty *vty), void (* show_opaque_info )(struct vty *vty, struct ospf_lsa *lsa), int (* lsa_originator)(void *arg), struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa), int (* new_lsa_hook)(struct ospf_lsa *lsa), int (* del_lsa_hook)(struct ospf_lsa *lsa) ); extern void ospf_delete_opaque_functab (u_char lsa_type, u_char opaque_type); extern int ospf_opaque_new_if (struct interface *ifp); extern int ospf_opaque_del_if (struct interface *ifp); extern void ospf_opaque_ism_change (struct ospf_interface *oi, int old_status); extern void ospf_opaque_nsm_change (struct ospf_neighbor *nbr, int old_status); extern void ospf_opaque_config_write_router (struct vty *vty, struct ospf *); extern void ospf_opaque_config_write_if (struct vty *vty, struct interface *ifp); extern void ospf_opaque_config_write_debug (struct vty *vty); extern void show_opaque_info_detail (struct vty *vty, struct ospf_lsa *lsa); extern void ospf_opaque_lsa_dump (struct stream *s, u_int16_t length); extern void ospf_opaque_lsa_originate_schedule (struct ospf_interface *oi, int *init_delay); extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *, int rt_recalc); extern struct ospf_lsa *ospf_opaque_lsa_refresh (struct ospf_lsa *lsa); extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent, u_char lsa_type, u_char opaque_type); extern void ospf_opaque_lsa_refresh_schedule (struct ospf_lsa *lsa); extern void ospf_opaque_lsa_flush_schedule (struct ospf_lsa *lsa); extern void ospf_opaque_adjust_lsreq (struct ospf_neighbor *nbr, struct list *lsas); extern void ospf_opaque_self_originated_lsa_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); extern void ospf_opaque_ls_ack_received (struct ospf_neighbor *nbr, struct ospf_lsa *lsa); extern void htonf (float *src, float *dst); extern void ntohf (float *src, float *dst); extern struct ospf *oi_to_top (struct ospf_interface *oi); #endif /* _ZEBRA_OSPF_OPAQUE_H */ quagga-0.99.24.1/ospfd/ospf_ism.h0000644000175000017500000001026512476520570013343 00000000000000/* * OSPF version 2 Interface State Machine. * From RFC2328 [OSPF Version 2] * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ISM_H #define _ZEBRA_OSPF_ISM_H /* OSPF Interface State Machine Status. */ #define ISM_DependUpon 0 #define ISM_Down 1 #define ISM_Loopback 2 #define ISM_Waiting 3 #define ISM_PointToPoint 4 #define ISM_DROther 5 #define ISM_Backup 6 #define ISM_DR 7 #define OSPF_ISM_STATE_MAX 8 /* Because DR/DROther values are exhanged wrt RFC */ #define ISM_SNMP(x) (((x) == ISM_DROther) ? ISM_DR : \ ((x) == ISM_DR) ? ISM_DROther : (x)) /* OSPF Interface State Machine Event. */ #define ISM_NoEvent 0 #define ISM_InterfaceUp 1 #define ISM_WaitTimer 2 #define ISM_BackupSeen 3 #define ISM_NeighborChange 4 #define ISM_LoopInd 5 #define ISM_UnloopInd 6 #define ISM_InterfaceDown 7 #define OSPF_ISM_EVENT_MAX 8 #define OSPF_ISM_WRITE_ON(O) \ do \ { \ if (oi->on_write_q == 0) \ { \ listnode_add ((O)->oi_write_q, oi); \ oi->on_write_q = 1; \ } \ if ((O)->t_write == NULL) \ (O)->t_write = \ thread_add_write (master, ospf_write, (O), (O)->fd); \ } while (0) /* Macro for OSPF ISM timer turn on. */ #define OSPF_ISM_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), oi, (V)); \ } while (0) #define OSPF_ISM_TIMER_MSEC_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer_msec (master, (F), oi, (V)); \ } while (0) /* convenience macro to set hello timer correctly, according to * whether fast-hello is set or not */ #define OSPF_HELLO_TIMER_ON(O) \ do { \ if (OSPF_IF_PARAM ((O), fast_hello)) \ OSPF_ISM_TIMER_MSEC_ON ((O)->t_hello, ospf_hello_timer, \ 1000 / OSPF_IF_PARAM ((O), fast_hello)); \ else \ OSPF_ISM_TIMER_ON ((O)->t_hello, ospf_hello_timer, \ OSPF_IF_PARAM ((O), v_hello)); \ } while (0) /* Macro for OSPF ISM timer turn off. */ #define OSPF_ISM_TIMER_OFF(X) \ do { \ if (X) \ { \ thread_cancel (X); \ (X) = NULL; \ } \ } while (0) /* Macro for OSPF schedule event. */ #define OSPF_ISM_EVENT_SCHEDULE(I,E) \ thread_add_event (master, ospf_ism_event, (I), (E)) /* Macro for OSPF execute event. */ #define OSPF_ISM_EVENT_EXECUTE(I,E) \ thread_execute (master, ospf_ism_event, (I), (E)) /* Prototypes. */ extern int ospf_ism_event (struct thread *); extern void ism_change_status (struct ospf_interface *, int); extern int ospf_hello_timer (struct thread *thread); #endif /* _ZEBRA_OSPF_ISM_H */ quagga-0.99.24.1/ospfd/ospf_nsm.h0000644000175000017500000000656512476520570013360 00000000000000/* * OSPF version 2 Neighbor State Machine * From RFC2328 [OSPF Version 2] * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_NSM_H #define _ZEBRA_OSPF_NSM_H /* OSPF Neighbor State Machine State. */ #define NSM_DependUpon 0 #define NSM_Deleted 1 #define NSM_Down 2 #define NSM_Attempt 3 #define NSM_Init 4 #define NSM_TwoWay 5 #define NSM_ExStart 6 #define NSM_Exchange 7 #define NSM_Loading 8 #define NSM_Full 9 #define OSPF_NSM_STATE_MAX 10 /* OSPF Neighbor State Machine Event. */ #define NSM_NoEvent 0 #define NSM_PacketReceived 1 /* HelloReceived in the protocol */ #define NSM_Start 2 #define NSM_TwoWayReceived 3 #define NSM_NegotiationDone 4 #define NSM_ExchangeDone 5 #define NSM_BadLSReq 6 #define NSM_LoadingDone 7 #define NSM_AdjOK 8 #define NSM_SeqNumberMismatch 9 #define NSM_OneWayReceived 10 #define NSM_KillNbr 11 #define NSM_InactivityTimer 12 #define NSM_LLDown 13 #define OSPF_NSM_EVENT_MAX 14 /* Macro for OSPF NSM timer turn on. */ #define OSPF_NSM_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), nbr, (V)); \ } while (0) /* Macro for OSPF NSM timer turn off. */ #define OSPF_NSM_TIMER_OFF(X) \ do { \ if (X) \ { \ thread_cancel (X); \ (X) = NULL; \ } \ } while (0) /* Macro for OSPF NSM schedule event. */ #define OSPF_NSM_EVENT_SCHEDULE(N,E) \ thread_add_event (master, ospf_nsm_event, (N), (E)) /* Macro for OSPF NSM execute event. */ #define OSPF_NSM_EVENT_EXECUTE(N,E) \ thread_execute (master, ospf_nsm_event, (N), (E)) /* Prototypes. */ extern int ospf_nsm_event (struct thread *); extern void ospf_check_nbr_loading (struct ospf_neighbor *); extern int ospf_db_summary_isempty (struct ospf_neighbor *); extern int ospf_db_summary_count (struct ospf_neighbor *); extern void ospf_db_summary_clear (struct ospf_neighbor *); #endif /* _ZEBRA_OSPF_NSM_H */ quagga-0.99.24.1/ospfd/ospf_lsdb.h0000644000175000017500000000717612476520570013506 00000000000000/* * OSPF LSDB support. * Copyright (C) 1999, 2000 Alex Zinin, Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H /* OSPF LSDB structure. */ struct ospf_lsdb { struct { unsigned long count; unsigned long count_self; unsigned int checksum; struct route_table *db; } type[OSPF_MAX_LSA]; unsigned long total; #define MONITOR_LSDB_CHANGE 1 /* XXX */ #ifdef MONITOR_LSDB_CHANGE /* Hooks for callback functions to catch every add/del event. */ int (* new_lsa_hook)(struct ospf_lsa *); int (* del_lsa_hook)(struct ospf_lsa *); #endif /* MONITOR_LSDB_CHANGE */ }; /* Macros. */ #define LSDB_LOOP(T,N,L) \ if ((T) != NULL) \ for ((N) = route_top ((T)); ((N)); ((N)) = route_next ((N))) \ if (((L) = (N)->info)) #define ROUTER_LSDB(A) ((A)->lsdb->type[OSPF_ROUTER_LSA].db) #define NETWORK_LSDB(A) ((A)->lsdb->type[OSPF_NETWORK_LSA].db) #define SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_SUMMARY_LSA].db) #define ASBR_SUMMARY_LSDB(A) ((A)->lsdb->type[OSPF_ASBR_SUMMARY_LSA].db) #define EXTERNAL_LSDB(O) ((O)->lsdb->type[OSPF_AS_EXTERNAL_LSA].db) #define NSSA_LSDB(A) ((A)->lsdb->type[OSPF_AS_NSSA_LSA].db) #define OPAQUE_LINK_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_LINK_LSA].db) #define OPAQUE_AREA_LSDB(A) ((A)->lsdb->type[OSPF_OPAQUE_AREA_LSA].db) #define OPAQUE_AS_LSDB(O) ((O)->lsdb->type[OSPF_OPAQUE_AS_LSA].db) #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new (void); extern void ospf_lsdb_init (struct ospf_lsdb *); extern void ospf_lsdb_free (struct ospf_lsdb *); extern void ospf_lsdb_cleanup (struct ospf_lsdb *); extern void ls_prefix_set (struct prefix_ls *lp, struct ospf_lsa *lsa); extern void ospf_lsdb_add (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete (struct ospf_lsdb *, struct ospf_lsa *); extern void ospf_lsdb_delete_all (struct ospf_lsdb *); /* Set all stats to -1 (LSA_SPF_NOT_EXPLORED). */ extern void ospf_lsdb_clean_stat (struct ospf_lsdb *lsdb); extern struct ospf_lsa *ospf_lsdb_lookup (struct ospf_lsdb *, struct ospf_lsa *); extern struct ospf_lsa *ospf_lsdb_lookup_by_id (struct ospf_lsdb *, u_char, struct in_addr, struct in_addr); extern struct ospf_lsa *ospf_lsdb_lookup_by_id_next (struct ospf_lsdb *, u_char, struct in_addr, struct in_addr, int); extern unsigned long ospf_lsdb_count_all (struct ospf_lsdb *); extern unsigned long ospf_lsdb_count (struct ospf_lsdb *, int); extern unsigned long ospf_lsdb_count_self (struct ospf_lsdb *, int); extern unsigned int ospf_lsdb_checksum (struct ospf_lsdb *, int); extern unsigned long ospf_lsdb_isempty (struct ospf_lsdb *); #endif /* _ZEBRA_OSPF_LSDB_H */ quagga-0.99.24.1/ospfd/ospf_lsa.h0000644000175000017500000002727012476520570013336 00000000000000/* * OSPF Link State Advertisement * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_LSA_H #define _ZEBRA_OSPF_LSA_H #include "stream.h" /* OSPF LSA Range definition. */ #define OSPF_MIN_LSA 1 /* begin range here */ #if defined (HAVE_OPAQUE_LSA) #define OSPF_MAX_LSA 12 #else #define OSPF_MAX_LSA 8 #endif /* OSPF LSA Type definition. */ #define OSPF_UNKNOWN_LSA 0 #define OSPF_ROUTER_LSA 1 #define OSPF_NETWORK_LSA 2 #define OSPF_SUMMARY_LSA 3 #define OSPF_ASBR_SUMMARY_LSA 4 #define OSPF_AS_EXTERNAL_LSA 5 #define OSPF_GROUP_MEMBER_LSA 6 /* Not supported. */ #define OSPF_AS_NSSA_LSA 7 #define OSPF_EXTERNAL_ATTRIBUTES_LSA 8 /* Not supported. */ #define OSPF_OPAQUE_LINK_LSA 9 #define OSPF_OPAQUE_AREA_LSA 10 #define OSPF_OPAQUE_AS_LSA 11 #define OSPF_LSA_HEADER_SIZE 20U #define OSPF_ROUTER_LSA_LINK_SIZE 12U #define OSPF_ROUTER_LSA_TOS_SIZE 4U #define OSPF_MAX_LSA_SIZE 1500U /* AS-external-LSA refresh method. */ #define LSA_REFRESH_IF_CHANGED 0 #define LSA_REFRESH_FORCE 1 /* OSPF LSA header. */ struct lsa_header { u_int16_t ls_age; u_char options; u_char type; struct in_addr id; struct in_addr adv_router; u_int32_t ls_seqnum; u_int16_t checksum; u_int16_t length; }; /* OSPF LSA. */ struct ospf_lsa { /* LSA origination flag. */ u_char flags; #define OSPF_LSA_SELF 0x01 #define OSPF_LSA_SELF_CHECKED 0x02 #define OSPF_LSA_RECEIVED 0x04 #define OSPF_LSA_APPROVED 0x08 #define OSPF_LSA_DISCARD 0x10 #define OSPF_LSA_LOCAL_XLT 0x20 #define OSPF_LSA_PREMATURE_AGE 0x40 #define OSPF_LSA_IN_MAXAGE 0x80 /* LSA data. */ struct lsa_header *data; /* Received time stamp. */ struct timeval tv_recv; /* Last time it was originated */ struct timeval tv_orig; /* All of reference count, also lock to remove. */ int lock; /* Flags for the SPF calculation. */ int stat; #define LSA_SPF_NOT_EXPLORED -1 #define LSA_SPF_IN_SPFTREE -2 /* If stat >= 0, stat is LSA position in candidates heap. */ /* References to this LSA in neighbor retransmission lists*/ int retransmit_counter; /* Area the LSA belongs to, may be NULL if AS-external-LSA. */ struct ospf_area *area; /* Parent LSDB. */ struct ospf_lsdb *lsdb; /* Related Route. */ void *route; /* Refreshement List or Queue */ int refresh_list; /* For Type-9 Opaque-LSAs */ struct ospf_interface *oi; }; /* OSPF LSA Link Type. */ #define LSA_LINK_TYPE_POINTOPOINT 1 #define LSA_LINK_TYPE_TRANSIT 2 #define LSA_LINK_TYPE_STUB 3 #define LSA_LINK_TYPE_VIRTUALLINK 4 /* OSPF Router LSA Flag. */ #define ROUTER_LSA_BORDER 0x01 /* The router is an ABR */ #define ROUTER_LSA_EXTERNAL 0x02 /* The router is an ASBR */ #define ROUTER_LSA_VIRTUAL 0x04 /* The router has a VL in this area */ #define ROUTER_LSA_NT 0x10 /* The routers always translates Type-7 */ #define ROUTER_LSA_SHORTCUT 0x20 /* Shortcut-ABR specific flag */ #define IS_ROUTER_LSA_VIRTUAL(x) ((x)->flags & ROUTER_LSA_VIRTUAL) #define IS_ROUTER_LSA_EXTERNAL(x) ((x)->flags & ROUTER_LSA_EXTERNAL) #define IS_ROUTER_LSA_BORDER(x) ((x)->flags & ROUTER_LSA_BORDER) #define IS_ROUTER_LSA_SHORTCUT(x) ((x)->flags & ROUTER_LSA_SHORTCUT) #define IS_ROUTER_LSA_NT(x) ((x)->flags & ROUTER_LSA_NT) /* OSPF Router-LSA Link information. */ struct router_lsa_link { struct in_addr link_id; struct in_addr link_data; struct { u_char type; u_char tos_count; u_int16_t metric; } m[1]; }; /* OSPF Router-LSAs structure. */ #define OSPF_ROUTER_LSA_MIN_SIZE 4U /* w/0 link descriptors */ /* There is an edge case, when number of links in a Router-LSA may be 0 without breaking the specification. A router, which has no other links to backbone area besides one virtual link, will not put any VL descriptor blocks into the Router-LSA generated for area 0 until a full adjacency over the VL is reached (RFC2328 12.4.1.3). In this case the Router-LSA initially received by the other end of the VL will have 0 link descriptor blocks, but soon will be replaced with the next revision having 1 descriptor block. */ struct router_lsa { struct lsa_header header; u_char flags; u_char zero; u_int16_t links; struct { struct in_addr link_id; struct in_addr link_data; u_char type; u_char tos; u_int16_t metric; } link[1]; }; /* OSPF Network-LSAs structure. */ #define OSPF_NETWORK_LSA_MIN_SIZE 8U /* w/1 router-ID */ struct network_lsa { struct lsa_header header; struct in_addr mask; struct in_addr routers[1]; }; /* OSPF Summary-LSAs structure. */ #define OSPF_SUMMARY_LSA_MIN_SIZE 8U /* w/1 TOS metric block */ struct summary_lsa { struct lsa_header header; struct in_addr mask; u_char tos; u_char metric[3]; }; /* OSPF AS-external-LSAs structure. */ #define OSPF_AS_EXTERNAL_LSA_MIN_SIZE 16U /* w/1 TOS forwarding block */ struct as_external_lsa { struct lsa_header header; struct in_addr mask; struct { u_char tos; u_char metric[3]; struct in_addr fwd_addr; u_int32_t route_tag; } e[1]; }; #ifdef HAVE_OPAQUE_LSA #include "ospfd/ospf_opaque.h" #endif /* HAVE_OPAQUE_LSA */ /* Macros. */ #define GET_METRIC(x) get_metric(x) #define IS_EXTERNAL_METRIC(x) ((x) & 0x80) #define GET_AGE(x) (ntohs ((x)->data->ls_age) + time (NULL) - (x)->tv_recv) #define LS_AGE(x) (OSPF_LSA_MAXAGE < get_age(x) ? \ OSPF_LSA_MAXAGE : get_age(x)) #define IS_LSA_SELF(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_SELF)) #define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE) #define OSPF_LSA_UPDATE_DELAY 2 #define OSPF_LSA_UPDATE_TIMER_ON(T,F) \ if (!(T)) \ (T) = thread_add_timer (master, (F), 0, 2) /* Prototypes. */ /* XXX: Eek, time functions, similar are in lib/thread.c */ extern struct timeval tv_adjust (struct timeval); extern int tv_ceil (struct timeval); extern int tv_floor (struct timeval); extern struct timeval int2tv (int); extern struct timeval tv_add (struct timeval, struct timeval); extern struct timeval tv_sub (struct timeval, struct timeval); extern int tv_cmp (struct timeval, struct timeval); extern int get_age (struct ospf_lsa *); extern u_int16_t ospf_lsa_checksum (struct lsa_header *); extern int ospf_lsa_checksum_valid (struct lsa_header *); extern int ospf_lsa_refresh_delay (struct ospf_lsa *); extern const char *dump_lsa_key (struct ospf_lsa *); extern u_int32_t lsa_seqnum_increment (struct ospf_lsa *); extern void lsa_header_set (struct stream *, u_char, u_char, struct in_addr, struct in_addr); extern struct ospf_neighbor *ospf_nbr_lookup_ptop (struct ospf_interface *); extern int ospf_check_nbr_status (struct ospf *); /* Prototype for LSA primitive. */ extern struct ospf_lsa *ospf_lsa_new (void); extern struct ospf_lsa *ospf_lsa_dup (struct ospf_lsa *); extern void ospf_lsa_free (struct ospf_lsa *); extern struct ospf_lsa *ospf_lsa_lock (struct ospf_lsa *); extern void ospf_lsa_unlock (struct ospf_lsa **); extern void ospf_lsa_discard (struct ospf_lsa *); extern struct lsa_header *ospf_lsa_data_new (size_t); extern struct lsa_header *ospf_lsa_data_dup (struct lsa_header *); extern void ospf_lsa_data_free (struct lsa_header *); /* Prototype for various LSAs */ extern int ospf_router_lsa_update (struct ospf *); extern int ospf_router_lsa_update_area (struct ospf_area *); extern void ospf_network_lsa_update (struct ospf_interface *); extern struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); extern struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); extern struct ospf_lsa *ospf_lsa_install (struct ospf *, struct ospf_interface *, struct ospf_lsa *); extern void ospf_nssa_lsa_flush (struct ospf *ospf, struct prefix_ipv4 *p); extern void ospf_external_lsa_flush (struct ospf *, u_char, struct prefix_ipv4 *, unsigned int /* , struct in_addr nexthop */); extern struct in_addr ospf_get_ip_from_ifp (struct ospf_interface *); extern struct ospf_lsa *ospf_external_lsa_originate (struct ospf *, struct external_info *); extern int ospf_external_lsa_originate_timer (struct thread *); extern int ospf_default_originate_timer (struct thread *); extern struct ospf_lsa *ospf_lsa_lookup (struct ospf_area *, u_int32_t, struct in_addr, struct in_addr); extern struct ospf_lsa *ospf_lsa_lookup_by_id (struct ospf_area *, u_int32_t, struct in_addr); extern struct ospf_lsa *ospf_lsa_lookup_by_header (struct ospf_area *, struct lsa_header *); extern int ospf_lsa_more_recent (struct ospf_lsa *, struct ospf_lsa *); extern int ospf_lsa_different (struct ospf_lsa *, struct ospf_lsa *); extern void ospf_flush_self_originated_lsas_now (struct ospf *); extern int ospf_lsa_is_self_originated (struct ospf *, struct ospf_lsa *); extern struct ospf_lsa *ospf_lsa_lookup_by_prefix (struct ospf_lsdb *, u_char, struct prefix_ipv4 *, struct in_addr); extern void ospf_lsa_maxage (struct ospf *, struct ospf_lsa *); extern u_int32_t get_metric (u_char *); extern int ospf_lsa_maxage_walker (struct thread *); extern struct ospf_lsa *ospf_lsa_refresh (struct ospf *, struct ospf_lsa *); extern void ospf_external_lsa_refresh_default (struct ospf *); extern void ospf_external_lsa_refresh_type (struct ospf *, u_char, int); extern struct ospf_lsa *ospf_external_lsa_refresh (struct ospf *, struct ospf_lsa *, struct external_info *, int); extern struct in_addr ospf_lsa_unique_id (struct ospf *, struct ospf_lsdb *, u_char, struct prefix_ipv4 *); extern void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_schedule_lsa_flush_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_refresher_register_lsa (struct ospf *, struct ospf_lsa *); extern void ospf_refresher_unregister_lsa (struct ospf *, struct ospf_lsa *); extern int ospf_lsa_refresh_walker (struct thread *); extern void ospf_lsa_maxage_delete (struct ospf *, struct ospf_lsa *); extern void ospf_discard_from_db (struct ospf *, struct ospf_lsdb *, struct ospf_lsa*); extern int is_prefix_default (struct prefix_ipv4 *); extern int metric_type (struct ospf *, u_char); extern int metric_value (struct ospf *, u_char); extern struct in_addr ospf_get_nssa_ip (struct ospf_area *); extern int ospf_translated_nssa_compare (struct ospf_lsa *, struct ospf_lsa *); extern struct ospf_lsa *ospf_translated_nssa_refresh (struct ospf *, struct ospf_lsa *, struct ospf_lsa *); extern struct ospf_lsa *ospf_translated_nssa_originate (struct ospf *, struct ospf_lsa *); #endif /* _ZEBRA_OSPF_LSA_H */ quagga-0.99.24.1/ospfd/ospf_dump.h0000644000175000017500000001151412476520570013516 00000000000000/* * OSPFd dump routine. * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_DUMP_H #define _ZEBRA_OSPF_DUMP_H /* Debug Flags. */ #define OSPF_DEBUG_HELLO 0x01 #define OSPF_DEBUG_DB_DESC 0x02 #define OSPF_DEBUG_LS_REQ 0x04 #define OSPF_DEBUG_LS_UPD 0x08 #define OSPF_DEBUG_LS_ACK 0x10 #define OSPF_DEBUG_ALL 0x1f #define OSPF_DEBUG_SEND 0x01 #define OSPF_DEBUG_RECV 0x02 #define OSPF_DEBUG_SEND_RECV 0x03 #define OSPF_DEBUG_DETAIL 0x04 #define OSPF_DEBUG_ISM_STATUS 0x01 #define OSPF_DEBUG_ISM_EVENTS 0x02 #define OSPF_DEBUG_ISM_TIMERS 0x04 #define OSPF_DEBUG_ISM 0x07 #define OSPF_DEBUG_NSM_STATUS 0x01 #define OSPF_DEBUG_NSM_EVENTS 0x02 #define OSPF_DEBUG_NSM_TIMERS 0x04 #define OSPF_DEBUG_NSM 0x07 #define OSPF_DEBUG_LSA_GENERATE 0x01 #define OSPF_DEBUG_LSA_FLOODING 0x02 #define OSPF_DEBUG_LSA_INSTALL 0x04 #define OSPF_DEBUG_LSA_REFRESH 0x08 #define OSPF_DEBUG_LSA 0x0F #define OSPF_DEBUG_ZEBRA_INTERFACE 0x01 #define OSPF_DEBUG_ZEBRA_REDISTRIBUTE 0x02 #define OSPF_DEBUG_ZEBRA 0x03 #define OSPF_DEBUG_EVENT 0x01 #define OSPF_DEBUG_NSSA 0x02 /* Macro for setting debug option. */ #define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b) #define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b) #define TERM_DEBUG_PACKET_ON(a, b) term_debug_ospf_packet[a] |= (b) #define TERM_DEBUG_PACKET_OFF(a, b) term_debug_ospf_packet[a] &= ~(b) #define DEBUG_PACKET_ON(a, b) \ do { \ CONF_DEBUG_PACKET_ON(a, b); \ TERM_DEBUG_PACKET_ON(a, b); \ } while (0) #define DEBUG_PACKET_OFF(a, b) \ do { \ CONF_DEBUG_PACKET_OFF(a, b); \ TERM_DEBUG_PACKET_OFF(a, b); \ } while (0) #define CONF_DEBUG_ON(a, b) conf_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) #define CONF_DEBUG_OFF(a, b) conf_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) #define TERM_DEBUG_ON(a, b) term_debug_ospf_ ## a |= (OSPF_DEBUG_ ## b) #define TERM_DEBUG_OFF(a, b) term_debug_ospf_ ## a &= ~(OSPF_DEBUG_ ## b) #define DEBUG_ON(a, b) \ do { \ CONF_DEBUG_ON(a, b); \ TERM_DEBUG_ON(a, b); \ } while (0) #define DEBUG_OFF(a, b) \ do { \ CONF_DEBUG_OFF(a, b); \ TERM_DEBUG_OFF(a, b); \ } while (0) /* Macro for checking debug option. */ #define IS_DEBUG_OSPF_PACKET(a, b) \ (term_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_DEBUG_OSPF(a, b) \ (term_debug_ospf_ ## a & OSPF_DEBUG_ ## b) #define IS_DEBUG_OSPF_EVENT IS_DEBUG_OSPF(event,EVENT) #define IS_DEBUG_OSPF_NSSA IS_DEBUG_OSPF(nssa,NSSA) #define IS_CONF_DEBUG_OSPF_PACKET(a, b) \ (conf_debug_ospf_packet[a] & OSPF_DEBUG_ ## b) #define IS_CONF_DEBUG_OSPF(a, b) \ (conf_debug_ospf_ ## a & OSPF_DEBUG_ ## b) #ifdef ORIGINAL_CODING #else /* ORIGINAL_CODING */ struct stream; #endif /* ORIGINAL_CODING */ #define AREA_NAME(A) ospf_area_name_string ((A)) #define IF_NAME(I) ospf_if_name_string ((I)) /* Extern debug flag. */ extern unsigned long term_debug_ospf_packet[]; extern unsigned long term_debug_ospf_event; extern unsigned long term_debug_ospf_ism; extern unsigned long term_debug_ospf_nsm; extern unsigned long term_debug_ospf_lsa; extern unsigned long term_debug_ospf_zebra; extern unsigned long term_debug_ospf_nssa; /* Message Strings. */ extern char *ospf_lsa_type_str[]; extern const struct message ospf_auth_type_str[]; extern const size_t ospf_auth_type_str_max; /* Prototypes. */ extern const char *ospf_area_name_string (struct ospf_area *); extern const char *ospf_area_desc_string (struct ospf_area *); extern const char *ospf_if_name_string (struct ospf_interface *); extern void ospf_nbr_state_message (struct ospf_neighbor *, char *, size_t); extern char *ospf_options_dump (u_char); extern const char *ospf_timer_dump (struct thread *, char *, size_t); extern const char *ospf_timeval_dump (struct timeval *, char *, size_t); extern void ospf_ip_header_dump (struct ip *); extern void ospf_packet_dump (struct stream *); extern void ospf_lsa_header_dump (struct lsa_header *); extern void debug_init (void); /* Appropriate buffer size to use with ospf_timer_dump and ospf_timeval_dump: */ #define OSPF_TIME_DUMP_SIZE 16 #endif /* _ZEBRA_OSPF_DUMP_H */ quagga-0.99.24.1/ospfd/ospf_asbr.h0000644000175000017500000000530712476520570013503 00000000000000/* * OSPF AS Boundary Router functions. * Copyright (C) 1999, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ASBR_H #define _ZEBRA_OSPF_ASBR_H struct route_map_set_values { int32_t metric; int32_t metric_type; }; /* Redistributed external information. */ struct external_info { /* Type of source protocol. */ u_char type; /* Prefix. */ struct prefix_ipv4 p; /* Interface index. */ unsigned int ifindex; /* Nexthop address. */ struct in_addr nexthop; /* Additional Route tag. */ u_int32_t tag; struct route_map_set_values route_map_set; #define ROUTEMAP_METRIC(E) (E)->route_map_set.metric #define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type }; #define OSPF_ASBR_CHECK_DELAY 30 extern void ospf_external_route_remove (struct ospf *, struct prefix_ipv4 *); extern struct external_info *ospf_external_info_new (u_char); extern void ospf_reset_route_map_set_values (struct route_map_set_values *); extern int ospf_route_map_set_compare (struct route_map_set_values *, struct route_map_set_values *); extern struct external_info *ospf_external_info_add (u_char, struct prefix_ipv4, unsigned int, struct in_addr); extern void ospf_external_info_delete (u_char, struct prefix_ipv4); extern struct external_info *ospf_external_info_lookup (u_char, struct prefix_ipv4 *); extern struct ospf_route *ospf_external_route_lookup (struct ospf *, struct prefix_ipv4 *); extern void ospf_asbr_status_update (struct ospf *, u_char); extern void ospf_redistribute_withdraw (struct ospf *, u_char); extern void ospf_asbr_check (void); extern void ospf_schedule_asbr_check (void); extern void ospf_asbr_route_install_lsa (struct ospf_lsa *); extern struct ospf_lsa *ospf_external_info_find_lsa (struct ospf *, struct prefix_ipv4 *p); #endif /* _ZEBRA_OSPF_ASBR_H */ quagga-0.99.24.1/ospfd/ospf_api.h0000644000175000017500000002511712476520570013326 00000000000000/* * API message handling module for OSPF daemon and client. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* This file is used both by the OSPFd and client applications to define message formats used for communication. */ #ifndef _OSPF_API_H #define _OSPF_API_H #define OSPF_API_VERSION 1 /* MTYPE definition is not reflected to "memory.h". */ #define MTYPE_OSPF_API_MSG MTYPE_TMP #define MTYPE_OSPF_API_FIFO MTYPE_TMP /* Default API server port to accept connection request from client-side. */ /* This value could be overridden by "ospfapi" entry in "/etc/services". */ #define OSPF_API_SYNC_PORT 2607 /* ----------------------------------------------------------- * Generic messages * ----------------------------------------------------------- */ /* Message header structure, fields are in network byte order and aligned to four octets. */ struct apimsghdr { u_char version; /* OSPF API protocol version */ u_char msgtype; /* Type of message */ u_int16_t msglen; /* Length of message w/o header */ u_int32_t msgseq; /* Sequence number */ }; /* Message representation with header and body */ struct msg { struct msg *next; /* to link into fifo */ /* Message header */ struct apimsghdr hdr; /* Message body */ struct stream *s; }; /* Prototypes for generic messages. */ extern struct msg *msg_new (u_char msgtype, void *msgbody, u_int32_t seqnum, u_int16_t msglen); extern struct msg *msg_dup (struct msg *msg); extern void msg_print (struct msg *msg); /* XXX debug only */ extern void msg_free (struct msg *msg); struct msg *msg_read (int fd); extern int msg_write (int fd, struct msg *msg); /* For requests, the message sequence number is between MIN_SEQ and MAX_SEQ. For notifications, the sequence number is 0. */ #define MIN_SEQ 1 #define MAX_SEQ 2147483647 extern void msg_set_seq (struct msg *msg, u_int32_t seqnr); extern u_int32_t msg_get_seq (struct msg *msg); /* ----------------------------------------------------------- * Message fifo queues * ----------------------------------------------------------- */ /* Message queue structure. */ struct msg_fifo { unsigned long count; struct msg *head; struct msg *tail; }; /* Prototype for message fifo queues. */ extern struct msg_fifo *msg_fifo_new (void); extern void msg_fifo_push (struct msg_fifo *, struct msg *msg); extern struct msg *msg_fifo_pop (struct msg_fifo *fifo); extern struct msg *msg_fifo_head (struct msg_fifo *fifo); extern void msg_fifo_flush (struct msg_fifo *fifo); extern void msg_fifo_free (struct msg_fifo *fifo); /* ----------------------------------------------------------- * Specific message type and format definitions * ----------------------------------------------------------- */ /* Messages to OSPF daemon. */ #define MSG_REGISTER_OPAQUETYPE 1 #define MSG_UNREGISTER_OPAQUETYPE 2 #define MSG_REGISTER_EVENT 3 #define MSG_SYNC_LSDB 4 #define MSG_ORIGINATE_REQUEST 5 #define MSG_DELETE_REQUEST 6 /* Messages from OSPF daemon. */ #define MSG_REPLY 10 #define MSG_READY_NOTIFY 11 #define MSG_LSA_UPDATE_NOTIFY 12 #define MSG_LSA_DELETE_NOTIFY 13 #define MSG_NEW_IF 14 #define MSG_DEL_IF 15 #define MSG_ISM_CHANGE 16 #define MSG_NSM_CHANGE 17 struct msg_register_opaque_type { u_char lsatype; u_char opaquetype; u_char pad[2]; /* padding */ }; struct msg_unregister_opaque_type { u_char lsatype; u_char opaquetype; u_char pad[2]; /* padding */ }; /* Power2 is needed to convert LSA types into bit positions, * see typemask below. Type definition starts at 1, so * Power2[0] is not used. */ #ifdef ORIGINAL_CODING static const u_int16_t Power2[] = { 0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 }; #else static const u_int16_t Power2[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15) }; #endif /* ORIGINAL_CODING */ struct lsa_filter_type { u_int16_t typemask; /* bitmask for selecting LSA types (1..16) */ u_char origin; /* selects according to origin. */ #define NON_SELF_ORIGINATED 0 #define SELF_ORIGINATED (OSPF_LSA_SELF) #define ANY_ORIGIN 2 u_char num_areas; /* number of areas in the filter. */ /* areas, if any, go here. */ }; struct msg_register_event { struct lsa_filter_type filter; }; struct msg_sync_lsdb { struct lsa_filter_type filter; }; struct msg_originate_request { /* Used for LSA type 9 otherwise ignored */ struct in_addr ifaddr; /* Used for LSA type 10 otherwise ignored */ struct in_addr area_id; /* LSA header and LSA-specific part */ struct lsa_header data; }; struct msg_delete_request { struct in_addr area_id; /* "0.0.0.0" for AS-external opaque LSAs */ u_char lsa_type; u_char opaque_type; u_char pad[2]; /* padding */ u_int32_t opaque_id; }; struct msg_reply { signed char errcode; #define OSPF_API_OK 0 #define OSPF_API_NOSUCHINTERFACE (-1) #define OSPF_API_NOSUCHAREA (-2) #define OSPF_API_NOSUCHLSA (-3) #define OSPF_API_ILLEGALLSATYPE (-4) #define OSPF_API_OPAQUETYPEINUSE (-5) #define OSPF_API_OPAQUETYPENOTREGISTERED (-6) #define OSPF_API_NOTREADY (-7) #define OSPF_API_NOMEMORY (-8) #define OSPF_API_ERROR (-9) #define OSPF_API_UNDEF (-10) u_char pad[3]; /* padding to four byte alignment */ }; /* Message to tell client application that it ospf daemon is * ready to accept opaque LSAs for a given interface or area. */ struct msg_ready_notify { u_char lsa_type; u_char opaque_type; u_char pad[2]; /* padding */ struct in_addr addr; /* interface address or area address */ }; /* These messages have a dynamic length depending on the embodied LSA. They are aligned to four octets. msg_lsa_change_notify is used for both LSA update and LSAs delete. */ struct msg_lsa_change_notify { /* Used for LSA type 9 otherwise ignored */ struct in_addr ifaddr; /* Area ID. Not valid for AS-External and Opaque11 LSAs. */ struct in_addr area_id; u_char is_self_originated; /* 1 if self originated. */ u_char pad[3]; struct lsa_header data; }; struct msg_new_if { struct in_addr ifaddr; /* interface IP address */ struct in_addr area_id; /* area this interface belongs to */ }; struct msg_del_if { struct in_addr ifaddr; /* interface IP address */ }; struct msg_ism_change { struct in_addr ifaddr; /* interface IP address */ struct in_addr area_id; /* area this interface belongs to */ u_char status; /* interface status (up/down) */ u_char pad[3]; /* not used */ }; struct msg_nsm_change { struct in_addr ifaddr; /* attached interface */ struct in_addr nbraddr; /* Neighbor interface address */ struct in_addr router_id; /* Router ID of neighbor */ u_char status; /* NSM status */ u_char pad[3]; }; /* We make use of a union to define a structure that covers all possible API messages. This allows us to find out how much memory needs to be reserved for the largest API message. */ struct apimsg { struct apimsghdr hdr; union { struct msg_register_opaque_type register_opaque_type; struct msg_register_event register_event; struct msg_sync_lsdb sync_lsdb; struct msg_originate_request originate_request; struct msg_delete_request delete_request; struct msg_reply reply; struct msg_ready_notify ready_notify; struct msg_new_if new_if; struct msg_del_if del_if; struct msg_ism_change ism_change; struct msg_nsm_change nsm_change; struct msg_lsa_change_notify lsa_change_notify; } u; }; #define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_LSA_SIZE) /* ----------------------------------------------------------- * Prototypes for specific messages * ----------------------------------------------------------- */ /* For debugging only. */ extern void api_opaque_lsa_print (struct lsa_header *data); /* Messages sent by client */ extern struct msg *new_msg_register_opaque_type (u_int32_t seqnum, u_char ltype, u_char otype); extern struct msg *new_msg_register_event (u_int32_t seqnum, struct lsa_filter_type *filter); extern struct msg *new_msg_sync_lsdb (u_int32_t seqnum, struct lsa_filter_type *filter); extern struct msg *new_msg_originate_request (u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, struct lsa_header *data); extern struct msg *new_msg_delete_request (u_int32_t seqnum, struct in_addr area_id, u_char lsa_type, u_char opaque_type, u_int32_t opaque_id); /* Messages sent by OSPF daemon */ extern struct msg *new_msg_reply (u_int32_t seqnum, u_char rc); extern struct msg *new_msg_ready_notify (u_int32_t seqnr, u_char lsa_type, u_char opaque_type, struct in_addr addr); extern struct msg *new_msg_new_if (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area); extern struct msg *new_msg_del_if (u_int32_t seqnr, struct in_addr ifaddr); extern struct msg *new_msg_ism_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr area, u_char status); extern struct msg *new_msg_nsm_change (u_int32_t seqnr, struct in_addr ifaddr, struct in_addr nbraddr, struct in_addr router_id, u_char status); /* msgtype is MSG_LSA_UPDATE_NOTIFY or MSG_LSA_DELETE_NOTIFY */ extern struct msg *new_msg_lsa_change_notify (u_char msgtype, u_int32_t seqnum, struct in_addr ifaddr, struct in_addr area_id, u_char is_self_originated, struct lsa_header *data); /* string printing functions */ extern const char *ospf_api_errname (int errcode); extern const char *ospf_api_typename (int msgtype); #endif /* _OSPF_API_H */ quagga-0.99.24.1/ospfd/ospf_apiserver.h0000644000175000017500000001761112476520570014555 00000000000000/* * Server side of OSPF API. * Copyright (C) 2001, 2002 Ralph Keller * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _OSPF_APISERVER_H #define _OSPF_APISERVER_H /* MTYPE definition is not reflected to "memory.h". */ #define MTYPE_OSPF_APISERVER MTYPE_TMP #define MTYPE_OSPF_APISERVER_MSGFILTER MTYPE_TMP /* List of opaque types that application registered */ struct registered_opaque_type { u_char lsa_type; u_char opaque_type; }; /* Server instance for each accepted client connection. */ struct ospf_apiserver { /* Socket connections for synchronous commands and asynchronous notifications */ int fd_sync; /* synchronous requests */ struct sockaddr_in peer_sync; int fd_async; /* asynchronous notifications */ struct sockaddr_in peer_async; /* List of all opaque types that application registers to use. Using a single connection with the OSPF daemon, multiple pairs can be registered. However, each combination can only be registered once by all applications. */ struct list *opaque_types; /* of type registered_opaque_type */ /* Temporary storage for LSA instances to be refreshed. */ struct ospf_lsdb reserve; /* filter for LSA update/delete notifies */ struct lsa_filter_type *filter; /* Fifo buffers for outgoing messages */ struct msg_fifo *out_sync_fifo; struct msg_fifo *out_async_fifo; /* Read and write threads */ struct thread *t_sync_read; #ifdef USE_ASYNC_READ struct thread *t_async_read; #endif /* USE_ASYNC_READ */ struct thread *t_sync_write; struct thread *t_async_write; }; enum event { OSPF_APISERVER_ACCEPT, OSPF_APISERVER_SYNC_READ, #ifdef USE_ASYNC_READ OSPF_APISERVER_ASYNC_READ, #endif /* USE_ASYNC_READ */ OSPF_APISERVER_SYNC_WRITE, OSPF_APISERVER_ASYNC_WRITE }; /* ----------------------------------------------------------- * Followings are functions to manage client connections. * ----------------------------------------------------------- */ extern unsigned short ospf_apiserver_getport (void); extern int ospf_apiserver_init (void); extern void ospf_apiserver_term (void); extern struct ospf_apiserver *ospf_apiserver_new (int fd_sync, int fd_async); extern void ospf_apiserver_free (struct ospf_apiserver *apiserv); extern void ospf_apiserver_event (enum event event, int fd, struct ospf_apiserver *apiserv); extern int ospf_apiserver_serv_sock_family (unsigned short port, int family); extern int ospf_apiserver_accept (struct thread *thread); extern int ospf_apiserver_read (struct thread *thread); extern int ospf_apiserver_sync_write (struct thread *thread); extern int ospf_apiserver_async_write (struct thread *thread); extern int ospf_apiserver_send_reply (struct ospf_apiserver *apiserv, u_int32_t seqnr, u_char rc); /* ----------------------------------------------------------- * Followings are message handler functions * ----------------------------------------------------------- */ extern int ospf_apiserver_lsa9_originator (void *arg); extern int ospf_apiserver_lsa10_originator (void *arg); extern int ospf_apiserver_lsa11_originator (void *arg); extern void ospf_apiserver_clients_notify_all (struct msg *msg); extern void ospf_apiserver_clients_notify_ready_type9 (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_ready_type10 (struct ospf_area *area); extern void ospf_apiserver_clients_notify_ready_type11 (struct ospf *top); extern void ospf_apiserver_clients_notify_new_if (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_del_if (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_ism_change (struct ospf_interface *oi); extern void ospf_apiserver_clients_notify_nsm_change (struct ospf_neighbor *nbr); extern int ospf_apiserver_is_ready_type9 (struct ospf_interface *oi); extern int ospf_apiserver_is_ready_type10 (struct ospf_area *area); extern int ospf_apiserver_is_ready_type11 (struct ospf *ospf); extern void ospf_apiserver_notify_ready_type9 (struct ospf_apiserver *apiserv); extern void ospf_apiserver_notify_ready_type10 (struct ospf_apiserver *apiserv); extern void ospf_apiserver_notify_ready_type11 (struct ospf_apiserver *apiserv); extern int ospf_apiserver_handle_msg (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_register_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_unregister_opaque_type (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_register_event (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_originate_request (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_delete_request (struct ospf_apiserver *apiserv, struct msg *msg); extern int ospf_apiserver_handle_sync_lsdb (struct ospf_apiserver *apiserv, struct msg *msg); /* ----------------------------------------------------------- * Followings are functions for LSA origination/deletion * ----------------------------------------------------------- */ extern int ospf_apiserver_register_opaque_type (struct ospf_apiserver *apiserver, u_char lsa_type, u_char opaque_type); extern int ospf_apiserver_unregister_opaque_type (struct ospf_apiserver *apiserver, u_char lsa_type, u_char opaque_type); extern struct ospf_lsa *ospf_apiserver_opaque_lsa_new (struct ospf_area *area, struct ospf_interface *oi, struct lsa_header *protolsa); extern struct ospf_interface *ospf_apiserver_if_lookup_by_addr (struct in_addr address); extern struct ospf_interface *ospf_apiserver_if_lookup_by_ifp (struct interface *ifp); extern int ospf_apiserver_originate1 (struct ospf_lsa *lsa); extern void ospf_apiserver_flood_opaque_lsa (struct ospf_lsa *lsa); /* ----------------------------------------------------------- * Followings are callback functions to handle opaque types * ----------------------------------------------------------- */ extern int ospf_apiserver_new_if (struct interface *ifp); extern int ospf_apiserver_del_if (struct interface *ifp); extern void ospf_apiserver_ism_change (struct ospf_interface *oi, int old_status); extern void ospf_apiserver_nsm_change (struct ospf_neighbor *nbr, int old_status); extern void ospf_apiserver_config_write_router (struct vty *vty); extern void ospf_apiserver_config_write_if (struct vty *vty, struct interface *ifp); extern void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa); extern int ospf_ospf_apiserver_lsa_originator (void *arg); extern struct ospf_lsa *ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa); extern void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv, u_char lsa_type, u_char opaque_type); /* ----------------------------------------------------------- * Followings are hooks when LSAs are updated or deleted * ----------------------------------------------------------- */ /* Hooks that are invoked from ospf opaque module */ extern int ospf_apiserver_lsa_update (struct ospf_lsa *lsa); extern int ospf_apiserver_lsa_delete (struct ospf_lsa *lsa); extern void ospf_apiserver_clients_lsa_change_notify (u_char msgtype, struct ospf_lsa *lsa); #endif /* _OSPF_APISERVER_H */ quagga-0.99.24.1/ospfd/ospf_vty.h0000644000175000017500000000546012476520570013376 00000000000000/* OSPF VTY interface. * Copyright (C) 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_OSPF_VTY_H #define _QUAGGA_OSPF_VTY_H /* Macros. */ #define VTY_GET_OSPF_AREA_ID(V,F,STR) \ { \ int retv; \ retv = ospf_str2area_id ((STR), &(V), &(F)); \ if (retv < 0) \ { \ vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ return CMD_WARNING; \ } \ } #define VTY_GET_OSPF_AREA_ID_NO_BB(NAME,V,F,STR) \ { \ int retv; \ retv = ospf_str2area_id ((STR), &(V), &(F)); \ if (retv < 0) \ { \ vty_out (vty, "%% Invalid OSPF area ID%s", VTY_NEWLINE); \ return CMD_WARNING; \ } \ if (OSPF_IS_AREA_ID_BACKBONE ((V))) \ { \ vty_out (vty, "%% You can't configure %s to backbone%s", \ NAME, VTY_NEWLINE); \ } \ } /* Prototypes. */ extern void ospf_vty_init (void); extern void ospf_vty_show_init (void); #endif /* _QUAGGA_OSPF_VTY_H */ quagga-0.99.24.1/ospfd/ospf_te.h0000644000175000017500000001337112476520570013164 00000000000000/* * This is an implementation of draft-katz-yeung-ospf-traffic-06.txt * Copyright (C) 2001 KDD R&D Laboratories, Inc. * http://www.kddlabs.co.jp/ * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_MPLS_TE_H #define _ZEBRA_OSPF_MPLS_TE_H /* * Opaque LSA's link state ID for Traffic Engineering is * structured as follows. * * 24 16 8 0 * +--------+--------+--------+--------+ * | 1 | MBZ |........|........| * +--------+--------+--------+--------+ * |<-Type->||<-- Instance --->| * * * Type: IANA has assigned '1' for Traffic Engineering. * MBZ: Reserved, must be set to zero. * Instance: User may select an arbitrary 16-bit value. * */ #define MAX_LEGAL_TE_INSTANCE_NUM (0xffff) /* * 24 16 8 0 * +--------+--------+--------+--------+ --- * | LS age |Options | 10 | A * +--------+--------+--------+--------+ | * | 1 | 0 | Instance | | * +--------+--------+--------+--------+ | * | Advertising router | | Standard (Opaque) LSA header; * +--------+--------+--------+--------+ | Only type-10 is used. * | LS sequence number | | * +--------+--------+--------+--------+ | * | LS checksum | Length | V * +--------+--------+--------+--------+ --- * | Type | Length | A * +--------+--------+--------+--------+ | TLV part for TE; Values might be * | Values ... | V structured as a set of sub-TLVs. * +--------+--------+--------+--------+ --- */ /* * Following section defines TLV (tag, length, value) structures, * used for Traffic Engineering. */ struct te_tlv_header { u_int16_t type; /* TE_TLV_XXX (see below) */ u_int16_t length; /* Value portion only, in octets */ }; #define TLV_HDR_SIZE \ (sizeof (struct te_tlv_header)) #define TLV_BODY_SIZE(tlvh) \ (ROUNDUP (ntohs ((tlvh)->length), sizeof (u_int32_t))) #define TLV_SIZE(tlvh) \ (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) #define TLV_HDR_TOP(lsah) \ (struct te_tlv_header *)((char *)(lsah) + OSPF_LSA_HEADER_SIZE) #define TLV_HDR_NEXT(tlvh) \ (struct te_tlv_header *)((char *)(tlvh) + TLV_SIZE(tlvh)) /* * Following section defines TLV body parts. */ /* Router Address TLV *//* Mandatory */ #define TE_TLV_ROUTER_ADDR 1 struct te_tlv_router_addr { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; }; /* Link TLV */ #define TE_TLV_LINK 2 struct te_tlv_link { struct te_tlv_header header; /* A set of link-sub-TLVs will follow. */ }; /* Link Type Sub-TLV *//* Mandatory */ #define TE_LINK_SUBTLV_LINK_TYPE 1 struct te_link_subtlv_link_type { struct te_tlv_header header; /* Value length is 1 octet. */ struct { #define LINK_TYPE_SUBTLV_VALUE_PTP 1 #define LINK_TYPE_SUBTLV_VALUE_MA 2 u_char value; u_char padding[3]; } link_type; }; /* Link Sub-TLV: Link ID *//* Mandatory */ #define TE_LINK_SUBTLV_LINK_ID 2 struct te_link_subtlv_link_id { struct te_tlv_header header; /* Value length is 4 octets. */ struct in_addr value; /* Same as router-lsa's link-id. */ }; /* Link Sub-TLV: Local Interface IP Address *//* Optional */ #define TE_LINK_SUBTLV_LCLIF_IPADDR 3 struct te_link_subtlv_lclif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Local IP address(es). */ }; /* Link Sub-TLV: Remote Interface IP Address *//* Optional */ #define TE_LINK_SUBTLV_RMTIF_IPADDR 4 struct te_link_subtlv_rmtif_ipaddr { struct te_tlv_header header; /* Value length is 4 x N octets. */ struct in_addr value[1]; /* Neighbor's IP address(es). */ }; /* Link Sub-TLV: Traffic Engineering Metric *//* Optional */ #define TE_LINK_SUBTLV_TE_METRIC 5 struct te_link_subtlv_te_metric { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Link metric for TE purpose. */ }; /* Link Sub-TLV: Maximum Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_MAX_BW 6 struct te_link_subtlv_max_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; /* Link Sub-TLV: Maximum Reservable Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_MAX_RSV_BW 7 struct te_link_subtlv_max_rsv_bw { struct te_tlv_header header; /* Value length is 4 octets. */ float value; /* bytes/sec */ }; /* Link Sub-TLV: Unreserved Bandwidth *//* Optional */ #define TE_LINK_SUBTLV_UNRSV_BW 8 struct te_link_subtlv_unrsv_bw { struct te_tlv_header header; /* Value length is 32 octets. */ float value[8]; /* One for each priority level. */ }; /* Link Sub-TLV: Resource Class/Color *//* Optional */ #define TE_LINK_SUBTLV_RSC_CLSCLR 9 struct te_link_subtlv_rsc_clsclr { struct te_tlv_header header; /* Value length is 4 octets. */ u_int32_t value; /* Admin. group membership. */ }; /* Here are "non-official" architechtual constants. */ #define MPLS_TE_MINIMUM_BANDWIDTH 1.0 /* Reasonable? *//* XXX */ /* Prototypes. */ extern int ospf_mpls_te_init (void); extern void ospf_mpls_te_term (void); #endif /* _ZEBRA_OSPF_MPLS_TE_H */ quagga-0.99.24.1/ospfd/ospf_snmp.h0000644000175000017500000000264312476520570013531 00000000000000/* OSPFv2 SNMP support * Copyright (C) 2000 IP Infusion Inc. * * Written by Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_SNMP_H #define _ZEBRA_OSPF_SNMP_H extern void ospf_snmp_if_update (struct interface *); extern void ospf_snmp_if_delete (struct interface *); extern void ospf_snmp_vl_add (struct ospf_vl_data *); extern void ospf_snmp_vl_delete (struct ospf_vl_data *); extern void ospfTrapIfStateChange (struct ospf_interface *); extern void ospfTrapVirtIfStateChange (struct ospf_interface *); extern void ospfTrapNbrStateChange (struct ospf_neighbor *); extern void ospfTrapVirtNbrStateChange (struct ospf_neighbor *); #endif /* _ZEBRA_OSPF_SNMP_H */ quagga-0.99.24.1/ospfd/ospf_flood.h0000644000175000017500000000627412476520570013663 00000000000000/* * OSPF Flooding -- RFC2328 Section 13. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H extern int ospf_flood (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *); extern int ospf_flood_through_area (struct ospf_area *, struct ospf_neighbor *, struct ospf_lsa *); extern int ospf_flood_through_as (struct ospf *, struct ospf_neighbor *, struct ospf_lsa *); extern unsigned long ospf_ls_request_count (struct ospf_neighbor *); extern int ospf_ls_request_isempty (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_request_new (struct lsa_header *); extern void ospf_ls_request_free (struct ospf_lsa *); extern void ospf_ls_request_add (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_request_delete (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_request_delete_all (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_request_lookup (struct ospf_neighbor *, struct ospf_lsa *); extern unsigned long ospf_ls_retransmit_count (struct ospf_neighbor *); extern unsigned long ospf_ls_retransmit_count_self (struct ospf_neighbor *, int); extern int ospf_ls_retransmit_isempty (struct ospf_neighbor *); extern void ospf_ls_retransmit_add (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear (struct ospf_neighbor *); extern struct ospf_lsa *ospf_ls_retransmit_lookup (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area (struct ospf_area *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_as (struct ospf *, struct ospf_lsa *); extern void ospf_ls_retransmit_add_nbr_all (struct ospf_interface *, struct ospf_lsa *); extern void ospf_flood_lsa_area (struct ospf_lsa *, struct ospf_area *); extern void ospf_flood_lsa_as (struct ospf_lsa *); extern void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *); extern void ospf_lsa_flush_as (struct ospf *, struct ospf_lsa *); extern void ospf_lsa_flush (struct ospf *, struct ospf_lsa *); extern struct external_info *ospf_external_info_check (struct ospf_lsa *); extern void ospf_lsdb_init (struct ospf_lsdb *); #endif /* _ZEBRA_OSPF_FLOOD_H */ quagga-0.99.24.1/ospfd/ospf_ia.h0000644000175000017500000000273712476520570013151 00000000000000/* * OSPF inter-area routing. * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_IA_H #define _ZEBRA_OSPF_IA_H /* Macros. */ #define OSPF_EXAMINE_SUMMARIES_ALL(A,N,R) \ { \ ospf_examine_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ ospf_examine_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ } #define OSPF_EXAMINE_TRANSIT_SUMMARIES_ALL(A,N,R) \ { \ ospf_examine_transit_summaries ((A), SUMMARY_LSDB ((A)), (N), (R)); \ ospf_examine_transit_summaries ((A), ASBR_SUMMARY_LSDB ((A)), (N), (R)); \ } extern void ospf_ia_routing (struct ospf *, struct route_table *, struct route_table *); extern int ospf_area_is_transit (struct ospf_area *); #endif /* _ZEBRA_OSPF_IA_H */ quagga-0.99.24.1/ospfd/ospf_abr.h0000644000175000017500000000563212476520570013321 00000000000000/* * OSPF ABR functions. * Copyright (C) 1999 Alex Zinin * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ABR_H #define _ZEBRA_OSPF_ABR_H #define OSPF_ABR_TASK_DELAY 7 #define OSPF_AREA_RANGE_ADVERTISE (1 << 0) #define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1) /* Area range. */ struct ospf_area_range { /* Area range address. */ struct in_addr addr; /* Area range masklen. */ u_char masklen; /* Flags. */ u_char flags; /* Number of more specific prefixes. */ int specifics; /* Addr and masklen to substitute. */ struct in_addr subst_addr; u_char subst_masklen; /* Range cost. */ u_int32_t cost; /* Configured range cost. */ u_int32_t cost_config; #define OSPF_AREA_RANGE_COST_UNSPEC -1U }; /* Prototypes. */ extern struct ospf_area_range *ospf_area_range_lookup (struct ospf_area *, struct prefix_ipv4 *); extern struct ospf_area_range *ospf_some_area_range_match (struct prefix_ipv4 *); extern struct ospf_area_range *ospf_area_range_lookup_next (struct ospf_area *, struct in_addr *, int); extern int ospf_area_range_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, int); extern int ospf_area_range_cost_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, u_int32_t); extern int ospf_area_range_unset (struct ospf *, struct in_addr, struct prefix_ipv4 *); extern int ospf_area_range_substitute_set (struct ospf *, struct in_addr, struct prefix_ipv4 *, struct prefix_ipv4 *); extern int ospf_area_range_substitute_unset (struct ospf *, struct in_addr, struct prefix_ipv4 *); extern struct ospf_area_range *ospf_area_range_match_any (struct ospf *, struct prefix_ipv4 *); extern int ospf_area_range_active (struct ospf_area_range *); extern int ospf_act_bb_connection (struct ospf *); extern void ospf_check_abr_status (struct ospf *); extern void ospf_abr_task (struct ospf *); extern void ospf_schedule_abr_task (struct ospf *); extern void ospf_abr_announce_network_to_area (struct prefix_ipv4 *, u_int32_t, struct ospf_area *); #endif /* _ZEBRA_OSPF_ABR_H */ quagga-0.99.24.1/ospfd/ospf_ase.h0000644000175000017500000000333212476520570013320 00000000000000/* * OSPF AS External route calculation. * Copyright (C) 1999, 2000 Alex Zinin, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ASE_H #define _ZEBRA_OSPF_ASE_H extern struct ospf_route *ospf_find_asbr_route (struct ospf *, struct route_table *, struct prefix_ipv4 *); extern struct ospf_route *ospf_find_asbr_route_through_area (struct route_table *, struct prefix_ipv4 *, struct ospf_area *); extern int ospf_ase_calculate_route (struct ospf *, struct ospf_lsa *); extern void ospf_ase_calculate_schedule (struct ospf *); extern void ospf_ase_calculate_timer_add (struct ospf *); extern void ospf_ase_external_lsas_finish (struct route_table *); extern void ospf_ase_incremental_update (struct ospf *, struct ospf_lsa *); extern void ospf_ase_register_external_lsa (struct ospf_lsa *, struct ospf *); extern void ospf_ase_unregister_external_lsa (struct ospf_lsa *, struct ospf *); #endif /* _ZEBRA_OSPF_ASE_H */ quagga-0.99.24.1/ospfd/ospf_route.h0000644000175000017500000001122712476520570013710 00000000000000/* * OSPF routing table. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ROUTE_H #define _ZEBRA_OSPF_ROUTE_H #define OSPF_DESTINATION_ROUTER 1 #define OSPF_DESTINATION_NETWORK 2 #define OSPF_DESTINATION_DISCARD 3 #define OSPF_PATH_MIN 0 #define OSPF_PATH_INTRA_AREA 1 #define OSPF_PATH_INTER_AREA 2 #define OSPF_PATH_TYPE1_EXTERNAL 3 #define OSPF_PATH_TYPE2_EXTERNAL 4 #define OSPF_PATH_MAX 5 /* OSPF Path. */ struct ospf_path { struct in_addr nexthop; struct in_addr adv_router; unsigned int ifindex; }; /* Below is the structure linked to every route node. Note that for Network routing entries a single ospf_route is kept, while for ABRs and ASBRs (Router routing entries), we link an instance of ospf_router_route where a list of paths is maintained, so nr->info is a (struct ospf_route *) for OSPF_DESTINATION_NETWORK but nr->info is a (struct ospf_router_route *) for OSPF_DESTINATION_ROUTER */ struct route_standard { /* Link Sate Origin. */ struct lsa_header *origin; /* Associated Area. */ struct in_addr area_id; /* The area the route belongs to */ /* Area Type */ int external_routing; /* Optional Capability. */ u_char options; /* Get from LSA header. */ /* */ u_char flags; /* From router-LSA */ }; struct route_external { /* Link State Origin. */ struct ospf_lsa *origin; /* Link State Cost Type2. */ u_int32_t type2_cost; /* Tag value. */ u_int32_t tag; /* ASBR route. */ struct ospf_route *asbr; }; struct ospf_route { /* Create time. */ time_t ctime; /* Modified time. */ time_t mtime; /* Destination Type. */ u_char type; /* Destination ID. */ /* i.e. Link State ID. */ struct in_addr id; /* Address Mask. */ struct in_addr mask; /* Only valid for networks. */ /* Path Type. */ u_char path_type; /* List of Paths. */ struct list *paths; /* Link State Cost. */ u_int32_t cost; /* i.e. metric. */ /* Route specific info. */ union { struct route_standard std; struct route_external ext; } u; }; extern struct ospf_path *ospf_path_new (void); extern void ospf_path_free (struct ospf_path *); extern struct ospf_path *ospf_path_lookup (struct list *, struct ospf_path *); extern struct ospf_route *ospf_route_new (void); extern void ospf_route_free (struct ospf_route *); extern void ospf_route_delete (struct route_table *); extern void ospf_route_table_free (struct route_table *); extern void ospf_route_install (struct ospf *, struct route_table *); extern void ospf_route_table_dump (struct route_table *); extern void ospf_intra_add_router (struct route_table *, struct vertex *, struct ospf_area *); extern void ospf_intra_add_transit (struct route_table *, struct vertex *, struct ospf_area *); extern void ospf_intra_add_stub (struct route_table *, struct router_lsa_link *, struct vertex *, struct ospf_area *, int parent_is_root, int); extern int ospf_route_cmp (struct ospf *, struct ospf_route *, struct ospf_route *); extern void ospf_route_copy_nexthops (struct ospf_route *, struct list *); extern void ospf_route_copy_nexthops_from_vertex (struct ospf_route *, struct vertex *); extern void ospf_route_subst (struct route_node *, struct ospf_route *, struct ospf_route *); extern void ospf_route_add (struct route_table *, struct prefix_ipv4 *, struct ospf_route *, struct ospf_route *); extern void ospf_route_subst_nexthops (struct ospf_route *, struct list *); extern void ospf_prune_unreachable_networks (struct route_table *); extern void ospf_prune_unreachable_routers (struct route_table *); extern int ospf_add_discard_route (struct route_table *, struct ospf_area *, struct prefix_ipv4 *); extern void ospf_delete_discard_route (struct route_table *, struct prefix_ipv4 *); extern int ospf_route_match_same (struct route_table *, struct prefix_ipv4 *, struct ospf_route *); #endif /* _ZEBRA_OSPF_ROUTE_H */ quagga-0.99.24.1/ospfd/ospf_spf.h0000644000175000017500000000473612476520570013351 00000000000000/* * OSPF calculation. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_OSPF_SPF_H #define _QUAGGA_OSPF_SPF_H /* values for vertex->type */ #define OSPF_VERTEX_ROUTER 1 /* for a Router-LSA */ #define OSPF_VERTEX_NETWORK 2 /* for a Network-LSA */ /* values for vertex->flags */ #define OSPF_VERTEX_PROCESSED 0x01 /* The "root" is the node running the SPF calculation */ /* A router or network in an area */ struct vertex { u_char flags; u_char type; /* copied from LSA header */ struct in_addr id; /* copied from LSA header */ struct lsa_header *lsa; /* Router or Network LSA */ int *stat; /* Link to LSA status. */ u_int32_t distance; /* from root to this vertex */ struct list *parents; /* list of parents in SPF tree */ struct list *children; /* list of children in SPF tree*/ }; /* A nexthop taken on the root node to get to this (parent) vertex */ struct vertex_nexthop { struct ospf_interface *oi; /* output intf on root node */ struct in_addr router; /* router address to send to */ }; struct vertex_parent { struct vertex_nexthop *nexthop; /* link to nexthop info for this parent */ struct vertex *parent; /* parent vertex */ int backlink; /* index back to parent for router-lsa's */ }; /* What triggered the SPF ? */ typedef enum { SPF_FLAG_ROUTER_LSA_INSTALL = 1, SPF_FLAG_NETWORK_LSA_INSTALL, SPF_FLAG_SUMMARY_LSA_INSTALL, SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL, SPF_FLAG_MAXAGE, SPF_FLAG_ABR_STATUS_CHANGE, SPF_FLAG_ASBR_STATUS_CHANGE, SPF_FLAG_CONFIG_CHANGE, } ospf_spf_reason_t; extern void ospf_spf_calculate_schedule (struct ospf *, ospf_spf_reason_t); extern void ospf_rtrs_free (struct route_table *); /* void ospf_spf_calculate_timer_add (); */ #endif /* _QUAGGA_OSPF_SPF_H */ quagga-0.99.24.1/ospfd/ospf_zebra.h0000644000175000017500000000547712476520570013667 00000000000000/* * Zebra connect library for OSPFd * Copyright (C) 1997, 98, 99, 2000 Kunihiro Ishiguro, Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_ZEBRA_H #define _ZEBRA_OSPF_ZEBRA_H #include "vty.h" #define EXTERNAL_METRIC_TYPE_1 0 #define EXTERNAL_METRIC_TYPE_2 1 #define DEFAULT_ROUTE ZEBRA_ROUTE_MAX #define DEFAULT_ROUTE_TYPE(T) ((T) == DEFAULT_ROUTE) /* OSPF distance. */ struct ospf_distance { /* Distance value for the IP source prefix. */ u_char distance; /* Name of the access-list to be matched. */ char *access_list; }; /* Prototypes */ extern void ospf_zclient_start (void); extern void ospf_zebra_add (struct prefix_ipv4 *, struct ospf_route *); extern void ospf_zebra_delete (struct prefix_ipv4 *, struct ospf_route *); extern void ospf_zebra_add_discard (struct prefix_ipv4 *); extern void ospf_zebra_delete_discard (struct prefix_ipv4 *); extern int ospf_redistribute_check (struct ospf *, struct external_info *, int *); extern int ospf_distribute_check_connected (struct ospf *, struct external_info *); extern void ospf_distribute_list_update (struct ospf *, uintptr_t); extern int ospf_is_type_redistributed (int); extern void ospf_distance_reset (struct ospf *); extern u_char ospf_distance_apply (struct prefix_ipv4 *, struct ospf_route *); extern int ospf_redistribute_set (struct ospf *, int, int, int); extern int ospf_redistribute_unset (struct ospf *, int); extern int ospf_redistribute_default_set (struct ospf *, int, int, int); extern int ospf_redistribute_default_unset (struct ospf *); extern int ospf_distribute_list_out_set (struct ospf *, int, const char *); extern int ospf_distribute_list_out_unset (struct ospf *, int, const char *); extern void ospf_routemap_set (struct ospf *, int, const char *); extern void ospf_routemap_unset (struct ospf *, int); extern int ospf_distance_set (struct vty *, struct ospf *, const char *, const char *, const char *); extern int ospf_distance_unset (struct vty *, struct ospf *, const char *, const char *, const char *); extern void ospf_zebra_init (void); #endif /* _ZEBRA_OSPF_ZEBRA_H */ quagga-0.99.24.1/ospfd/ospf_packet.h0000644000175000017500000001347612476520570014031 00000000000000/* * OSPF Sending and Receiving OSPF Packets. * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_PACKET_H #define _ZEBRA_OSPF_PACKET_H #define OSPF_HEADER_SIZE 24U #define OSPF_AUTH_SIMPLE_SIZE 8U #define OSPF_AUTH_MD5_SIZE 16U #define OSPF_MAX_PACKET_SIZE 65535U /* includes IP Header size. */ #define OSPF_HELLO_MIN_SIZE 20U /* not including neighbors */ #define OSPF_DB_DESC_MIN_SIZE 8U #define OSPF_LS_REQ_MIN_SIZE 0U #define OSPF_LS_UPD_MIN_SIZE 4U #define OSPF_LS_ACK_MIN_SIZE 0U #define OSPF_MSG_HELLO 1 /* OSPF Hello Message. */ #define OSPF_MSG_DB_DESC 2 /* OSPF Database Descriptoin Message. */ #define OSPF_MSG_LS_REQ 3 /* OSPF Link State Request Message. */ #define OSPF_MSG_LS_UPD 4 /* OSPF Link State Update Message. */ #define OSPF_MSG_LS_ACK 5 /* OSPF Link State Acknoledgement Message. */ #define OSPF_SEND_PACKET_DIRECT 1 #define OSPF_SEND_PACKET_INDIRECT 2 #define OSPF_SEND_PACKET_LOOP 3 #define OSPF_HELLO_REPLY_DELAY 1 /* Return values of functions involved in packet verification, see ospf6d. */ #define MSG_OK 0 #define MSG_NG 1 struct ospf_packet { struct ospf_packet *next; /* Pointer to data stream. */ struct stream *s; /* IP destination address. */ struct in_addr dst; /* OSPF packet length. */ u_int16_t length; }; /* OSPF packet queue structure. */ struct ospf_fifo { unsigned long count; struct ospf_packet *head; struct ospf_packet *tail; }; /* OSPF packet header structure. */ struct ospf_header { u_char version; /* OSPF Version. */ u_char type; /* Packet Type. */ u_int16_t length; /* Packet Length. */ struct in_addr router_id; /* Router ID. */ struct in_addr area_id; /* Area ID. */ u_int16_t checksum; /* Check Sum. */ u_int16_t auth_type; /* Authentication Type. */ /* Authentication Data. */ union { /* Simple Authentication. */ u_char auth_data [OSPF_AUTH_SIMPLE_SIZE]; /* Cryptographic Authentication. */ struct { u_int16_t zero; /* Should be 0. */ u_char key_id; /* Key ID. */ u_char auth_data_len; /* Auth Data Length. */ u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ } crypt; } u; }; /* OSPF Hello body format. */ struct ospf_hello { struct in_addr network_mask; u_int16_t hello_interval; u_char options; u_char priority; u_int32_t dead_interval; struct in_addr d_router; struct in_addr bd_router; struct in_addr neighbors[1]; }; /* OSPF Database Description body format. */ struct ospf_db_desc { u_int16_t mtu; u_char options; u_char flags; u_int32_t dd_seqnum; }; struct ospf_ls_update { u_int32_t num_lsas; }; /* Macros. */ /* XXX Perhaps obsolete; function in ospf_packet.c */ #define OSPF_PACKET_MAX(oi) ospf_packet_max (oi) #define OSPF_OUTPUT_PNT(S) ((S)->data + (S)->putp) #define OSPF_OUTPUT_LENGTH(S) ((S)->endp) #define IS_SET_DD_MS(X) ((X) & OSPF_DD_FLAG_MS) #define IS_SET_DD_M(X) ((X) & OSPF_DD_FLAG_M) #define IS_SET_DD_I(X) ((X) & OSPF_DD_FLAG_I) #define IS_SET_DD_ALL(X) ((X) & OSPF_DD_FLAG_ALL) /* Prototypes. */ extern void ospf_output_forward (struct stream *, int); extern struct ospf_packet *ospf_packet_new (size_t); extern void ospf_packet_free (struct ospf_packet *); extern struct ospf_fifo *ospf_fifo_new (void); extern void ospf_fifo_push (struct ospf_fifo *, struct ospf_packet *); extern struct ospf_packet *ospf_fifo_pop (struct ospf_fifo *); extern struct ospf_packet *ospf_fifo_head (struct ospf_fifo *); extern void ospf_fifo_flush (struct ospf_fifo *); extern void ospf_fifo_free (struct ospf_fifo *); extern void ospf_packet_add (struct ospf_interface *, struct ospf_packet *); extern void ospf_packet_delete (struct ospf_interface *); extern struct stream *ospf_stream_dup (struct stream *); extern struct ospf_packet *ospf_packet_dup (struct ospf_packet *); extern int ospf_read (struct thread *); extern void ospf_hello_send (struct ospf_interface *); extern void ospf_db_desc_send (struct ospf_neighbor *); extern void ospf_db_desc_resend (struct ospf_neighbor *); extern void ospf_ls_req_send (struct ospf_neighbor *); extern void ospf_ls_upd_send_lsa (struct ospf_neighbor *, struct ospf_lsa *, int); extern void ospf_ls_upd_send (struct ospf_neighbor *, struct list *, int); extern void ospf_ls_ack_send (struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_ack_send_delayed (struct ospf_interface *); extern void ospf_ls_retransmit (struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event (struct ospf_neighbor *); extern int ospf_ls_upd_timer (struct thread *); extern int ospf_ls_ack_timer (struct thread *); extern int ospf_poll_timer (struct thread *); extern int ospf_hello_reply_timer (struct thread *); extern const struct message ospf_packet_type_str[]; extern const size_t ospf_packet_type_str_max; #endif /* _ZEBRA_OSPF_PACKET_H */ quagga-0.99.24.1/ospfd/ospf_network.h0000644000175000017500000000274512476520570014250 00000000000000/* * OSPF network related functions. * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_NETWORK_H #define _ZEBRA_OSPF_NETWORK_H /* Prototypes. */ extern int ospf_if_add_allspfrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_drop_allspfrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_add_alldrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_drop_alldrouters (struct ospf *, struct prefix *, unsigned int); extern int ospf_if_ipmulticast (struct ospf *, struct prefix *, unsigned int); extern int ospf_sock_init (void); extern void ospf_adjust_sndbuflen (struct ospf *, unsigned int); #endif /* _ZEBRA_OSPF_NETWORK_H */ quagga-0.99.24.1/ospfd/ospf_neighbor.h0000644000175000017500000000774512476520570014361 00000000000000/* * OSPF Neighbor functions. * Copyright (C) 1999, 2000 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_NEIGHBOR_H #define _ZEBRA_OSPF_NEIGHBOR_H #include /* Neighbor Data Structure */ struct ospf_neighbor { /* This neighbor's parent ospf interface. */ struct ospf_interface *oi; /* OSPF neighbor Information */ u_char state; /* NSM status. */ u_char dd_flags; /* DD bit flags. */ u_int32_t dd_seqnum; /* DD Sequence Number. */ /* Neighbor Information from Hello. */ struct prefix address; /* Neighbor Interface Address. */ struct in_addr src; /* Src address. */ struct in_addr router_id; /* Router ID. */ u_char options; /* Options. */ int priority; /* Router Priority. */ struct in_addr d_router; /* Designated Router. */ struct in_addr bd_router; /* Backup Designated Router. */ /* Last sent Database Description packet. */ struct ospf_packet *last_send; /* Timestemp when last Database Description packet was sent */ struct timeval last_send_ts; /* Last received Databse Description packet. */ struct { u_char options; u_char flags; u_int32_t dd_seqnum; } last_recv; /* LSA data. */ struct ospf_lsdb ls_rxmt; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; u_int32_t crypt_seqnum; /* Cryptographic Sequence Number. */ /* Timer values. */ u_int32_t v_inactivity; u_int32_t v_db_desc; u_int32_t v_ls_req; u_int32_t v_ls_upd; /* Threads. */ struct thread *t_inactivity; struct thread *t_db_desc; struct thread *t_ls_req; struct thread *t_ls_upd; struct thread *t_hello_reply; /* NBMA configured neighbour */ struct ospf_nbr_nbma *nbr_nbma; /* Statistics */ struct timeval ts_last_progress; /* last advance of NSM */ struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ u_int32_t state_change; /* NSM state change counter */ }; /* Macros. */ #define NBR_IS_DR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->d_router) #define NBR_IS_BDR(n) IPV4_ADDR_SAME (&n->address.u.prefix4, &n->bd_router) /* Prototypes. */ extern struct ospf_neighbor *ospf_nbr_new (struct ospf_interface *); extern void ospf_nbr_free (struct ospf_neighbor *); extern void ospf_nbr_delete (struct ospf_neighbor *); extern int ospf_nbr_bidirectional (struct in_addr *, struct in_addr *, int); extern void ospf_nbr_add_self (struct ospf_interface *); extern int ospf_nbr_count (struct ospf_interface *, int); #ifdef HAVE_OPAQUE_LSA extern int ospf_nbr_count_opaque_capable (struct ospf_interface *); #endif /* HAVE_OPAQUE_LSA */ extern struct ospf_neighbor *ospf_nbr_get (struct ospf_interface *, struct ospf_header *, struct ip *, struct prefix *); extern struct ospf_neighbor *ospf_nbr_lookup (struct ospf_interface *, struct ip *, struct ospf_header *); extern struct ospf_neighbor *ospf_nbr_lookup_by_addr (struct route_table *, struct in_addr *); extern struct ospf_neighbor *ospf_nbr_lookup_by_routerid (struct route_table *, struct in_addr *); extern void ospf_renegotiate_optional_capabilities (struct ospf *top); #endif /* _ZEBRA_OSPF_NEIGHBOR_H */ quagga-0.99.24.1/ospfd/ospf_interface.h0000644000175000017500000002621512476520570014515 00000000000000/* * OSPF Interface functions. * Copyright (C) 1999 Toshiaki Takada * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef _ZEBRA_OSPF_INTERFACE_H #define _ZEBRA_OSPF_INTERFACE_H #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) #define IF_OIFS(I) (IF_OSPF_IF_INFO (I)->oifs) #define IF_OIFS_PARAMS(I) (IF_OSPF_IF_INFO (I)->params) #define OSPF_IF_PARAM_CONFIGURED(S, P) ((S) && (S)->P##__config) #define OSPF_IF_PARAM(O, P) \ (OSPF_IF_PARAM_CONFIGURED ((O)->params, P)?\ (O)->params->P:IF_DEF_PARAMS((O)->ifp)->P) #define DECLARE_IF_PARAM(T, P) T P; u_char P##__config:1 #define UNSET_IF_PARAM(S, P) ((S)->P##__config) = 0 #define SET_IF_PARAM(S, P) ((S)->P##__config) = 1 struct ospf_if_params { DECLARE_IF_PARAM (u_int32_t, transmit_delay); /* Interface Transmisson Delay */ DECLARE_IF_PARAM (u_int32_t, output_cost_cmd);/* Command Interface Output Cost */ DECLARE_IF_PARAM (u_int32_t, retransmit_interval); /* Retransmission Interval */ DECLARE_IF_PARAM (u_char, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to join multicast groups) */ DECLARE_IF_PARAM (u_char, priority); /* OSPF Interface priority */ DECLARE_IF_PARAM (u_char, type); /* type of interface */ #define OSPF_IF_ACTIVE 0 #define OSPF_IF_PASSIVE 1 #define OSPF_IF_PASSIVE_STATUS(O) \ (OSPF_IF_PARAM_CONFIGURED((O)->params, passive_interface) ? \ (O)->params->passive_interface : \ (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS((O)->ifp), passive_interface) ? \ IF_DEF_PARAMS((O)->ifp)->passive_interface : \ (O)->ospf->passive_interface_default)) DECLARE_IF_PARAM (u_int32_t, v_hello); /* Hello Interval */ DECLARE_IF_PARAM (u_int32_t, v_wait); /* Router Dead Interval */ /* MTU mismatch check (see RFC2328, chap 10.6) */ DECLARE_IF_PARAM (u_char, mtu_ignore); /* Fast-Hellos */ DECLARE_IF_PARAM (u_char, fast_hello); /* Authentication data. */ u_char auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */ u_char auth_simple__config:1; DECLARE_IF_PARAM (struct list *, auth_crypt); /* List of Auth cryptographic data. */ DECLARE_IF_PARAM (int, auth_type); /* OSPF authentication type */ /* Other, non-configuration state */ u_int32_t network_lsa_seqnum; /* Network LSA seqnum */ }; enum { MEMBER_ALLROUTERS = 0, MEMBER_DROUTERS, MEMBER_MAX, }; struct ospf_if_info { struct ospf_if_params *def_params; struct route_table *params; struct route_table *oifs; unsigned int membership_counts[MEMBER_MAX]; /* multicast group refcnts */ }; struct ospf_interface; struct ospf_vl_data { struct in_addr vl_peer; /* Router-ID of the peer for VLs. */ struct in_addr vl_area_id; /* Transit area for this VL. */ int format; /* area ID format */ struct ospf_interface *vl_oi; /* Interface data structure for the VL. */ struct vertex_nexthop nexthop; /* Nexthop router and oi to use */ struct in_addr peer_addr; /* Address used to reach the peer. */ u_char flags; }; #define OSPF_VL_MAX_COUNT 256 #define OSPF_VL_MTU 1500 #define OSPF_VL_FLAG_APPROVED 0x01 struct crypt_key { u_char key_id; u_char auth_key[OSPF_AUTH_MD5_SIZE + 1]; }; /* OSPF interface structure. */ struct ospf_interface { /* This interface's parent ospf instance. */ struct ospf *ospf; /* OSPF Area. */ struct ospf_area *area; /* Position range in Router LSA */ uint16_t lsa_pos_beg; /* inclusive, >= */ uint16_t lsa_pos_end; /* exclusive, < */ /* Interface data from zebra. */ struct interface *ifp; struct ospf_vl_data *vl_data; /* Data for Virtual Link */ /* Packet send buffer. */ struct ospf_fifo *obuf; /* Output queue */ /* OSPF Network Type. */ u_char type; /* State of Interface State Machine. */ u_char state; /* To which multicast groups do we currently belong? */ u_char multicast_memberships; #define OI_MEMBER_FLAG(M) (1 << (M)) #define OI_MEMBER_COUNT(O,M) (IF_OSPF_IF_INFO(oi->ifp)->membership_counts[(M)]) #define OI_MEMBER_CHECK(O,M) \ (CHECK_FLAG((O)->multicast_memberships, OI_MEMBER_FLAG(M))) #define OI_MEMBER_JOINED(O,M) \ do { \ SET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \ IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]++; \ } while (0) #define OI_MEMBER_LEFT(O,M) \ do { \ UNSET_FLAG ((O)->multicast_memberships, OI_MEMBER_FLAG(M)); \ IF_OSPF_IF_INFO((O)->ifp)->membership_counts[(M)]--; \ } while (0) struct prefix *address; /* Interface prefix */ struct connected *connected; /* Pointer to connected */ /* Configured varables. */ struct ospf_if_params *params; u_int32_t crypt_seqnum; /* Cryptographic Sequence Number */ u_int32_t output_cost; /* Acutual Interface Output Cost */ /* Neighbor information. */ struct route_table *nbrs; /* OSPF Neighbor List */ struct ospf_neighbor *nbr_self; /* Neighbor Self */ #define DR(I) ((I)->nbr_self->d_router) #define BDR(I) ((I)->nbr_self->bd_router) #define OPTIONS(I) ((I)->nbr_self->options) #define PRIORITY(I) ((I)->nbr_self->priority) /* List of configured NBMA neighbor. */ struct list *nbr_nbma; /* self-originated LSAs. */ struct ospf_lsa *network_lsa_self; /* network-LSA. */ #ifdef HAVE_OPAQUE_LSA struct list *opaque_lsa_self; /* Type-9 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ struct route_table *ls_upd_queue; struct list *ls_ack; /* Link State Acknowledgment list. */ struct { struct list *ls_ack; struct in_addr dst; } ls_ack_direct; /* Timer values. */ u_int32_t v_ls_ack; /* Delayed Link State Acknowledgment */ /* Threads. */ struct thread *t_hello; /* timer */ struct thread *t_wait; /* timer */ struct thread *t_ls_ack; /* timer */ struct thread *t_ls_ack_direct; /* event */ struct thread *t_ls_upd_event; /* event */ #ifdef HAVE_OPAQUE_LSA struct thread *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ #endif /* HAVE_OPAQUE_LSA */ int on_write_q; /* Statistics fields. */ u_int32_t hello_in; /* Hello message input count. */ u_int32_t hello_out; /* Hello message output count. */ u_int32_t db_desc_in; /* database desc. message input count. */ u_int32_t db_desc_out; /* database desc. message output count. */ u_int32_t ls_req_in; /* LS request message input count. */ u_int32_t ls_req_out; /* LS request message output count. */ u_int32_t ls_upd_in; /* LS update message input count. */ u_int32_t ls_upd_out; /* LS update message output count. */ u_int32_t ls_ack_in; /* LS Ack message input count. */ u_int32_t ls_ack_out; /* LS Ack message output count. */ u_int32_t discarded; /* discarded input count by error. */ u_int32_t state_change; /* Number of status change. */ u_int32_t full_nbrs; }; /* Prototypes. */ extern char *ospf_if_name (struct ospf_interface *); extern struct ospf_interface *ospf_if_new (struct ospf *, struct interface *, struct prefix *); extern void ospf_if_cleanup (struct ospf_interface *); extern void ospf_if_free (struct ospf_interface *); extern int ospf_if_up (struct ospf_interface *); extern int ospf_if_down (struct ospf_interface *); extern int ospf_if_is_up (struct ospf_interface *); extern struct ospf_interface *ospf_if_exists (struct ospf_interface *); extern struct ospf_interface *ospf_if_lookup_by_lsa_pos (struct ospf_area *, int); extern struct ospf_interface *ospf_if_lookup_by_local_addr (struct ospf *, struct interface *, struct in_addr); extern struct ospf_interface *ospf_if_lookup_by_prefix (struct ospf *, struct prefix_ipv4 *); extern struct ospf_interface *ospf_if_table_lookup (struct interface *, struct prefix *); extern struct ospf_interface *ospf_if_addr_local (struct in_addr); extern struct ospf_interface *ospf_if_lookup_recv_if (struct ospf *, struct in_addr, struct interface *); extern struct ospf_interface *ospf_if_is_configured (struct ospf *, struct in_addr *); extern struct ospf_if_params *ospf_lookup_if_params (struct interface *, struct in_addr); extern struct ospf_if_params *ospf_get_if_params (struct interface *, struct in_addr); extern void ospf_del_if_params (struct ospf_if_params *); extern void ospf_free_if_params (struct interface *, struct in_addr); extern void ospf_if_update_params (struct interface *, struct in_addr); extern int ospf_if_new_hook (struct interface *); extern void ospf_if_init (void); extern void ospf_if_stream_set (struct ospf_interface *); extern void ospf_if_stream_unset (struct ospf_interface *); extern void ospf_if_reset_variables (struct ospf_interface *); extern int ospf_if_is_enable (struct ospf_interface *); extern int ospf_if_get_output_cost (struct ospf_interface *); extern void ospf_if_recalculate_output_cost (struct interface *); /* Simulate down/up on the interface. */ extern void ospf_if_reset (struct interface *); extern struct ospf_interface *ospf_vl_new (struct ospf *, struct ospf_vl_data *); extern struct ospf_vl_data *ospf_vl_data_new (struct ospf_area *, struct in_addr); extern struct ospf_vl_data *ospf_vl_lookup (struct ospf *, struct ospf_area *, struct in_addr); extern void ospf_vl_data_free (struct ospf_vl_data *); extern void ospf_vl_add (struct ospf *, struct ospf_vl_data *); extern void ospf_vl_delete (struct ospf *, struct ospf_vl_data *); extern void ospf_vl_up_check (struct ospf_area *, struct in_addr, struct vertex *); extern void ospf_vl_unapprove (struct ospf *); extern void ospf_vl_shut_unapproved (struct ospf *); extern int ospf_full_virtual_nbrs (struct ospf_area *); extern int ospf_vls_in_area (struct ospf_area *); extern struct crypt_key *ospf_crypt_key_lookup (struct list *, u_char); extern struct crypt_key *ospf_crypt_key_new (void); extern void ospf_crypt_key_add (struct list *, struct crypt_key *); extern int ospf_crypt_key_delete (struct list *, u_char); extern u_char ospf_default_iftype (struct interface *ifp); /* Set all multicast memberships appropriately based on the type and state of the interface. */ extern void ospf_if_set_multicast (struct ospf_interface *); #endif /* _ZEBRA_OSPF_INTERFACE_H */ quagga-0.99.24.1/ospfd/ospfd.conf.sample0000644000175000017500000000026612476520570014615 00000000000000! -*- ospf -*- ! ! OSPFd sample configuration file ! ! hostname ospfd password zebra !enable password please-set-at-here ! !router ospf ! network 192.168.1.0/24 area 0 ! log stdout quagga-0.99.24.1/ospfd/Makefile.am0000644000175000017500000000240212476520570013401 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 sbin_PROGRAMS = ospfd libospf_la_SOURCES = \ ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ ospf_opaque.c ospf_te.c ospf_vty.c ospf_api.c ospf_apiserver.c ospfdheaderdir = $(pkgincludedir)/ospfd ospfdheader_HEADERS = \ ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ ospf_flood.h ospf_snmp.h ospf_te.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt examplesdir = $(exampledir) dist_examples_DATA = ospfd.conf.sample quagga-0.99.24.1/ospfd/Makefile.in0000644000175000017500000007107412476521251013422 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ospfd$(EXEEXT) subdir = ospfd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) \ $(ospfdheader_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(examplesdir)" "$(DESTDIR)$(ospfdheaderdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libospf_la_LIBADD = am_libospf_la_OBJECTS = ospfd.lo ospf_zebra.lo ospf_interface.lo \ ospf_ism.lo ospf_neighbor.lo ospf_nsm.lo ospf_dump.lo \ ospf_network.lo ospf_packet.lo ospf_lsa.lo ospf_spf.lo \ ospf_route.lo ospf_ase.lo ospf_abr.lo ospf_ia.lo ospf_flood.lo \ ospf_lsdb.lo ospf_asbr.lo ospf_routemap.lo ospf_snmp.lo \ ospf_opaque.lo ospf_te.lo ospf_vty.lo ospf_api.lo \ ospf_apiserver.lo libospf_la_OBJECTS = $(am_libospf_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libospf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libospf_la_LDFLAGS) $(LDFLAGS) -o $@ PROGRAMS = $(sbin_PROGRAMS) am_ospfd_OBJECTS = ospf_main.$(OBJEXT) ospfd_OBJECTS = $(am_ospfd_OBJECTS) ospfd_DEPENDENCIES = libospf.la ../lib/libzebra.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libospf_la_SOURCES) $(ospfd_SOURCES) DIST_SOURCES = $(libospf_la_SOURCES) $(ospfd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) $(ospfdheader_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 lib_LTLIBRARIES = libospf.la libospf_la_LDFLAGS = -version-info 0:0:0 libospf_la_SOURCES = \ ospfd.c ospf_zebra.c ospf_interface.c ospf_ism.c ospf_neighbor.c \ ospf_nsm.c ospf_dump.c ospf_network.c ospf_packet.c ospf_lsa.c \ ospf_spf.c ospf_route.c ospf_ase.c ospf_abr.c ospf_ia.c ospf_flood.c \ ospf_lsdb.c ospf_asbr.c ospf_routemap.c ospf_snmp.c \ ospf_opaque.c ospf_te.c ospf_vty.c ospf_api.c ospf_apiserver.c ospfdheaderdir = $(pkgincludedir)/ospfd ospfdheader_HEADERS = \ ospf_api.h ospf_asbr.h ospf_dump.h ospf_lsa.h ospf_lsdb.h \ ospf_nsm.h ospf_ism.h ospf_opaque.h ospfd.h noinst_HEADERS = \ ospf_interface.h ospf_neighbor.h ospf_network.h ospf_packet.h \ ospf_zebra.h ospf_spf.h ospf_route.h ospf_ase.h ospf_abr.h ospf_ia.h \ ospf_flood.h ospf_snmp.h ospf_te.h ospf_vty.h ospf_apiserver.h ospfd_SOURCES = ospf_main.c ospfd_LDADD = libospf.la ../lib/libzebra.la @LIBCAP@ EXTRA_DIST = OSPF-MIB.txt OSPF-TRAP-MIB.txt ChangeLog.opaque.txt examplesdir = $(exampledir) dist_examples_DATA = ospfd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ospfd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ospfd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libospf.la: $(libospf_la_OBJECTS) $(libospf_la_DEPENDENCIES) $(EXTRA_libospf_la_DEPENDENCIES) $(AM_V_CCLD)$(libospf_la_LINK) -rpath $(libdir) $(libospf_la_OBJECTS) $(libospf_la_LIBADD) $(LIBS) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ospfd$(EXEEXT): $(ospfd_OBJECTS) $(ospfd_DEPENDENCIES) $(EXTRA_ospfd_DEPENDENCIES) @rm -f ospfd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ospfd_OBJECTS) $(ospfd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_abr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_api.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_apiserver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_asbr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ase.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_dump.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_flood.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ia.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_ism.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_lsdb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_neighbor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_network.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_nsm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_opaque.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_packet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_route.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_routemap.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_snmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_spf.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_te.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_vty.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospf_zebra.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ospfd.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) install-ospfdheaderHEADERS: $(ospfdheader_HEADERS) @$(NORMAL_INSTALL) @list='$(ospfdheader_HEADERS)'; test -n "$(ospfdheaderdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(ospfdheaderdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(ospfdheaderdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(ospfdheaderdir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(ospfdheaderdir)" || exit $$?; \ done uninstall-ospfdheaderHEADERS: @$(NORMAL_UNINSTALL) @list='$(ospfdheader_HEADERS)'; test -n "$(ospfdheaderdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(ospfdheaderdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" "$(DESTDIR)$(ospfdheaderdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-ospfdheaderHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-libLTLIBRARIES \ uninstall-ospfdheaderHEADERS uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-libLTLIBRARIES install-man install-ospfdheaderHEADERS \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-libLTLIBRARIES \ uninstall-ospfdheaderHEADERS uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/ripngd/0000755000175000017500000000000012476521355011601 500000000000000quagga-0.99.24.1/ripngd/ripng_main.c0000644000175000017500000001550212476520570014011 00000000000000/* * RIPngd main routine. * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "vector.h" #include "vty.h" #include "command.h" #include "memory.h" #include "thread.h" #include "log.h" #include "prefix.h" #include "if.h" #include "privs.h" #include "sigevent.h" #include "ripngd/ripngd.h" /* Configuration filename and directory. */ char config_default[] = SYSCONFDIR RIPNG_DEFAULT_CONFIG; char *config_file = NULL; /* RIPngd options. */ struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* ripngd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ripngd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* RIPngd program name */ /* Route retain mode flag. */ int retain_mode = 0; /* RIPng VTY bind address. */ char *vty_addr = NULL; /* RIPng VTY connection port. */ int vty_port = RIPNG_VTY_PORT; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_RIPNGD_PID; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages RIPng.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by ripngd.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); ripng_clean (); ripng_reset (); /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) ripng_clean (); exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t ripng_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* RIPngd main routine. */ int main (int argc, char **argv) { char *p; int vty_port = RIPNG_VTY_PORT; int daemon_mode = 0; char *progname; struct thread thread; int dryrun = 0; /* Set umask before anything for security */ umask (0027); /* get program name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog(progname, ZLOG_RIPNG, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:vC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ripngd not listening on ripngd port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIPNG_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'u': ripngd_privs.user = optarg; break; case 'g': ripngd_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } master = thread_master_create (); /* Library inits. */ zprivs_init (&ripngd_privs); signal_init (master, array_size(ripng_signals), ripng_signals); cmd_init (1); vty_init (master); memory_init (); /* RIPngd inits. */ ripng_init (); zebra_init (); ripng_peer_init (); /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return(0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("RIPNGd daemon failed: %s", strerror(errno)); exit (1); } /* Create VTY socket */ vty_serv_sock (vty_addr, vty_port, RIPNG_VTYSH_PATH); /* Process id file create. */ pid_output (pid_file); /* Print banner. */ zlog_notice ("RIPNGd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Fetch next active thread. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return 0; } quagga-0.99.24.1/ripngd/ripng_nexthop.c0000644000175000017500000001335112476520570014552 00000000000000/* RIPngd Zebra * Copyright (C) 2002 6WIND * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* This file is required in order to support properly the RIPng nexthop * feature. */ #include /* For struct udphdr. */ #include #include "linklist.h" #include "stream.h" #include "log.h" #include "memory.h" #include "vty.h" #include "if.h" #include "prefix.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" #define DEBUG 1 #define min(a, b) ((a) < (b) ? (a) : (b)) struct ripng_rte_data { struct prefix_ipv6 *p; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; }; void _ripng_rte_del(struct ripng_rte_data *A); int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B); #define METRIC_OUT(a) \ ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out) #define NEXTHOP_OUT_PTR(a) \ ((a)->rinfo ? &((a)->rinfo->nexthop_out) : &((a)->aggregate->nexthop_out)) #define TAG_OUT(a) \ ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) struct list * ripng_rte_new(void) { struct list *rte; rte = list_new(); rte->cmp = (int (*)(void *, void *)) _ripng_rte_cmp; rte->del = (void (*)(void *)) _ripng_rte_del; return rte; } void ripng_rte_free(struct list *ripng_rte_list) { list_delete(ripng_rte_list); } /* Delete RTE */ void _ripng_rte_del(struct ripng_rte_data *A) { XFREE(MTYPE_RIPNG_RTE_DATA, A); } /* Compare RTE: * return + if A > B * 0 if A = B * - if A < B */ int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) { return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); } /* Add routing table entry */ void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, struct ripng_info *rinfo, struct ripng_aggregate *aggregate) { struct ripng_rte_data *data; /* At least one should not be null */ assert(!rinfo || !aggregate); data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data)); data->p = p; data->rinfo = rinfo; data->aggregate = aggregate; listnode_add_sort(ripng_rte_list, data); } /* Send the RTE with the nexthop support */ void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, struct sockaddr_in6 *to) { struct ripng_rte_data *data; struct listnode *node, *nnode; struct in6_addr last_nexthop; struct in6_addr myself_nexthop; struct stream *s; int num; int mtu; int rtemax; int ret; /* Most of the time, there is no nexthop */ memset(&last_nexthop, 0, sizeof(last_nexthop)); /* Use myself_nexthop if the nexthop is not a link-local address, because * we remain a right path without beeing the optimal one. */ memset(&myself_nexthop, 0, sizeof(myself_nexthop)); /* Output stream get from ripng structre. XXX this should be interface structure. */ s = ripng->obuf; /* Reset stream and RTE counter. */ stream_reset (s); num = 0; mtu = ifp->mtu6; if (mtu < 0) mtu = IFMINMTU; rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN - sizeof (struct udphdr) - sizeof (struct ripng_packet) + sizeof (struct rte)) / sizeof (struct rte); for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) { /* (2.1) Next hop support */ if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { /* A nexthop entry should be at least followed by 1 RTE */ if (num == (rtemax-1)) { ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), to, ifp); if (ret >= 0 && IS_RIPNG_DEBUG_SEND) ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s), stream_get_endp(s), "SEND"); num = 0; stream_reset (s); } /* Add the nexthop (2.1) */ /* If the received next hop address is not a link-local address, * it should be treated as 0:0:0:0:0:0:0:0. */ if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) last_nexthop = myself_nexthop; else last_nexthop = *NEXTHOP_OUT_PTR(data); num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); } else { /* Rewrite the nexthop for each new packet */ if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); } num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data), METRIC_OUT(data)); if (num == rtemax) { ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), to, ifp); if (ret >= 0 && IS_RIPNG_DEBUG_SEND) ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s), stream_get_endp(s), "SEND"); num = 0; stream_reset (s); } } /* If unwritten RTE exist, flush it. */ if (num != 0) { ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), to, ifp); if (ret >= 0 && IS_RIPNG_DEBUG_SEND) ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), stream_get_endp (s), "SEND"); stream_reset (s); } } quagga-0.99.24.1/ripngd/ripng_peer.c0000644000175000017500000001161212476520570014016 00000000000000/* RIPng peer support * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* RIPng support added by Vincent Jardin * Copyright (C) 2002 6WIND */ #include #include "if.h" #include "prefix.h" #include "command.h" #include "linklist.h" #include "thread.h" #include "memory.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" /* Linked list of RIPng peer. */ struct list *peer_list; static struct ripng_peer * ripng_peer_new (void) { return XCALLOC (MTYPE_RIPNG_PEER, sizeof (struct ripng_peer)); } static void ripng_peer_free (struct ripng_peer *peer) { XFREE (MTYPE_RIPNG_PEER, peer); } struct ripng_peer * ripng_peer_lookup (struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (IPV6_ADDR_SAME (&peer->addr, addr)) return peer; } return NULL; } struct ripng_peer * ripng_peer_lookup_next (struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (addr6_cmp(&peer->addr, addr) > 0) return peer; } return NULL; } /* RIPng peer is timeout. * Garbage collector. **/ static int ripng_peer_timeout (struct thread *t) { struct ripng_peer *peer; peer = THREAD_ARG (t); listnode_delete (peer_list, peer); ripng_peer_free (peer); return 0; } /* Get RIPng peer. At the same time update timeout thread. */ static struct ripng_peer * ripng_peer_get (struct in6_addr *addr) { struct ripng_peer *peer; peer = ripng_peer_lookup (addr); if (peer) { if (peer->t_timeout) thread_cancel (peer->t_timeout); } else { peer = ripng_peer_new (); peer->addr = *addr; /* XXX */ listnode_add_sort (peer_list, peer); } /* Update timeout thread. */ peer->t_timeout = thread_add_timer (master, ripng_peer_timeout, peer, RIPNG_PEER_TIMER_DEFAULT); /* Last update time set. */ time (&peer->uptime); return peer; } void ripng_peer_update (struct sockaddr_in6 *from, u_char version) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->version = version; } void ripng_peer_bad_route (struct sockaddr_in6 *from) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->recv_badroutes++; } void ripng_peer_bad_packet (struct sockaddr_in6 *from) { struct ripng_peer *peer; peer = ripng_peer_get (&from->sin6_addr); peer->recv_badpackets++; } /* Display peer uptime. */ static char * ripng_peer_uptime (struct ripng_peer *peer, char *buf, size_t len) { time_t uptime; struct tm *tm; /* If there is no connection has been done before print `never'. */ if (peer->uptime == 0) { snprintf (buf, len, "never "); return buf; } /* Get current time. */ uptime = time (NULL); uptime -= peer->uptime; tm = gmtime (&uptime); /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (uptime < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } void ripng_peer_display (struct vty *vty) { struct ripng_peer *peer; struct listnode *node, *nnode; #define RIPNG_UPTIME_LEN 25 char timebuf[RIPNG_UPTIME_LEN]; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { vty_out (vty, " %s %s%14s %10d %10d %10d %s%s", inet6_ntoa (peer->addr), VTY_NEWLINE, " ", peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIPNG_DISTANCE_DEFAULT, ripng_peer_uptime (peer, timebuf, RIPNG_UPTIME_LEN), VTY_NEWLINE); } } static int ripng_peer_list_cmp (struct ripng_peer *p1, struct ripng_peer *p2) { return addr6_cmp(&p1->addr, &p2->addr) > 0; } void ripng_peer_init () { peer_list = list_new (); peer_list->cmp = (int (*)(void *, void *)) ripng_peer_list_cmp; } quagga-0.99.24.1/ripngd/ripng_offset.c0000644000175000017500000002601712476520570014356 00000000000000/* RIPng offset-list * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* RIPng support by Vincent Jardin * Copyright (C) 2002 6WIND */ #include #include "if.h" #include "prefix.h" #include "filter.h" #include "command.h" #include "linklist.h" #include "memory.h" #include "ripngd/ripngd.h" #define RIPNG_OFFSET_LIST_IN 0 #define RIPNG_OFFSET_LIST_OUT 1 #define RIPNG_OFFSET_LIST_MAX 2 struct ripng_offset_list { char *ifname; struct { char *alist_name; /* struct access_list *alist; */ int metric; } direct[RIPNG_OFFSET_LIST_MAX]; }; static struct list *ripng_offset_list_master; static int strcmp_safe (const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 0; if (s1 == NULL) return -1; if (s2 == NULL) return 1; return strcmp (s1, s2); } static struct ripng_offset_list * ripng_offset_list_new () { struct ripng_offset_list *new; new = XCALLOC (MTYPE_RIPNG_OFFSET_LIST, sizeof (struct ripng_offset_list)); return new; } static void ripng_offset_list_free (struct ripng_offset_list *offset) { XFREE (MTYPE_RIPNG_OFFSET_LIST, offset); } static struct ripng_offset_list * ripng_offset_list_lookup (const char *ifname) { struct ripng_offset_list *offset; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (ripng_offset_list_master, node, nnode, offset)) { if (strcmp_safe (offset->ifname, ifname) == 0) return offset; } return NULL; } static struct ripng_offset_list * ripng_offset_list_get (const char *ifname) { struct ripng_offset_list *offset; offset = ripng_offset_list_lookup (ifname); if (offset) return offset; offset = ripng_offset_list_new (); if (ifname) offset->ifname = strdup (ifname); listnode_add_sort (ripng_offset_list_master, offset); return offset; } static int ripng_offset_list_set (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct ripng_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIPNG_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIPNG_OFFSET_LIST_OUT; else { vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); return CMD_WARNING; } /* Check metric. */ metric = atoi (metric_str); if (metric < 0 || metric > 16) { vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); return CMD_WARNING; } /* Get offset-list structure with interface name. */ offset = ripng_offset_list_get (ifname); if (offset->direct[direct].alist_name) free (offset->direct[direct].alist_name); offset->direct[direct].alist_name = strdup (alist); offset->direct[direct].metric = metric; return CMD_SUCCESS; } static int ripng_offset_list_unset (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct ripng_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIPNG_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIPNG_OFFSET_LIST_OUT; else { vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); return CMD_WARNING; } /* Check metric. */ metric = atoi (metric_str); if (metric < 0 || metric > 16) { vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); return CMD_WARNING; } /* Get offset-list structure with interface name. */ offset = ripng_offset_list_lookup (ifname); if (offset) { if (offset->direct[direct].alist_name) free (offset->direct[direct].alist_name); offset->direct[direct].alist_name = NULL; if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name == NULL && offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name == NULL) { listnode_delete (ripng_offset_list_master, offset); if (offset->ifname) free (offset->ifname); ripng_offset_list_free (offset); } } else { vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) #define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name) #define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric) /* If metric is modifed return 1. */ int ripng_offset_list_apply_in (struct prefix_ipv6 *p, struct interface *ifp, u_char *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = ripng_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP6, OFFSET_LIST_IN_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_IN_METRIC (offset); return 1; } return 0; } /* Look up offset-list without interface name. */ offset = ripng_offset_list_lookup (NULL); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP6, OFFSET_LIST_IN_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_IN_METRIC (offset); return 1; } return 0; } return 0; } /* If metric is modifed return 1. */ int ripng_offset_list_apply_out (struct prefix_ipv6 *p, struct interface *ifp, u_char *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = ripng_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP6, OFFSET_LIST_OUT_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_OUT_METRIC (offset); return 1; } return 0; } /* Look up offset-list without interface name. */ offset = ripng_offset_list_lookup (NULL); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP6, OFFSET_LIST_OUT_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_OUT_METRIC (offset); return 1; } return 0; } return 0; } DEFUN (ripng_offset_list, ripng_offset_list_cmd, "offset-list WORD (in|out) <0-16>", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (ripng_offset_list_ifname, ripng_offset_list_ifname_cmd, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return ripng_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); } DEFUN (no_ripng_offset_list, no_ripng_offset_list_cmd, "no offset-list WORD (in|out) <0-16>", NO_STR "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (no_ripng_offset_list_ifname, no_ripng_offset_list_ifname_cmd, "no offset-list WORD (in|out) <0-16> IFNAME", NO_STR "Modify RIPng metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return ripng_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); } static int offset_list_cmp (struct ripng_offset_list *o1, struct ripng_offset_list *o2) { return strcmp_safe (o1->ifname, o2->ifname); } static void offset_list_del (struct ripng_offset_list *offset) { if (OFFSET_LIST_IN_NAME (offset)) free (OFFSET_LIST_IN_NAME (offset)); if (OFFSET_LIST_OUT_NAME (offset)) free (OFFSET_LIST_OUT_NAME (offset)); if (offset->ifname) free (offset->ifname); ripng_offset_list_free (offset); } void ripng_offset_init (void) { ripng_offset_list_master = list_new (); ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; ripng_offset_list_master->del = (void (*)(void *)) offset_list_del; install_element (RIPNG_NODE, &ripng_offset_list_cmd); install_element (RIPNG_NODE, &ripng_offset_list_ifname_cmd); install_element (RIPNG_NODE, &no_ripng_offset_list_cmd); install_element (RIPNG_NODE, &no_ripng_offset_list_ifname_cmd); } void ripng_offset_clean (void) { list_delete (ripng_offset_list_master); ripng_offset_list_master = list_new (); ripng_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; ripng_offset_list_master->del = (void (*)(void *)) offset_list_del; } int config_write_ripng_offset_list (struct vty *vty) { struct listnode *node, *nnode; struct ripng_offset_list *offset; for (ALL_LIST_ELEMENTS (ripng_offset_list_master, node, nnode, offset)) { if (! offset->ifname) { if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d%s", offset->direct[RIPNG_OFFSET_LIST_IN].alist_name, offset->direct[RIPNG_OFFSET_LIST_IN].metric, VTY_NEWLINE); if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d%s", offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name, offset->direct[RIPNG_OFFSET_LIST_OUT].metric, VTY_NEWLINE); } else { if (offset->direct[RIPNG_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d %s%s", offset->direct[RIPNG_OFFSET_LIST_IN].alist_name, offset->direct[RIPNG_OFFSET_LIST_IN].metric, offset->ifname, VTY_NEWLINE); if (offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d %s%s", offset->direct[RIPNG_OFFSET_LIST_OUT].alist_name, offset->direct[RIPNG_OFFSET_LIST_OUT].metric, offset->ifname, VTY_NEWLINE); } } return 0; } quagga-0.99.24.1/ripngd/ripng_routemap.c0000644000175000017500000004162512476520570014726 00000000000000/* RIPng routemap. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "memory.h" #include "prefix.h" #include "routemap.h" #include "command.h" #include "sockunion.h" #include "ripngd/ripngd.h" struct rip_metric_modifier { enum { metric_increment, metric_decrement, metric_absolute } type; u_char metric; }; static int ripng_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } static int ripng_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric; struct ripng_info *rinfo; if (type == RMAP_RIPNG) { metric = rule; rinfo = object; if (rinfo->metric == *metric) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match metric' match statement. `arg' is METRIC value */ static void * route_match_metric_compile (const char *arg) { u_int32_t *metric; metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); *metric = atoi (arg); if(*metric > 0) return metric; XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); return NULL; } /* Free route map's compiled `match metric' value. */ static void route_match_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ static struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, route_match_metric_compile, route_match_metric_free }; /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct ripng_info *rinfo; struct interface *ifp; char *ifname; if (type == RMAP_RIPNG) { ifname = rule; ifp = if_lookup_by_name(ifname); if (!ifp) return RMAP_NOMATCH; rinfo = object; if (rinfo->ifindex == ifp->ifindex) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match interface' match statement. `arg' is IFNAME value */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_interface_cmd = { "interface", route_match_interface, route_match_interface_compile, route_match_interface_free }; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_short *tag; struct ripng_info *rinfo; if (type == RMAP_RIPNG) { tag = rule; rinfo = object; /* The information stored by rinfo is host ordered. */ if (rinfo->tag == *tag) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match tag' match statement. `arg' is TAG value */ static void * route_match_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `match tag' value. */ static void route_match_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag matching. */ static struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_match_tag_compile, route_match_tag_free }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { if (type == RMAP_RIPNG) { struct rip_metric_modifier *mod; struct ripng_info *rinfo; mod = rule; rinfo = object; if (mod->type == metric_increment) rinfo->metric_out += mod->metric; else if (mod->type == metric_decrement) rinfo->metric_out-= mod->metric; else if (mod->type == metric_absolute) rinfo->metric_out = mod->metric; if (rinfo->metric_out < 1) rinfo->metric_out = 1; if (rinfo->metric_out > RIPNG_METRIC_INFINITY) rinfo->metric_out = RIPNG_METRIC_INFINITY; rinfo->metric_set = 1; } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { int len; const char *pnt; int type; long metric; char *endptr = NULL; struct rip_metric_modifier *mod; len = strlen (arg); pnt = arg; if (len == 0) return NULL; /* Examine first character. */ if (arg[0] == '+') { type = metric_increment; pnt++; } else if (arg[0] == '-') { type = metric_decrement; pnt++; } else type = metric_absolute; /* Check beginning with digit string. */ if (*pnt < '0' || *pnt > '9') return NULL; /* Convert string to integer. */ metric = strtol (pnt, &endptr, 10); if (metric == LONG_MAX || *endptr != '\0') return NULL; /* Commented out by Hasso Tepper, to avoid problems in vtysh. */ /* if (metric < 0 || metric > RIPNG_METRIC_INFINITY) */ if (metric < 0) return NULL; mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rip_metric_modifier)); mod->type = type; mod->metric = metric; return mod; } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free, }; /* `set ipv6 next-hop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr *address; struct ripng_info *rinfo; if(type == RMAP_RIPNG) { /* Fetch routemap's rule information. */ address = rule; rinfo = object; /* Set next hop value. */ rinfo->nexthop_out = *address; } return RMAP_OKAY; } /* Route map `ipv6 nexthop local' compile function. Given string is converted to struct in6_addr structure. */ static void * route_set_ipv6_nexthop_local_compile (const char *arg) { int ret; struct in6_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); ret = inet_pton (AF_INET6, arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } /* Free route map's compiled `ipv6 nexthop local' value. */ static void route_set_ipv6_nexthop_local_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ipv6 nexthop local set. */ static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { "ipv6 next-hop local", route_set_ipv6_nexthop_local, route_set_ipv6_nexthop_local_compile, route_set_ipv6_nexthop_local_free }; /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_short *tag; struct ripng_info *rinfo; if(type == RMAP_RIPNG) { /* Fetch routemap's rule information. */ tag = rule; rinfo = object; /* Set next hop value. */ rinfo->tag_out = *tag; } return RMAP_OKAY; } /* Route map `tag' compile function. Given string is converted to u_short. */ static void * route_set_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_set_tag_compile, route_set_tag_free }; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" DEFUN (match_metric, match_metric_cmd, "match metric <0-4294967295>", MATCH_STR "Match metric of route\n" "Metric value\n") { return ripng_route_match_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_match_metric, no_match_metric_cmd, "no match metric", NO_STR MATCH_STR "Match metric of route\n") { if (argc == 0) return ripng_route_match_delete (vty, vty->index, "metric", NULL); return ripng_route_match_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_match_metric, no_match_metric_val_cmd, "no match metric <0-4294967295>", NO_STR MATCH_STR "Match metric of route\n" "Metric value\n") DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return ripng_route_match_add (vty, vty->index, "interface", argv[0]); } DEFUN (no_match_interface, no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { if (argc == 0) return ripng_route_match_delete (vty, vty->index, "interface", NULL); return ripng_route_match_delete (vty, vty->index, "interface", argv[0]); } ALIAS (no_match_interface, no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") DEFUN (match_tag, match_tag_cmd, "match tag <0-65535>", MATCH_STR "Match tag of route\n" "Metric value\n") { return ripng_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return ripng_route_match_delete (vty, vty->index, "tag", NULL); return ripng_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <0-65535>", NO_STR MATCH_STR "Match tag of route\n" "Metric value\n") /* set functions */ DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", "Set value\n" "Metric value for destination routing protocol\n" "Metric value\n") { return ripng_route_set_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric value for destination routing protocol\n") { if (argc == 0) return ripng_route_set_delete (vty, vty->index, "metric", NULL); return ripng_route_set_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_set_metric, no_set_metric_val_cmd, "no set metric <0-4294967295>", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n") DEFUN (set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, "set ipv6 next-hop local X:X::X:X", SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") { union sockunion su; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed next-hop local address%s", VTY_NEWLINE); return CMD_WARNING; } return ripng_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); } DEFUN (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, "no set ipv6 next-hop local", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n") { if (argc == 0) return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); return ripng_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); } ALIAS (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_val_cmd, "no set ipv6 next-hop local X:X::X:X", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") DEFUN (set_tag, set_tag_cmd, "set tag <0-65535>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return ripng_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) return ripng_route_set_delete (vty, vty->index, "tag", NULL); return ripng_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <0-65535>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") void ripng_route_map_reset () { /* XXX ??? */ ; } void ripng_route_map_init () { route_map_init (); route_map_init_vty (); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_interface_cmd); route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); route_map_install_set (&route_set_tag_cmd); install_element (RMAP_NODE, &match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_val_cmd); install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); install_element (RMAP_NODE, &match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); } quagga-0.99.24.1/ripngd/ripng_debug.c0000644000175000017500000001726012476520570014156 00000000000000/* * RIPng debug output routines * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "ripngd/ripng_debug.h" /* For debug statement. */ unsigned long ripng_debug_event = 0; unsigned long ripng_debug_packet = 0; unsigned long ripng_debug_zebra = 0; DEFUN (show_debugging_ripng, show_debugging_ripng_cmd, "show debugging ripng", SHOW_STR DEBUG_STR "RIPng configuration\n") { vty_out (vty, "RIPng debugging status:%s", VTY_NEWLINE); if (IS_RIPNG_DEBUG_EVENT) vty_out (vty, " RIPng event debugging is on%s", VTY_NEWLINE); if (IS_RIPNG_DEBUG_PACKET) { if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV) { vty_out (vty, " RIPng packet debugging is on%s", VTY_NEWLINE); } else { if (IS_RIPNG_DEBUG_SEND) vty_out (vty, " RIPng packet send debugging is on%s", VTY_NEWLINE); else vty_out (vty, " RIPng packet receive debugging is on%s", VTY_NEWLINE); } } if (IS_RIPNG_DEBUG_ZEBRA) vty_out (vty, " RIPng zebra debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (debug_ripng_events, debug_ripng_events_cmd, "debug ripng events", DEBUG_STR "RIPng configuration\n" "Debug option set for ripng events\n") { ripng_debug_event = RIPNG_DEBUG_EVENT; return CMD_WARNING; } DEFUN (debug_ripng_packet, debug_ripng_packet_cmd, "debug ripng packet", DEBUG_STR "RIPng configuration\n" "Debug option set for ripng packet\n") { ripng_debug_packet = RIPNG_DEBUG_PACKET; ripng_debug_packet |= RIPNG_DEBUG_SEND; ripng_debug_packet |= RIPNG_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (debug_ripng_packet_direct, debug_ripng_packet_direct_cmd, "debug ripng packet (recv|send)", DEBUG_STR "RIPng configuration\n" "Debug option set for ripng packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") { ripng_debug_packet |= RIPNG_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) ripng_debug_packet |= RIPNG_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) ripng_debug_packet |= RIPNG_DEBUG_RECV; return CMD_SUCCESS; } /* N.B. the "detail" modifier is a no-op. we leave this command for legacy compatibility. */ DEFUN_DEPRECATED (debug_ripng_packet_detail, debug_ripng_packet_detail_cmd, "debug ripng packet (recv|send) detail", DEBUG_STR "RIPng configuration\n" "Debug option set for ripng packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n" "Debug option set detaied information\n") { ripng_debug_packet |= RIPNG_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) ripng_debug_packet |= RIPNG_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) ripng_debug_packet |= RIPNG_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (debug_ripng_zebra, debug_ripng_zebra_cmd, "debug ripng zebra", DEBUG_STR "RIPng configuration\n" "Debug option set for ripng and zebra communication\n") { ripng_debug_zebra = RIPNG_DEBUG_ZEBRA; return CMD_WARNING; } DEFUN (no_debug_ripng_events, no_debug_ripng_events_cmd, "no debug ripng events", NO_STR DEBUG_STR "RIPng configuration\n" "Debug option set for ripng events\n") { ripng_debug_event = 0; return CMD_SUCCESS; } DEFUN (no_debug_ripng_packet, no_debug_ripng_packet_cmd, "no debug ripng packet", NO_STR DEBUG_STR "RIPng configuration\n" "Debug option set for ripng packet\n") { ripng_debug_packet = 0; return CMD_SUCCESS; } DEFUN (no_debug_ripng_packet_direct, no_debug_ripng_packet_direct_cmd, "no debug ripng packet (recv|send)", NO_STR DEBUG_STR "RIPng configuration\n" "Debug option set for ripng packet\n" "Debug option set for receive packet\n" "Debug option set for send packet\n") { if (strncmp ("send", argv[0], strlen (argv[0])) == 0) { if (IS_RIPNG_DEBUG_RECV) ripng_debug_packet &= ~RIPNG_DEBUG_SEND; else ripng_debug_packet = 0; } else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) { if (IS_RIPNG_DEBUG_SEND) ripng_debug_packet &= ~RIPNG_DEBUG_RECV; else ripng_debug_packet = 0; } return CMD_SUCCESS; } DEFUN (no_debug_ripng_zebra, no_debug_ripng_zebra_cmd, "no debug ripng zebra", NO_STR DEBUG_STR "RIPng configuration\n" "Debug option set for ripng and zebra communication\n") { ripng_debug_zebra = 0; return CMD_WARNING; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", /* Debug node has no interface. */ 1 /* VTYSH */ }; static int config_write_debug (struct vty *vty) { int write = 0; if (IS_RIPNG_DEBUG_EVENT) { vty_out (vty, "debug ripng events%s", VTY_NEWLINE); write++; } if (IS_RIPNG_DEBUG_PACKET) { if (IS_RIPNG_DEBUG_SEND && IS_RIPNG_DEBUG_RECV) { vty_out (vty, "debug ripng packet%s", VTY_NEWLINE); write++; } else { if (IS_RIPNG_DEBUG_SEND) vty_out (vty, "debug ripng packet send%s", VTY_NEWLINE); else vty_out (vty, "debug ripng packet recv%s", VTY_NEWLINE); write++; } } if (IS_RIPNG_DEBUG_ZEBRA) { vty_out (vty, "debug ripng zebra%s", VTY_NEWLINE); write++; } return write; } void ripng_debug_reset () { ripng_debug_event = 0; ripng_debug_packet = 0; ripng_debug_zebra = 0; } void ripng_debug_init () { ripng_debug_event = 0; ripng_debug_packet = 0; ripng_debug_zebra = 0; install_node (&debug_node, config_write_debug); install_element (VIEW_NODE, &show_debugging_ripng_cmd); install_element (ENABLE_NODE, &show_debugging_ripng_cmd); install_element (ENABLE_NODE, &debug_ripng_events_cmd); install_element (ENABLE_NODE, &debug_ripng_packet_cmd); install_element (ENABLE_NODE, &debug_ripng_packet_direct_cmd); install_element (ENABLE_NODE, &debug_ripng_packet_detail_cmd); install_element (ENABLE_NODE, &debug_ripng_zebra_cmd); install_element (ENABLE_NODE, &no_debug_ripng_events_cmd); install_element (ENABLE_NODE, &no_debug_ripng_packet_cmd); install_element (ENABLE_NODE, &no_debug_ripng_packet_direct_cmd); install_element (ENABLE_NODE, &no_debug_ripng_zebra_cmd); install_element (CONFIG_NODE, &debug_ripng_events_cmd); install_element (CONFIG_NODE, &debug_ripng_packet_cmd); install_element (CONFIG_NODE, &debug_ripng_packet_direct_cmd); install_element (CONFIG_NODE, &debug_ripng_packet_detail_cmd); install_element (CONFIG_NODE, &debug_ripng_zebra_cmd); install_element (CONFIG_NODE, &no_debug_ripng_events_cmd); install_element (CONFIG_NODE, &no_debug_ripng_packet_cmd); install_element (CONFIG_NODE, &no_debug_ripng_packet_direct_cmd); install_element (CONFIG_NODE, &no_debug_ripng_zebra_cmd); } quagga-0.99.24.1/ripngd/ripng_route.c0000644000175000017500000000716312476520570014227 00000000000000/* * RIPng routes function. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "table.h" #include "memory.h" #include "if.h" #include "vty.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" static struct ripng_aggregate * ripng_aggregate_new () { struct ripng_aggregate *new; new = XCALLOC (MTYPE_RIPNG_AGGREGATE, sizeof (struct ripng_aggregate)); return new; } static void ripng_aggregate_free (struct ripng_aggregate *aggregate) { XFREE (MTYPE_RIPNG_AGGREGATE, aggregate); } /* Aggregate count increment check. */ void ripng_aggregate_increment (struct route_node *child, struct ripng_info *rinfo) { struct route_node *np; struct ripng_aggregate *aggregate; for (np = child; np; np = np->parent) if ((aggregate = np->aggregate) != NULL) { aggregate->count++; rinfo->suppress++; } } /* Aggregate count decrement check. */ void ripng_aggregate_decrement (struct route_node *child, struct ripng_info *rinfo) { struct route_node *np; struct ripng_aggregate *aggregate; for (np = child; np; np = np->parent) if ((aggregate = np->aggregate) != NULL) { aggregate->count--; rinfo->suppress--; } } /* RIPng routes treatment. */ int ripng_aggregate_add (struct prefix *p) { struct route_node *top; struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); /* Allocate new aggregate. */ aggregate = ripng_aggregate_new (); aggregate->metric = 1; top->aggregate = aggregate; /* Suppress routes match to the aggregate. */ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ if ((rinfo = rp->info) != NULL) { aggregate->count++; rinfo->suppress++; } /* Suppress aggregate route. This may not need. */ if (rp != top && (sub = rp->aggregate) != NULL) { aggregate->count++; sub->suppress++; } } return 0; } /* Delete RIPng static route. */ int ripng_aggregate_delete (struct prefix *p) { struct route_node *top; struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct ripng_aggregate *sub; /* Get top node for aggregation. */ top = route_node_get (ripng->table, p); /* Allocate new aggregate. */ aggregate = top->aggregate; /* Suppress routes match to the aggregate. */ for (rp = route_lock_node (top); rp; rp = route_next_until (rp, top)) { /* Suppress normal route. */ if ((rinfo = rp->info) != NULL) { aggregate->count--; rinfo->suppress--; } if (rp != top && (sub = rp->aggregate) != NULL) { aggregate->count--; sub->suppress--; } } top->aggregate = NULL; ripng_aggregate_free (aggregate); route_unlock_node (top); route_unlock_node (top); return 0; } quagga-0.99.24.1/ripngd/ripng_zebra.c0000644000175000017500000003373012476520570014173 00000000000000/* * RIPngd and zebra interface. * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "stream.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripngd/ripngd.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* Callback prototypes for zebra client service. */ int ripng_interface_up (int, struct zclient *, zebra_size_t); int ripng_interface_down (int, struct zclient *, zebra_size_t); int ripng_interface_add (int, struct zclient *, zebra_size_t); int ripng_interface_delete (int, struct zclient *, zebra_size_t); int ripng_interface_address_add (int, struct zclient *, zebra_size_t); int ripng_interface_address_delete (int, struct zclient *, zebra_size_t); void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex, u_char metric) { struct zapi_ipv6 api; if (zclient->redist[ZEBRA_ROUTE_RIPNG]) { api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, p, &api); } } void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex) { struct zapi_ipv6 api; if (zclient->redist[ZEBRA_ROUTE_RIPNG]) { api.type = ZEBRA_ROUTE_RIPNG; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, p, &api); } } /* Zebra route add and delete treatment. */ static int ripng_zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; unsigned long ifindex; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; ifindex = 0; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, 16); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV6_ROUTE_ADD) ripng_redistribute_add (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop); else ripng_redistribute_delete (api.type, RIPNG_ROUTE_REDISTRIBUTE, &p, ifindex); return 0; } void ripng_zclient_reset (void) { zclient_reset (zclient); } static int ripng_redistribute_unset (int type) { if (! zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); ripng_redistribute_withdraw (type); return CMD_SUCCESS; } int ripng_redistribute_check (int type) { return (zclient->redist[type]); } static void ripng_redistribute_metric_set (int type, int metric) { ripng->route_map[type].metric_config = 1; ripng->route_map[type].metric = metric; } static int ripng_redistribute_metric_unset (int type) { ripng->route_map[type].metric_config = 0; ripng->route_map[type].metric = 0; return 0; } static void ripng_redistribute_routemap_set (int type, const char *name) { if (ripng->route_map[type].name) free (ripng->route_map[type].name); ripng->route_map[type].name = strdup (name); ripng->route_map[type].map = route_map_lookup_by_name (name); } static void ripng_redistribute_routemap_unset (int type) { if (ripng->route_map[type].name) free (ripng->route_map[type].name); ripng->route_map[type].name = NULL; ripng->route_map[type].map = NULL; } /* Redistribution types */ static struct { int type; int str_min_len; const char *str; } redist_type[] = { {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, {ZEBRA_ROUTE_CONNECT, 1, "connected"}, {ZEBRA_ROUTE_STATIC, 1, "static"}, {ZEBRA_ROUTE_OSPF6, 1, "ospf6"}, {ZEBRA_ROUTE_BGP, 2, "bgp"}, {ZEBRA_ROUTE_BABEL, 2, "babel"}, {0, 0, NULL} }; void ripng_redistribute_clean () { int i; for (i = 0; redist_type[i].str; i++) { if (zclient->redist[redist_type[i].type]) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type); zclient->redist[redist_type[i].type] = 0; /* Remove the routes from RIPng table. */ ripng_redistribute_withdraw (redist_type[i].type); } } } DEFUN (router_zebra, router_zebra_cmd, "router zebra", "Enable a routing process\n" "Make connection to zebra daemon\n") { vty->node = ZEBRA_NODE; zclient->enable = 1; zclient_start (zclient); return CMD_SUCCESS; } DEFUN (no_router_zebra, no_router_zebra_cmd, "no router zebra", NO_STR "Disable a routing process\n" "Stop connection to zebra daemon\n") { zclient->enable = 0; zclient_stop (zclient); return CMD_SUCCESS; } DEFUN (ripng_redistribute_ripng, ripng_redistribute_ripng_cmd, "redistribute ripng", "Redistribute information from another routing protocol\n" "RIPng route\n") { zclient->redist[ZEBRA_ROUTE_RIPNG] = 1; return CMD_SUCCESS; } DEFUN (no_ripng_redistribute_ripng, no_ripng_redistribute_ripng_cmd, "no redistribute ripng", NO_STR "Redistribute information from another routing protocol\n" "RIPng route\n") { zclient->redist[ZEBRA_ROUTE_RIPNG] = 0; return CMD_SUCCESS; } DEFUN (ripng_redistribute_type, ripng_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD, "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } DEFUN (no_ripng_redistribute_type, no_ripng_redistribute_type_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD, NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD) { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_unset (type); ripng_redistribute_routemap_unset (type); return ripng_redistribute_unset (type); } DEFUN (ripng_redistribute_type_metric, ripng_redistribute_type_metric_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") { int type; int metric; metric = atoi (argv[1]); type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_set (type, metric); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n") DEFUN (ripng_redistribute_type_routemap, ripng_redistribute_type_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum(AFI_IP6, argv[0]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_routemap_set (type, argv[1]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") DEFUN (ripng_redistribute_type_metric_routemap, ripng_redistribute_type_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") { int type; int metric; type = proto_redistnum(AFI_IP6, argv[0]); metric = atoi (argv[1]); if (type < 0) { vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_metric_set (type, metric); ripng_redistribute_routemap_set (type, argv[2]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } ALIAS (no_ripng_redistribute_type, no_ripng_redistribute_type_metric_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD", NO_STR "Redistribute\n" QUAGGA_REDIST_HELP_STR_RIPNGD "Route map reference\n" "Pointer to route-map entries\n") void ripng_redistribute_write (struct vty *vty, int config_mode) { int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) { if (config_mode) { if (ripng->route_map[i].metric_config) { if (ripng->route_map[i].name) vty_out (vty, " redistribute %s metric %d route-map %s%s", zebra_route_string(i), ripng->route_map[i].metric, ripng->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s metric %d%s", zebra_route_string(i), ripng->route_map[i].metric, VTY_NEWLINE); } else { if (ripng->route_map[i].name) vty_out (vty, " redistribute %s route-map %s%s", zebra_route_string(i), ripng->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s%s", zebra_route_string(i), VTY_NEWLINE); } } else vty_out (vty, " %s", zebra_route_string(i)); } } /* RIPng configuration write function. */ static int zebra_config_write (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! zclient->redist[ZEBRA_ROUTE_RIPNG]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute ripng%s", VTY_NEWLINE); return 1; } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", }; /* Initialize zebra structure and it's commands. */ void zebra_init () { /* Allocate zebra structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIPNG); zclient->interface_up = ripng_interface_up; zclient->interface_down = ripng_interface_down; zclient->interface_add = ripng_interface_add; zclient->interface_delete = ripng_interface_delete; zclient->interface_address_add = ripng_interface_address_add; zclient->interface_address_delete = ripng_interface_address_delete; zclient->ipv6_route_add = ripng_zebra_read_ipv6; zclient->ipv6_route_delete = ripng_zebra_read_ipv6; /* Install zebra node. */ install_node (&zebra_node, zebra_config_write); /* Install command element for zebra node. */ install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &ripng_redistribute_ripng_cmd); install_element (ZEBRA_NODE, &no_ripng_redistribute_ripng_cmd); /* Install command elements to ripng node */ install_element (RIPNG_NODE, &ripng_redistribute_type_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_routemap_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_cmd); install_element (RIPNG_NODE, &ripng_redistribute_type_metric_routemap_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_routemap_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_cmd); install_element (RIPNG_NODE, &no_ripng_redistribute_type_metric_routemap_cmd); } quagga-0.99.24.1/ripngd/ripngd.c0000644000175000017500000023511312476520570013153 00000000000000/* RIPng daemon * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "filter.h" #include "log.h" #include "thread.h" #include "memory.h" #include "if.h" #include "stream.h" #include "table.h" #include "command.h" #include "sockopt.h" #include "distribute.h" #include "plist.h" #include "routemap.h" #include "if_rmap.h" #include "privs.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_route.h" #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" /* RIPng structure which includes many parameters related to RIPng protocol. If ripng couldn't active or ripng doesn't configured, ripng->fd must be negative value. */ struct ripng *ripng = NULL; enum { ripng_all_route, ripng_changed_route, }; extern struct zebra_privs_t ripngd_privs; /* Prototypes. */ void ripng_output_process (struct interface *, struct sockaddr_in6 *, int); int ripng_triggered_update (struct thread *); /* RIPng next hop specification. */ struct ripng_nexthop { enum ripng_nexthop_type { RIPNG_NEXTHOP_UNSPEC, RIPNG_NEXTHOP_ADDRESS } flag; struct in6_addr address; }; static int ripng_route_rte (struct ripng_info *rinfo) { return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE); } /* Allocate new ripng information. */ struct ripng_info * ripng_info_new () { struct ripng_info *new; new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info)); return new; } /* Free ripng information. */ void ripng_info_free (struct ripng_info *rinfo) { XFREE (MTYPE_RIPNG_ROUTE, rinfo); } /* Create ripng socket. */ static int ripng_make_socket (void) { int ret; int sock; struct sockaddr_in6 ripaddr; sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { zlog (NULL, LOG_ERR, "Can't make ripng socket"); return sock; } ret = setsockopt_so_recvbuf (sock, 8096); if (ret < 0) return ret; ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) return ret; #ifdef IPTOS_PREC_INTERNETCONTROL ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); if (ret < 0) return ret; #endif ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) return ret; ret = setsockopt_ipv6_multicast_loop (sock, 0); if (ret < 0) return ret; ret = setsockopt_ipv6_hoplimit (sock, 1); if (ret < 0) return ret; memset (&ripaddr, 0, sizeof (ripaddr)); ripaddr.sin6_family = AF_INET6; #ifdef SIN6_LEN ripaddr.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT); if (ripngd_privs.change (ZPRIVS_RAISE)) zlog_err ("ripng_make_socket: could not raise privs"); ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno)); if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_make_socket: could not lower privs"); return ret; } if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_make_socket: could not lower privs"); return sock; } /* Send RIPng packet. */ int ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, struct interface *ifp) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; char adata [256]; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; if (IS_RIPNG_DEBUG_SEND) { if (to) zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr)); zlog_debug (" send interface %s", ifp->name); zlog_debug (" send packet size %d", bufsize); } memset (&addr, 0, sizeof (struct sockaddr_in6)); addr.sin6_family = AF_INET6; #ifdef SIN6_LEN addr.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT); /* When destination is specified. */ if (to != NULL) { addr.sin6_addr = to->sin6_addr; addr.sin6_port = to->sin6_port; } else { inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr); addr.sin6_port = htons (RIPNG_PORT_DEFAULT); } msg.msg_name = (void *) &addr; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); iov.iov_base = buf; iov.iov_len = bufsize; cmsgptr = (struct cmsghdr *)adata; cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo)); cmsgptr->cmsg_level = IPPROTO_IPV6; cmsgptr->cmsg_type = IPV6_PKTINFO; pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr)); pkt->ipi6_ifindex = ifp->ifindex; ret = sendmsg (ripng->sock, &msg, 0); if (ret < 0) { if (to) zlog_err ("RIPng send fail on %s to %s: %s", ifp->name, inet6_ntoa (to->sin6_addr), safe_strerror (errno)); else zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno)); } return ret; } /* Receive UDP RIPng packet from socket. */ static int ripng_recv_packet (int sock, u_char *buf, int bufsize, struct sockaddr_in6 *from, unsigned int *ifindex, int *hoplimit) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_addr dst; /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this point I can't determine size of cmsghdr */ char adata[1024]; /* Fill in message and iovec. */ msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = bufsize; /* If recvmsg fail return minus value. */ ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { /* I want interface index which this packet comes from. */ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO) { struct in6_pktinfo *ptr; ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); *ifindex = ptr->ipi6_ifindex; dst = ptr->ipi6_addr; if (*ifindex == 0) zlog_warn ("Interface index returned by IPV6_PKTINFO is zero"); } /* Incoming packet's multicast hop limit. */ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) { int *phoplimit = (int *) CMSG_DATA (cmsgptr); *hoplimit = *phoplimit; } } /* Hoplimit check shold be done when destination address is multicast address. */ if (! IN6_IS_ADDR_MULTICAST (&dst)) *hoplimit = -1; return ret; } /* Dump rip packet */ void ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv) { caddr_t lim; struct rte *rte; const char *command_str; /* Set command string. */ if (packet->command == RIPNG_REQUEST) command_str = "request"; else if (packet->command == RIPNG_RESPONSE) command_str = "response"; else command_str = "unknown"; /* Dump packet header. */ zlog_debug ("%s %s version %d packet size %d", sndrcv, command_str, packet->version, size); /* Dump each routing table entry. */ rte = packet->rte; for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) { if (rte->metric == RIPNG_METRIC_NEXTHOP) zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen); else zlog_debug (" %s/%d metric %d tag %d", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric, ntohs (rte->tag)); } } /* RIPng next hop address RTE (Route Table Entry). */ static void ripng_nexthop_rte (struct rte *rte, struct sockaddr_in6 *from, struct ripng_nexthop *nexthop) { char buf[INET6_BUFSIZ]; /* Logging before checking RTE. */ if (IS_RIPNG_DEBUG_RECV) zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d", inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen); /* RFC2080 2.1.1 Next Hop: The route tag and prefix length in the next hop RTE must be set to zero on sending and ignored on receiption. */ if (ntohs (rte->tag) != 0) zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s", ntohs (rte->tag), inet6_ntoa (from->sin6_addr)); if (rte->prefixlen != 0) zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s", rte->prefixlen, inet6_ntoa (from->sin6_addr)); /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a next hop RTE indicates that the next hop address should be the originator of the RIPng advertisement. An address specified as a next hop must be a link-local address. */ if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr)) { nexthop->flag = RIPNG_NEXTHOP_UNSPEC; memset (&nexthop->address, 0, sizeof (struct in6_addr)); return; } if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) { nexthop->flag = RIPNG_NEXTHOP_ADDRESS; IPV6_ADDR_COPY (&nexthop->address, &rte->addr); return; } /* The purpose of the next hop RTE is to eliminate packets being routed through extra hops in the system. It is particularly useful when RIPng is not being run on all of the routers on a network. Note that next hop RTE is "advisory". That is, if the provided information is ignored, a possibly sub-optimal, but absolutely valid, route may be taken. If the received next hop address is not a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */ zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s", inet6_ntoa (rte->addr), inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ)); nexthop->flag = RIPNG_NEXTHOP_UNSPEC; memset (&nexthop->address, 0, sizeof (struct in6_addr)); return; } /* If ifp has same link-local address then return 1. */ static int ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr) { struct listnode *node; struct connected *connected; struct prefix *p; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { p = connected->address; if (p->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) && IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr)) return 1; } return 0; } /* RIPng route garbage collect timer. */ static int ripng_garbage_collect (struct thread *t) { struct ripng_info *rinfo; struct route_node *rp; rinfo = THREAD_ARG (t); rinfo->t_garbage_collect = NULL; /* Off timeout timer. */ RIPNG_TIMER_OFF (rinfo->t_timeout); /* Get route_node pointer. */ rp = rinfo->rp; /* Unlock route_node. */ rp->info = NULL; route_unlock_node (rp); /* Free RIPng routing information. */ ripng_info_free (rinfo); return 0; } /* Timeout RIPng routes. */ static int ripng_timeout (struct thread *t) { struct ripng_info *rinfo; struct route_node *rp; rinfo = THREAD_ARG (t); rinfo->t_timeout = NULL; /* Get route_node pointer. */ rp = rinfo->rp; /* - The garbage-collection timer is set for 120 seconds. */ RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); /* Delete this route from the kernel. */ ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->ifindex); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service. */ rinfo->metric = RIPNG_METRIC_INFINITY; rinfo->flags &= ~RIPNG_RTF_FIB; /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); /* - The route change flag is to indicate that this entry has been changed. */ rinfo->flags |= RIPNG_RTF_CHANGED; /* - The output process is signalled to trigger a response. */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); return 0; } static void ripng_timeout_update (struct ripng_info *rinfo) { if (rinfo->metric != RIPNG_METRIC_INFINITY) { RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time); } } static int ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; /* Input distribute-list filtering. */ if (ri->list[RIPNG_FILTER_IN]) { if (access_list_apply (ri->list[RIPNG_FILTER_IN], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIPNG_FILTER_IN]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } static int ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; if (ri->list[RIPNG_FILTER_OUT]) { if (access_list_apply (ri->list[RIPNG_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by distribute out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIPNG_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by prefix-list out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list out", inet6_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } /* Process RIPng route according to RFC2080. */ static void ripng_route_process (struct rte *rte, struct sockaddr_in6 *from, struct ripng_nexthop *ripng_nexthop, struct interface *ifp) { int ret; struct prefix_ipv6 p; struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct in6_addr *nexthop; u_char oldmetric; int same = 0; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; /* p.prefix = rte->addr; */ IPV6_ADDR_COPY (&p.prefix, &rte->addr); p.prefixlen = rte->prefixlen; /* Make sure mask is applied. */ /* XXX We have to check the prefix is valid or not before call apply_mask_ipv6. */ apply_mask_ipv6 (&p); /* Apply input filters. */ ri = ifp->info; ret = ripng_incoming_filter (&p, ri); if (ret < 0) return; /* Modify entry. */ if (ri->routemap[RIPNG_FILTER_IN]) { int ret; struct ripng_info newinfo; memset (&newinfo, 0, sizeof (struct ripng_info)); newinfo.type = ZEBRA_ROUTE_RIPNG; newinfo.sub_type = RIPNG_ROUTE_RTE; if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) newinfo.nexthop = ripng_nexthop->address; else newinfo.nexthop = from->sin6_addr; newinfo.from = from->sin6_addr; newinfo.ifindex = ifp->ifindex; newinfo.metric = rte->metric; newinfo.metric_out = rte->metric; /* XXX */ newinfo.tag = ntohs(rte->tag); /* XXX */ ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], (struct prefix *)&p, RMAP_RIPNG, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map in", inet6_ntoa (p.prefix), p.prefixlen); return; } /* Get back the object */ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) { if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) { /* the nexthop get changed by the routemap */ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) ripng_nexthop->address = newinfo.nexthop; else ripng_nexthop->address = in6addr_any; } } else { if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) { /* the nexthop get changed by the routemap */ if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) { ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS; ripng_nexthop->address = newinfo.nexthop; } } } rte->tag = htons(newinfo.tag_out); /* XXX */ rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ } /* Once the entry has been validated, update the metric by * adding the cost of the network on wich the message * arrived. If the result is greater than infinity, use infinity * (RFC2453 Sec. 3.9.2) **/ /* Zebra ripngd can handle offset-list in. */ ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric); /* If offset-list does not modify the metric use interface's * one. */ if (! ret) rte->metric += ifp->metric ? ifp->metric : 1; if (rte->metric > RIPNG_METRIC_INFINITY) rte->metric = RIPNG_METRIC_INFINITY; /* Set nexthop pointer. */ if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) nexthop = &ripng_nexthop->address; else nexthop = &from->sin6_addr; /* Lookup RIPng routing table. */ rp = route_node_get (ripng->table, (struct prefix *) &p); /* Sanity check */ rinfo = rp->info; if (rinfo) { /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->metric != RIPNG_METRIC_INFINITY) return; /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIPNG && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) && rinfo->metric != RIPNG_METRIC_INFINITY) return; } if (rp->info == NULL) { /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add this route to the routing table, unless the metric is infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIPNG_METRIC_INFINITY) { rinfo = ripng_info_new (); /* - Setting the destination prefix and length to those in the RTE. */ rp->info = rinfo; rinfo->rp = rp; /* - Setting the metric to the newly calculated metric (as described above). */ rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); /* - Set the next hop address to be the address of the router from which the datagram came or the next hop address specified by a next hop RTE. */ IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); rinfo->ifindex = ifp->ifindex; /* - Initialize the timeout for the route. If the garbage-collection timer is running for this route, stop it. */ ripng_timeout_update (rinfo); /* - Set the route change flag. */ rinfo->flags |= RIPNG_RTF_CHANGED; /* - Signal the output process to trigger an update (see section 2.5). */ ripng_event (RIPNG_TRIGGERED_UPDATE, 0); /* Finally, route goes into the kernel. */ rinfo->type = ZEBRA_ROUTE_RIPNG; rinfo->sub_type = RIPNG_ROUTE_RTE; ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; /* Aggregate check. */ ripng_aggregate_increment (rp, rinfo); } } else { rinfo = rp->info; /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) && (rinfo->ifindex == ifp->ifindex)); if (same) ripng_timeout_update (rinfo); /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old one; do the following actions: */ if ((same && rinfo->metric != rte->metric) || rte->metric < rinfo->metric) { /* - Adopt the route from the datagram. That is, put the new metric in, and adjust the next hop address (if necessary). */ oldmetric = rinfo->metric; rinfo->metric = rte->metric; rinfo->tag = ntohs (rte->tag); IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr); rinfo->ifindex = ifp->ifindex; /* Should a new route to this network be established while the garbage-collection timer is running, the new route will replace the one that is about to be deleted. In this case the garbage-collection timer must be cleared. */ if (oldmetric == RIPNG_METRIC_INFINITY && rinfo->metric < RIPNG_METRIC_INFINITY) { rinfo->type = ZEBRA_ROUTE_RIPNG; rinfo->sub_type = RIPNG_ROUTE_RTE; RIPNG_TIMER_OFF (rinfo->t_garbage_collect); if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; /* The aggregation counter needs to be updated because the prefixes, which are into the gc, have been removed from the aggregator (see ripng_timout). */ ripng_aggregate_increment (rp, rinfo); } /* Update nexthop and/or metric value. */ if (oldmetric != RIPNG_METRIC_INFINITY) { ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric); rinfo->flags |= RIPNG_RTF_FIB; if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop)) IPV6_ADDR_COPY (&rinfo->nexthop, nexthop); } /* - Set the route change flag and signal the output process to trigger an update. */ rinfo->flags |= RIPNG_RTF_CHANGED; ripng_event (RIPNG_TRIGGERED_UPDATE, 0); /* - If the new metric is infinity, start the deletion process (described above); */ if (rinfo->metric == RIPNG_METRIC_INFINITY) { /* If the new metric is infinity, the deletion process begins for the route, which is no longer used for routing packets. Note that the deletion process is started only when the metric is first set to infinity. If the metric was already infinity, then a new deletion process is not started. */ if (oldmetric != RIPNG_METRIC_INFINITY) { /* - The garbage-collection timer is set for 120 seconds. */ RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* - The metric for the route is set to 16 (infinity). This causes the route to be removed from service.*/ ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex); rinfo->flags &= ~RIPNG_RTF_FIB; /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); /* - The route change flag is to indicate that this entry has been changed. */ /* - The output process is signalled to trigger a response. */ ; /* Above processes are already done previously. */ } } else { /* otherwise, re-initialize the timeout. */ ripng_timeout_update (rinfo); } } /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } } /* Add redistributed route to RIPng table. */ void ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, unsigned int ifindex, struct in6_addr *nexthop) { struct route_node *rp; struct ripng_info *rinfo; /* Redistribute route */ if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; rp = route_node_get (ripng->table, (struct prefix *) p); rinfo = rp->info; if (rinfo) { if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIPNG_ROUTE_INTERFACE && rinfo->metric != RIPNG_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Manually configured RIPng route check. * They have the precedence on all the other entries. **/ if (rinfo->type == ZEBRA_ROUTE_RIPNG && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) || (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) { if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) && (sub_type != RIPNG_ROUTE_DEFAULT))) { route_unlock_node (rp); return; } } RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); /* Tells the other daemons about the deletion of * this RIPng route **/ if (ripng_route_rte (rinfo)) ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->metric); rp->info = NULL; ripng_info_free (rinfo); route_unlock_node (rp); } rinfo = ripng_info_new (); rinfo->type = type; rinfo->sub_type = sub_type; rinfo->ifindex = ifindex; rinfo->metric = 1; rinfo->rp = rp; if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop)) rinfo->nexthop = *nexthop; rinfo->flags |= RIPNG_RTF_FIB; rp->info = rinfo; /* Aggregate check. */ ripng_aggregate_increment (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; if (IS_RIPNG_DEBUG_EVENT) { if (!nexthop) zlog_debug ("Redistribute new prefix %s/%d on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); else zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop), ifindex2ifname(ifindex)); } ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } /* Delete redistributed route to RIPng table. */ void ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, unsigned int ifindex) { struct route_node *rp; struct ripng_info *rinfo; if (IN6_IS_ADDR_LINKLOCAL (&p->prefix)) return; if (IN6_IS_ADDR_LOOPBACK (&p->prefix)) return; rp = route_node_lookup (ripng->table, (struct prefix *) p); if (rp) { rinfo = rp->info; if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* Perform poisoned reverse. */ rinfo->metric = RIPNG_METRIC_INFINITY; RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]", inet6_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } } } /* Withdraw redistributed route. */ void ripng_redistribute_withdraw (int type) { struct route_node *rp; struct ripng_info *rinfo; if (!ripng) return; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { if ((rinfo->type == type) && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE)) { /* Perform poisoned reverse. */ rinfo->metric = RIPNG_METRIC_INFINITY; RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect, ripng->garbage_time); RIPNG_TIMER_OFF (rinfo->t_timeout); /* Aggregate count decrement. */ ripng_aggregate_decrement (rp, rinfo); rinfo->flags |= RIPNG_RTF_CHANGED; if (IS_RIPNG_DEBUG_EVENT) { struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p; zlog_debug ("Poisone %s/%d on the interface %s [withdraw]", inet6_ntoa(p->prefix), p->prefixlen, ifindex2ifname(rinfo->ifindex)); } ripng_event (RIPNG_TRIGGERED_UPDATE, 0); } } } /* RIP routing information. */ static void ripng_response_process (struct ripng_packet *packet, int size, struct sockaddr_in6 *from, struct interface *ifp, int hoplimit) { caddr_t lim; struct rte *rte; struct ripng_nexthop nexthop; /* RFC2080 2.4.2 Response Messages: The Response must be ignored if it is not from the RIPng port. */ if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT) { zlog_warn ("RIPng packet comes from non RIPng port %d from %s", ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); return; } /* The datagram's IPv6 source address should be checked to see whether the datagram is from a valid neighbor; the source of the datagram must be a link-local address. */ if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) { zlog_warn ("RIPng packet comes from non link local address %s", inet6_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); return; } /* It is also worth checking to see whether the response is from one of the router's own addresses. Interfaces on broadcast networks may receive copies of their own multicasts immediately. If a router processes its own output as new input, confusion is likely, and such datagrams must be ignored. */ if (ripng_lladdr_check (ifp, &from->sin6_addr)) { zlog_warn ("RIPng packet comes from my own link local address %s", inet6_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); return; } /* As an additional check, periodic advertisements must have their hop counts set to 255, and inbound, multicast packets sent from the RIPng port (i.e. periodic advertisement or triggered update packets) must be examined to ensure that the hop count is 255. */ if (hoplimit >= 0 && hoplimit != 255) { zlog_warn ("RIPng packet comes with non 255 hop count %d from %s", hoplimit, inet6_ntoa (from->sin6_addr)); ripng_peer_bad_packet (from); return; } /* Update RIPng peer. */ ripng_peer_update (from, packet->version); /* Reset nexthop. */ memset (&nexthop, 0, sizeof (struct ripng_nexthop)); nexthop.flag = RIPNG_NEXTHOP_UNSPEC; /* Set RTE pointer. */ rte = packet->rte; for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++) { /* First of all, we have to check this RTE is next hop RTE or not. Next hop RTE is completely different with normal RTE so we need special treatment. */ if (rte->metric == RIPNG_METRIC_NEXTHOP) { ripng_nexthop_rte (rte, from, &nexthop); continue; } /* RTE information validation. */ /* - is the destination prefix valid (e.g., not a multicast prefix and not a link-local address) A link-local address should never be present in an RTE. */ if (IN6_IS_ADDR_MULTICAST (&rte->addr)) { zlog_warn ("Destination prefix is a multicast address %s/%d [%d]", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); continue; } if (IN6_IS_ADDR_LINKLOCAL (&rte->addr)) { zlog_warn ("Destination prefix is a link-local address %s/%d [%d]", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); continue; } if (IN6_IS_ADDR_LOOPBACK (&rte->addr)) { zlog_warn ("Destination prefix is a loopback address %s/%d [%d]", inet6_ntoa (rte->addr), rte->prefixlen, rte->metric); ripng_peer_bad_route (from); continue; } /* - is the prefix length valid (i.e., between 0 and 128, inclusive) */ if (rte->prefixlen > 128) { zlog_warn ("Invalid prefix length %s/%d from %s%%%s", inet6_ntoa (rte->addr), rte->prefixlen, inet6_ntoa (from->sin6_addr), ifp->name); ripng_peer_bad_route (from); continue; } /* - is the metric valid (i.e., between 1 and 16, inclusive) */ if (! (rte->metric >= 1 && rte->metric <= 16)) { zlog_warn ("Invalid metric %d from %s%%%s", rte->metric, inet6_ntoa (from->sin6_addr), ifp->name); ripng_peer_bad_route (from); continue; } /* Vincent: XXX Should we compute the direclty reachable nexthop * for our RIPng network ? **/ /* Routing table updates. */ ripng_route_process (rte, from, &nexthop, ifp); } } /* Response to request message. */ static void ripng_request_process (struct ripng_packet *packet,int size, struct sockaddr_in6 *from, struct interface *ifp) { caddr_t lim; struct rte *rte; struct prefix_ipv6 p; struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; /* Does not reponse to the requests on the loopback interfaces */ if (if_is_loopback (ifp)) return; /* Check RIPng process is enabled on this interface. */ ri = ifp->info; if (! ri->running) return; /* When passive interface is specified, suppress responses */ if (ri->passive) return; /* RIPng peer update. */ ripng_peer_update (from, packet->version); lim = ((caddr_t) packet) + size; rte = packet->rte; /* The Request is processed entry by entry. If there are no entries, no response is given. */ if (lim == (caddr_t) rte) return; /* There is one special case. If there is exactly one entry in the request, and it has a destination prefix of zero, a prefix length of zero, and a metric of infinity (i.e., 16), then this is a request to send the entire routing table. In that case, a call is made to the output process to send the routing table to the requesting address/port. */ if (lim == ((caddr_t) (rte + 1)) && IN6_IS_ADDR_UNSPECIFIED (&rte->addr) && rte->prefixlen == 0 && rte->metric == RIPNG_METRIC_INFINITY) { /* All route with split horizon */ ripng_output_process (ifp, from, ripng_all_route); } else { /* Except for this special case, processing is quite simple. Examine the list of RTEs in the Request one by one. For each entry, look up the destination in the router's routing database and, if there is a route, put that route's metric in the metric field of the RTE. If there is no explicit route to the specified destination, put infinity in the metric field. Once all the entries have been filled in, change the command from Request to Response and send the datagram back to the requestor. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; for (; ((caddr_t) rte) < lim; rte++) { p.prefix = rte->addr; p.prefixlen = rte->prefixlen; apply_mask_ipv6 (&p); rp = route_node_lookup (ripng->table, (struct prefix *) &p); if (rp) { rinfo = rp->info; rte->metric = rinfo->metric; route_unlock_node (rp); } else rte->metric = RIPNG_METRIC_INFINITY; } packet->command = RIPNG_RESPONSE; ripng_send_packet ((caddr_t) packet, size, from, ifp); } } /* First entry point of reading RIPng packet. */ static int ripng_read (struct thread *thread) { int len; int sock; struct sockaddr_in6 from; struct ripng_packet *packet; unsigned int ifindex; struct interface *ifp; int hoplimit = -1; /* Check ripng is active and alive. */ assert (ripng != NULL); assert (ripng->sock >= 0); /* Fetch thread data and set read pointer to empty for event managing. `sock' sould be same as ripng->sock. */ sock = THREAD_FD (thread); ripng->t_read = NULL; /* Add myself to the next event. */ ripng_event (RIPNG_READ, sock); /* Read RIPng packet. */ len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), STREAM_SIZE (ripng->ibuf), &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno)); return len; } /* Check RTE boundary. RTE size (Packet length - RIPng header size (4)) must be multiple size of one RTE size (20). */ if (((len - 4) % 20) != 0) { zlog_warn ("RIPng invalid packet size %d from %s", len, inet6_ntoa (from.sin6_addr)); ripng_peer_bad_packet (&from); return 0; } packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf); ifp = if_lookup_by_index (ifindex); /* RIPng packet received. */ if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng packet received from %s port %d on %s", inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port), ifp ? ifp->name : "unknown"); /* Logging before packet checking. */ if (IS_RIPNG_DEBUG_RECV) ripng_packet_dump (packet, len, "RECV"); /* Packet comes from unknown interface. */ if (ifp == NULL) { zlog_warn ("RIPng packet comes from unknown interface %d", ifindex); return 0; } /* Packet version mismatch checking. */ if (packet->version != ripng->version) { zlog_warn ("RIPng packet version %d doesn't fit to my version %d", packet->version, ripng->version); ripng_peer_bad_packet (&from); return 0; } /* Process RIPng packet. */ switch (packet->command) { case RIPNG_REQUEST: ripng_request_process (packet, len, &from, ifp); break; case RIPNG_RESPONSE: ripng_response_process (packet, len, &from, ifp, hoplimit); break; default: zlog_warn ("Invalid RIPng command %d", packet->command); ripng_peer_bad_packet (&from); break; } return 0; } /* Walk down the RIPng routing table then clear changed flag. */ static void ripng_clear_changed_flag (void) { struct route_node *rp; struct ripng_info *rinfo; for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) if (rinfo->flags & RIPNG_RTF_CHANGED) rinfo->flags &= ~RIPNG_RTF_CHANGED; } /* Regular update of RIPng route. Send all routing formation to RIPng enabled interface. */ static int ripng_update (struct thread *t) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; /* Clear update timer thread. */ ripng->t_update = NULL; /* Logging update event. */ if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng update timer expired!"); /* Supply routes to each interface. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if (if_is_loopback (ifp) || ! if_is_up (ifp)) continue; if (! ri->running) continue; /* When passive interface is specified, suppress announce to the interface. */ if (ri->passive) continue; #if RIPNG_ADVANCED if (ri->ri_send == RIPNG_SEND_OFF) { if (IS_RIPNG_DEBUG_EVENT) zlog (NULL, LOG_DEBUG, "[Event] RIPng send to if %d is suppressed by config", ifp->ifindex); continue; } #endif /* RIPNG_ADVANCED */ ripng_output_process (ifp, NULL, ripng_all_route); } /* Triggered updates may be suppressed if a regular update is due by the time the triggered update would be sent. */ if (ripng->t_triggered_interval) { thread_cancel (ripng->t_triggered_interval); ripng->t_triggered_interval = NULL; } ripng->trigger = 0; /* Reset flush event. */ ripng_event (RIPNG_UPDATE_EVENT, 0); return 0; } /* Triggered update interval timer. */ static int ripng_triggered_interval (struct thread *t) { ripng->t_triggered_interval = NULL; if (ripng->trigger) { ripng->trigger = 0; ripng_triggered_update (t); } return 0; } /* Execute triggered update. */ int ripng_triggered_update (struct thread *t) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; int interval; ripng->t_triggered_update = NULL; /* Cancel interval timer. */ if (ripng->t_triggered_interval) { thread_cancel (ripng->t_triggered_interval); ripng->t_triggered_interval = NULL; } ripng->trigger = 0; /* Logging triggered update. */ if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng triggered update!"); /* Split Horizon processing is done when generating triggered updates as well as normal updates (see section 2.6). */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if (if_is_loopback (ifp) || ! if_is_up (ifp)) continue; if (! ri->running) continue; /* When passive interface is specified, suppress announce to the interface. */ if (ri->passive) continue; ripng_output_process (ifp, NULL, ripng_changed_route); } /* Once all of the triggered updates have been generated, the route change flags should be cleared. */ ripng_clear_changed_flag (); /* After a triggered update is sent, a timer should be set for a random interval between 1 and 5 seconds. If other changes that would trigger updates occur before the timer expires, a single update is triggered when the timer expires. */ interval = (random () % 5) + 1; ripng->t_triggered_interval = thread_add_timer (master, ripng_triggered_interval, NULL, interval); return 0; } /* Write routing table entry to the stream and return next index of the routing table entry in the stream. */ int ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p, struct in6_addr *nexthop, u_int16_t tag, u_char metric) { /* RIPng packet header. */ if (num == 0) { stream_putc (s, RIPNG_RESPONSE); stream_putc (s, RIPNG_V1); stream_putw (s, 0); } /* Write routing table entry. */ if (!nexthop) stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr)); else stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr)); stream_putw (s, tag); if (p) stream_putc (s, p->prefixlen); else stream_putc (s, 0); stream_putc (s, metric); return ++num; } /* Send RESPONSE message to specified destination. */ void ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to, int route_type) { int ret; struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; struct list * ripng_rte_list; if (IS_RIPNG_DEBUG_EVENT) { if (to) zlog_debug ("RIPng update routes to neighbor %s", inet6_ntoa(to->sin6_addr)); else zlog_debug ("RIPng update routes on interface %s", ifp->name); } /* Get RIPng interface. */ ri = ifp->info; ripng_rte_list = ripng_rte_new(); for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((rinfo = rp->info) != NULL && rinfo->suppress == 0) { /* If no route-map are applied, the RTE will be these following * informations. */ p = (struct prefix_ipv6 *) &rp->p; rinfo->metric_out = rinfo->metric; rinfo->tag_out = rinfo->tag; memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out)); /* In order to avoid some local loops, * if the RIPng route has a nexthop via this interface, keep the nexthop, * otherwise set it to 0. The nexthop should not be propagated * beyond the local broadcast/multicast area in order * to avoid an IGP multi-level recursive look-up. */ if (rinfo->ifindex == ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; /* Apply output filters. */ ret = ripng_outgoing_filter (p, ri); if (ret < 0) continue; /* Changed route only output. */ if (route_type == ripng_changed_route && (! (rinfo->flags & RIPNG_RTF_CHANGED))) continue; /* Split horizon. */ if (ri->split_horizon == RIPNG_SPLIT_HORIZON) { /* We perform split horizon for RIPng routes. */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && rinfo->ifindex == ifp->ifindex) continue; } /* Preparation for route-map. */ rinfo->metric_set = 0; /* nexthop_out, * metric_out * and tag_out are already initialized. */ /* Interface route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], (struct prefix *) p, RMAP_RIPNG, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map out", inet6_ntoa (p->prefix), p->prefixlen); continue; } } /* Redistribute route-map. */ if (ripng->route_map[rinfo->type].name) { int ret; ret = route_map_apply (ripng->route_map[rinfo->type].map, (struct prefix *) p, RMAP_RIPNG, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map", inet6_ntoa (p->prefix), p->prefixlen); continue; } } /* When the route-map does not set metric. */ if (! rinfo->metric_set) { /* If the redistribute metric is set. */ if (ripng->route_map[rinfo->type].metric_config && rinfo->metric != RIPNG_METRIC_INFINITY) { rinfo->metric_out = ripng->route_map[rinfo->type].metric; } else { /* If the route is not connected or localy generated one, use default-metric value */ if (rinfo->type != ZEBRA_ROUTE_RIPNG && rinfo->type != ZEBRA_ROUTE_CONNECT && rinfo->metric != RIPNG_METRIC_INFINITY) rinfo->metric_out = ripng->default_metric; } } /* Apply offset-list */ if (rinfo->metric_out != RIPNG_METRIC_INFINITY) ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out); if (rinfo->metric_out > RIPNG_METRIC_INFINITY) rinfo->metric_out = RIPNG_METRIC_INFINITY; /* Perform split-horizon with poisoned reverse * for RIPng routes. **/ if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) { if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && rinfo->ifindex == ifp->ifindex) rinfo->metric_out = RIPNG_METRIC_INFINITY; } /* Add RTE to the list */ ripng_rte_add(ripng_rte_list, p, rinfo, NULL); } /* Process the aggregated RTE entry */ if ((aggregate = rp->aggregate) != NULL && aggregate->count > 0 && aggregate->suppress == 0) { /* If no route-map are applied, the RTE will be these following * informations. */ p = (struct prefix_ipv6 *) &rp->p; aggregate->metric_set = 0; aggregate->metric_out = aggregate->metric; aggregate->tag_out = aggregate->tag; memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out)); /* Apply output filters.*/ ret = ripng_outgoing_filter (p, ri); if (ret < 0) continue; /* Interface route-map */ if (ri->routemap[RIPNG_FILTER_OUT]) { int ret; struct ripng_info newinfo; /* let's cast the aggregate structure to ripng_info */ memset (&newinfo, 0, sizeof (struct ripng_info)); /* the nexthop is :: */ newinfo.metric = aggregate->metric; newinfo.metric_out = aggregate->metric_out; newinfo.tag = aggregate->tag; newinfo.tag_out = aggregate->tag_out; ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], (struct prefix *) p, RMAP_RIPNG, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) zlog_debug ("RIPng %s/%d is filtered by route-map out", inet6_ntoa (p->prefix), p->prefixlen); continue; } aggregate->metric_out = newinfo.metric_out; aggregate->tag_out = newinfo.tag_out; if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out)) aggregate->nexthop_out = newinfo.nexthop_out; } /* There is no redistribute routemap for the aggregated RTE */ /* Changed route only output. */ /* XXX, vincent, in order to increase time convergence, * it should be announced if a child has changed. */ if (route_type == ripng_changed_route) continue; /* Apply offset-list */ if (aggregate->metric_out != RIPNG_METRIC_INFINITY) ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out); if (aggregate->metric_out > RIPNG_METRIC_INFINITY) aggregate->metric_out = RIPNG_METRIC_INFINITY; /* Add RTE to the list */ ripng_rte_add(ripng_rte_list, p, NULL, aggregate); } } /* Flush the list */ ripng_rte_send(ripng_rte_list, ifp, to); ripng_rte_free(ripng_rte_list); } /* Create new RIPng instance and set it to global variable. */ static int ripng_create (void) { /* ripng should be NULL. */ assert (ripng == NULL); /* Allocaste RIPng instance. */ ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng)); /* Default version and timer values. */ ripng->version = RIPNG_V1; ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; /* Make buffer. */ ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5); ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE); /* Initialize RIPng routig table. */ ripng->table = route_table_init (); ripng->route = route_table_init (); ripng->aggregate = route_table_init (); /* Make socket. */ ripng->sock = ripng_make_socket (); if (ripng->sock < 0) return ripng->sock; /* Threads. */ ripng_event (RIPNG_READ, ripng->sock); ripng_event (RIPNG_UPDATE_EVENT, 1); return 0; } /* Send RIPng request to the interface. */ int ripng_request (struct interface *ifp) { struct rte *rte; struct ripng_packet ripng_packet; /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ if (if_is_loopback(ifp)) return 0; /* If interface is down, don't send RIP packet. */ if (! if_is_up (ifp)) return 0; if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng send request to %s", ifp->name); memset (&ripng_packet, 0, sizeof (ripng_packet)); ripng_packet.command = RIPNG_REQUEST; ripng_packet.version = RIPNG_V1; rte = ripng_packet.rte; rte->metric = RIPNG_METRIC_INFINITY; return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet), NULL, ifp); } static int ripng_update_jitter (int time) { return ((rand () % (time + 1)) - (time / 2)); } void ripng_event (enum ripng_event event, int sock) { int jitter = 0; switch (event) { case RIPNG_READ: if (!ripng->t_read) ripng->t_read = thread_add_read (master, ripng_read, NULL, sock); break; case RIPNG_UPDATE_EVENT: if (ripng->t_update) { thread_cancel (ripng->t_update); ripng->t_update = NULL; } /* Update timer jitter. */ jitter = ripng_update_jitter (ripng->update_time); ripng->t_update = thread_add_timer (master, ripng_update, NULL, sock ? 2 : ripng->update_time + jitter); break; case RIPNG_TRIGGERED_UPDATE: if (ripng->t_triggered_interval) ripng->trigger = 1; else if (! ripng->t_triggered_update) ripng->t_triggered_update = thread_add_event (master, ripng_triggered_update, NULL, 0); break; default: break; } } /* Print out routes update time. */ static void ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo) { time_t clock; struct tm *tm; #define TIME_BUF 25 char timebuf [TIME_BUF]; struct thread *thread; if ((thread = rinfo->t_timeout) != NULL) { clock = thread_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } else if ((thread = rinfo->t_garbage_collect) != NULL) { clock = thread_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } } static char * ripng_route_subtype_print (struct ripng_info *rinfo) { static char str[3]; memset(str, 0, 3); if (rinfo->suppress) strcat(str, "S"); switch (rinfo->sub_type) { case RIPNG_ROUTE_RTE: strcat(str, "n"); break; case RIPNG_ROUTE_STATIC: strcat(str, "s"); break; case RIPNG_ROUTE_DEFAULT: strcat(str, "d"); break; case RIPNG_ROUTE_REDISTRIBUTE: strcat(str, "r"); break; case RIPNG_ROUTE_INTERFACE: strcat(str, "i"); break; default: strcat(str, "?"); break; } return str; } DEFUN (show_ipv6_ripng, show_ipv6_ripng_cmd, "show ipv6 ripng", SHOW_STR IPV6_STR "Show RIPng routes\n") { struct route_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; struct prefix_ipv6 *p; int len; if (! ripng) return CMD_SUCCESS; /* Header of display. */ vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s" "Sub-codes:%s" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" " (i) - interface, (a/S) - aggregated/Suppressed%s%s" " Network Next Hop Via Metric Tag Time%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((aggregate = rp->aggregate) != NULL) { p = (struct prefix_ipv6 *) &rp->p; #ifdef DEBUG len = vty_out (vty, "R(a) %d/%d %s/%d ", aggregate->count, aggregate->suppress, inet6_ntoa (p->prefix), p->prefixlen); #else len = vty_out (vty, "R(a) %s/%d ", inet6_ntoa (p->prefix), p->prefixlen); #endif /* DEBUG */ vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%*s", 18, " "); vty_out (vty, "%*s", 28, " "); vty_out (vty, "self %2d %3d%s", aggregate->metric, aggregate->tag, VTY_NEWLINE); } if ((rinfo = rp->info) != NULL) { p = (struct prefix_ipv6 *) &rp->p; #ifdef DEBUG len = vty_out (vty, "%c(%s) 0/%d %s/%d ", zebra_route_char(rinfo->type), ripng_route_subtype_print(rinfo), rinfo->suppress, inet6_ntoa (p->prefix), p->prefixlen); #else len = vty_out (vty, "%c(%s) %s/%d ", zebra_route_char(rinfo->type), ripng_route_subtype_print(rinfo), inet6_ntoa (p->prefix), p->prefixlen); #endif /* DEBUG */ vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%*s", 18, " "); len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop)); len = 28 - len; if (len > 0) len = vty_out (vty, "%*s", len, " "); /* from */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) { len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex)); } else if (rinfo->metric == RIPNG_METRIC_INFINITY) { len = vty_out (vty, "kill"); } else len = vty_out (vty, "self"); len = 9 - len; if (len > 0) vty_out (vty, "%*s", len, " "); vty_out (vty, " %2d %3d ", rinfo->metric, rinfo->tag); /* time */ if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) { /* RTE from remote RIP routers */ ripng_vty_out_uptime (vty, rinfo); } else if (rinfo->metric == RIPNG_METRIC_INFINITY) { /* poisonous reversed routes (gc) */ ripng_vty_out_uptime (vty, rinfo); } vty_out (vty, "%s", VTY_NEWLINE); } } return CMD_SUCCESS; } DEFUN (show_ipv6_ripng_status, show_ipv6_ripng_status_cmd, "show ipv6 ripng status", SHOW_STR IPV6_STR "Show RIPng routes\n" "IPv6 routing protocol process parameters and statistics\n") { struct listnode *node; struct interface *ifp; if (! ripng) return CMD_SUCCESS; vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE); vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", ripng->update_time); vty_out (vty, " next due in %lu seconds%s", thread_timer_remain_second (ripng->t_update), VTY_NEWLINE); vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time); vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time, VTY_NEWLINE); /* Filtering status show. */ config_show_distribute (vty); /* Default metric information. */ vty_out (vty, " Default redistribution metric is %d%s", ripng->default_metric, VTY_NEWLINE); /* Redistribute information. */ vty_out (vty, " Redistributing:"); ripng_redistribute_write (vty, 0); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Default version control: send version %d,", ripng->version); vty_out (vty, " receive version %d %s", ripng->version, VTY_NEWLINE); vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct ripng_interface *ri; ri = ifp->info; if (ri->enable_network || ri->enable_interface) { vty_out (vty, " %-17s%-3d %-3d%s", ifp->name, ripng->version, ripng->version, VTY_NEWLINE); } } vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); ripng_network_write (vty, 0); vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); ripng_peer_display (vty); return CMD_SUCCESS; } DEFUN (router_ripng, router_ripng_cmd, "router ripng", "Enable a routing process\n" "Make RIPng instance command\n") { int ret; vty->node = RIPNG_NODE; if (!ripng) { ret = ripng_create (); /* Notice to user we couldn't create RIPng. */ if (ret < 0) { zlog_warn ("can't create RIPng"); return CMD_WARNING; } } return CMD_SUCCESS; } DEFUN (no_router_ripng, no_router_ripng_cmd, "no router ripng", NO_STR "Enable a routing process\n" "Make RIPng instance command\n") { if(ripng) ripng_clean(); return CMD_SUCCESS; } DEFUN (ripng_route, ripng_route_cmd, "route IPV6ADDR", "Static route setup\n" "Set static RIPng route announcement\n") { int ret; struct prefix_ipv6 p; struct route_node *rp; ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); if (ret <= 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&p); rp = route_node_get (ripng->route, (struct prefix *) &p); if (rp->info) { vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); route_unlock_node (rp); return CMD_WARNING; } rp->info = (void *)1; ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL); return CMD_SUCCESS; } DEFUN (no_ripng_route, no_ripng_route_cmd, "no route IPV6ADDR", NO_STR "Static route setup\n" "Delete static RIPng route announcement\n") { int ret; struct prefix_ipv6 p; struct route_node *rp; ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); if (ret <= 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&p); rp = route_node_lookup (ripng->route, (struct prefix *) &p); if (! rp) { vty_out (vty, "Can't find static route.%s", VTY_NEWLINE); return CMD_WARNING; } ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); route_unlock_node (rp); rp->info = NULL; route_unlock_node (rp); return CMD_SUCCESS; } DEFUN (ripng_aggregate_address, ripng_aggregate_address_cmd, "aggregate-address X:X::X:X/M", "Set aggregate RIPng route announcement\n" "Aggregate network\n") { int ret; struct prefix p; struct route_node *node; ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p); if (ret <= 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } /* Check aggregate alredy exist or not. */ node = route_node_get (ripng->aggregate, &p); if (node->info) { vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE); route_unlock_node (node); return CMD_WARNING; } node->info = (void *)1; ripng_aggregate_add (&p); return CMD_SUCCESS; } DEFUN (no_ripng_aggregate_address, no_ripng_aggregate_address_cmd, "no aggregate-address X:X::X:X/M", NO_STR "Delete aggregate RIPng route announcement\n" "Aggregate network") { int ret; struct prefix p; struct route_node *rn; ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p); if (ret <= 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } rn = route_node_lookup (ripng->aggregate, &p); if (! rn) { vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE); return CMD_WARNING; } route_unlock_node (rn); rn->info = NULL; route_unlock_node (rn); ripng_aggregate_delete (&p); return CMD_SUCCESS; } DEFUN (ripng_default_metric, ripng_default_metric_cmd, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") { if (ripng) { ripng->default_metric = atoi (argv[0]); } return CMD_SUCCESS; } DEFUN (no_ripng_default_metric, no_ripng_default_metric_cmd, "no default-metric", NO_STR "Set a metric of redistribute routes\n" "Default metric\n") { if (ripng) { ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT; } return CMD_SUCCESS; } ALIAS (no_ripng_default_metric, no_ripng_default_metric_val_cmd, "no default-metric <1-16>", NO_STR "Set a metric of redistribute routes\n" "Default metric\n") #if 0 /* RIPng update timer setup. */ DEFUN (ripng_update_timer, ripng_update_timer_cmd, "update-timer SECOND", "Set RIPng update timer in seconds\n" "Seconds\n") { unsigned long update; char *endptr = NULL; update = strtoul (argv[0], &endptr, 10); if (update == ULONG_MAX || *endptr != '\0') { vty_out (vty, "update timer value error%s", VTY_NEWLINE); return CMD_WARNING; } ripng->update_time = update; ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } DEFUN (no_ripng_update_timer, no_ripng_update_timer_cmd, "no update-timer SECOND", NO_STR "Unset RIPng update timer in seconds\n" "Seconds\n") { ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } /* RIPng timeout timer setup. */ DEFUN (ripng_timeout_timer, ripng_timeout_timer_cmd, "timeout-timer SECOND", "Set RIPng timeout timer in seconds\n" "Seconds\n") { unsigned long timeout; char *endptr = NULL; timeout = strtoul (argv[0], &endptr, 10); if (timeout == ULONG_MAX || *endptr != '\0') { vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); return CMD_WARNING; } ripng->timeout_time = timeout; return CMD_SUCCESS; } DEFUN (no_ripng_timeout_timer, no_ripng_timeout_timer_cmd, "no timeout-timer SECOND", NO_STR "Unset RIPng timeout timer in seconds\n" "Seconds\n") { ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; return CMD_SUCCESS; } /* RIPng garbage timer setup. */ DEFUN (ripng_garbage_timer, ripng_garbage_timer_cmd, "garbage-timer SECOND", "Set RIPng garbage timer in seconds\n" "Seconds\n") { unsigned long garbage; char *endptr = NULL; garbage = strtoul (argv[0], &endptr, 10); if (garbage == ULONG_MAX || *endptr != '\0') { vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); return CMD_WARNING; } ripng->garbage_time = garbage; return CMD_SUCCESS; } DEFUN (no_ripng_garbage_timer, no_ripng_garbage_timer_cmd, "no garbage-timer SECOND", NO_STR "Unset RIPng garbage timer in seconds\n" "Seconds\n") { ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; return CMD_SUCCESS; } #endif /* 0 */ DEFUN (ripng_timers, ripng_timers_cmd, "timers basic <0-65535> <0-65535> <0-65535>", "RIPng timers setup\n" "Basic timer\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") { unsigned long update; unsigned long timeout; unsigned long garbage; VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535); VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535); VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535); /* Set each timer value. */ ripng->update_time = update; ripng->timeout_time = timeout; ripng->garbage_time = garbage; /* Reset update timer thread. */ ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } DEFUN (no_ripng_timers, no_ripng_timers_cmd, "no timers basic", NO_STR "RIPng timers setup\n" "Basic timer\n") { /* Set each timer value to the default. */ ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT; ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT; ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT; /* Reset update timer thread. */ ripng_event (RIPNG_UPDATE_EVENT, 0); return CMD_SUCCESS; } ALIAS (no_ripng_timers, no_ripng_timers_val_cmd, "no timers basic <0-65535> <0-65535> <0-65535>", NO_STR "RIPng timers setup\n" "Basic timer\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd, "show ipv6 protocols", SHOW_STR IPV6_STR "Routing protocol information") { if (! ripng) return CMD_SUCCESS; vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE); vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s", ripng->update_time, 0, VTY_NEWLINE); vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s", ripng->timeout_time, ripng->garbage_time, VTY_NEWLINE); vty_out (vty, "Outgoing update filter list for all interfaces is not set"); vty_out (vty, "Incoming update filter list for all interfaces is not set"); return CMD_SUCCESS; } /* Please be carefull to use this command. */ DEFUN (ripng_default_information_originate, ripng_default_information_originate_cmd, "default-information originate", "Default route information\n" "Distribute default route\n") { struct prefix_ipv6 p; if (! ripng ->default_information) { ripng->default_information = 1; str2prefix_ipv6 ("::/0", &p); ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL); } return CMD_SUCCESS; } DEFUN (no_ripng_default_information_originate, no_ripng_default_information_originate_cmd, "no default-information originate", NO_STR "Default route information\n" "Distribute default route\n") { struct prefix_ipv6 p; if (ripng->default_information) { ripng->default_information = 0; str2prefix_ipv6 ("::/0", &p); ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0); } return CMD_SUCCESS; } /* RIPng configuration write function. */ static int ripng_config_write (struct vty *vty) { int ripng_network_write (struct vty *, int); void ripng_redistribute_write (struct vty *, int); int write = 0; struct route_node *rp; if (ripng) { /* RIPng router. */ vty_out (vty, "router ripng%s", VTY_NEWLINE); if (ripng->default_information) vty_out (vty, " default-information originate%s", VTY_NEWLINE); ripng_network_write (vty, 1); /* RIPng default metric configuration */ if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT) vty_out (vty, " default-metric %d%s", ripng->default_metric, VTY_NEWLINE); ripng_redistribute_write (vty, 1); /* RIP offset-list configuration. */ config_write_ripng_offset_list (vty); /* RIPng aggregate routes. */ for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp)) if (rp->info != NULL) vty_out (vty, " aggregate-address %s/%d%s", inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, VTY_NEWLINE); /* RIPng static routes. */ for (rp = route_top (ripng->route); rp; rp = route_next (rp)) if (rp->info != NULL) vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6), rp->p.prefixlen, VTY_NEWLINE); /* RIPng timers configuration. */ if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT || ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT || ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) { vty_out (vty, " timers basic %ld %ld %ld%s", ripng->update_time, ripng->timeout_time, ripng->garbage_time, VTY_NEWLINE); } #if 0 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT) vty_out (vty, " update-timer %d%s", ripng->update_time, VTY_NEWLINE); if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT) vty_out (vty, " timeout-timer %d%s", ripng->timeout_time, VTY_NEWLINE); if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT) vty_out (vty, " garbage-timer %d%s", ripng->garbage_time, VTY_NEWLINE); #endif /* 0 */ write += config_write_distribute (vty); write += config_write_if_rmap (vty); write++; } return write; } /* RIPng node structure. */ static struct cmd_node cmd_ripng_node = { RIPNG_NODE, "%s(config-router)# ", 1, }; static void ripng_distribute_update (struct distribute *dist) { struct interface *ifp; struct ripng_interface *ri; struct access_list *alist; struct prefix_list *plist; if (! dist->ifname) return; ifp = if_lookup_by_name (dist->ifname); if (ifp == NULL) return; ri = ifp->info; if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); if (alist) ri->list[RIPNG_FILTER_IN] = alist; else ri->list[RIPNG_FILTER_IN] = NULL; } else ri->list[RIPNG_FILTER_IN] = NULL; if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); if (alist) ri->list[RIPNG_FILTER_OUT] = alist; else ri->list[RIPNG_FILTER_OUT] = NULL; } else ri->list[RIPNG_FILTER_OUT] = NULL; if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); if (plist) ri->prefix[RIPNG_FILTER_IN] = plist; else ri->prefix[RIPNG_FILTER_IN] = NULL; } else ri->prefix[RIPNG_FILTER_IN] = NULL; if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); if (plist) ri->prefix[RIPNG_FILTER_OUT] = plist; else ri->prefix[RIPNG_FILTER_OUT] = NULL; } else ri->prefix[RIPNG_FILTER_OUT] = NULL; } void ripng_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) ripng_distribute_update (dist); } /* Update all interface's distribute list. */ static void ripng_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_distribute_update_interface (ifp); } static void ripng_distribute_update_all_wrapper (struct access_list *notused) { ripng_distribute_update_all(NULL); } /* delete all the added ripng routes. */ void ripng_clean() { int i; struct route_node *rp; struct ripng_info *rinfo; if (ripng) { /* Clear RIPng routes */ for (rp = route_top (ripng->table); rp; rp = route_next (rp)) { if ((rinfo = rp->info) != NULL) { if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && (rinfo->sub_type == RIPNG_ROUTE_RTE)) ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop, rinfo->metric); RIPNG_TIMER_OFF (rinfo->t_timeout); RIPNG_TIMER_OFF (rinfo->t_garbage_collect); rp->info = NULL; route_unlock_node (rp); ripng_info_free(rinfo); } } /* Cancel the RIPng timers */ RIPNG_TIMER_OFF (ripng->t_update); RIPNG_TIMER_OFF (ripng->t_triggered_update); RIPNG_TIMER_OFF (ripng->t_triggered_interval); /* Cancel the read thread */ if (ripng->t_read) { thread_cancel (ripng->t_read); ripng->t_read = NULL; } /* Close the RIPng socket */ if (ripng->sock >= 0) { close(ripng->sock); ripng->sock = -1; } /* Static RIPng route configuration. */ for (rp = route_top (ripng->route); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* RIPng aggregated prefixes */ for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (ripng->route_map[i].name) free (ripng->route_map[i].name); XFREE (MTYPE_ROUTE_TABLE, ripng->table); XFREE (MTYPE_ROUTE_TABLE, ripng->route); XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate); XFREE (MTYPE_RIPNG, ripng); ripng = NULL; } /* if (ripng) */ ripng_clean_network(); ripng_passive_interface_clean (); ripng_offset_clean (); ripng_interface_clean (); ripng_redistribute_clean (); } /* Reset all values to the default settings. */ void ripng_reset () { /* Call ripd related reset functions. */ ripng_debug_reset (); ripng_route_map_reset (); /* Call library reset functions. */ vty_reset (); access_list_reset (); prefix_list_reset (); distribute_list_reset (); ripng_interface_reset (); ripng_zclient_reset (); } static void ripng_if_rmap_update (struct if_rmap *if_rmap) { struct interface *ifp; struct ripng_interface *ri; struct route_map *rmap; ifp = if_lookup_by_name (if_rmap->ifname); if (ifp == NULL) return; ri = ifp->info; if (if_rmap->routemap[IF_RMAP_IN]) { rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); if (rmap) ri->routemap[IF_RMAP_IN] = rmap; else ri->routemap[IF_RMAP_IN] = NULL; } else ri->routemap[RIPNG_FILTER_IN] = NULL; if (if_rmap->routemap[IF_RMAP_OUT]) { rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); if (rmap) ri->routemap[IF_RMAP_OUT] = rmap; else ri->routemap[IF_RMAP_OUT] = NULL; } else ri->routemap[RIPNG_FILTER_OUT] = NULL; } void ripng_if_rmap_update_interface (struct interface *ifp) { struct if_rmap *if_rmap; if_rmap = if_rmap_lookup (ifp->name); if (if_rmap) ripng_if_rmap_update (if_rmap); } static void ripng_routemap_update_redistribute (void) { int i; if (ripng) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (ripng->route_map[i].name) ripng->route_map[i].map = route_map_lookup_by_name (ripng->route_map[i].name); } } } static void ripng_routemap_update (const char *unused) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_if_rmap_update_interface (ifp); ripng_routemap_update_redistribute (); } /* Initialize ripng structure and set commands. */ void ripng_init () { /* Randomize. */ srand (time (NULL)); /* Install RIPNG_NODE. */ install_node (&cmd_ripng_node, ripng_config_write); /* Install ripng commands. */ install_element (VIEW_NODE, &show_ipv6_ripng_cmd); install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd); install_element (ENABLE_NODE, &show_ipv6_ripng_cmd); install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd); install_element (CONFIG_NODE, &router_ripng_cmd); install_element (CONFIG_NODE, &no_router_ripng_cmd); install_default (RIPNG_NODE); install_element (RIPNG_NODE, &ripng_route_cmd); install_element (RIPNG_NODE, &no_ripng_route_cmd); install_element (RIPNG_NODE, &ripng_aggregate_address_cmd); install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd); install_element (RIPNG_NODE, &ripng_default_metric_cmd); install_element (RIPNG_NODE, &no_ripng_default_metric_cmd); install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd); install_element (RIPNG_NODE, &ripng_timers_cmd); install_element (RIPNG_NODE, &no_ripng_timers_cmd); install_element (RIPNG_NODE, &no_ripng_timers_val_cmd); #if 0 install_element (RIPNG_NODE, &ripng_update_timer_cmd); install_element (RIPNG_NODE, &no_ripng_update_timer_cmd); install_element (RIPNG_NODE, &ripng_timeout_timer_cmd); install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd); install_element (RIPNG_NODE, &ripng_garbage_timer_cmd); install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd); #endif /* 0 */ install_element (RIPNG_NODE, &ripng_default_information_originate_cmd); install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd); ripng_if_init (); ripng_debug_init (); /* Access list install. */ access_list_init (); access_list_add_hook (ripng_distribute_update_all_wrapper); access_list_delete_hook (ripng_distribute_update_all_wrapper); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (ripng_distribute_update_all); prefix_list_delete_hook (ripng_distribute_update_all); /* Distribute list install. */ distribute_list_init (RIPNG_NODE); distribute_list_add_hook (ripng_distribute_update); distribute_list_delete_hook (ripng_distribute_update); /* Route-map for interface. */ ripng_route_map_init (); ripng_offset_init (); route_map_add_hook (ripng_routemap_update); route_map_delete_hook (ripng_routemap_update); if_rmap_init (RIPNG_NODE); if_rmap_hook_add (ripng_if_rmap_update); if_rmap_hook_delete (ripng_if_rmap_update); } quagga-0.99.24.1/ripngd/ripng_interface.c0000644000175000017500000007251412476520570015033 00000000000000/* * Interface related function for RIPng. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "linklist.h" #include "if.h" #include "prefix.h" #include "memory.h" #include "network.h" #include "filter.h" #include "log.h" #include "stream.h" #include "zclient.h" #include "command.h" #include "table.h" #include "thread.h" #include "privs.h" #include "ripngd/ripngd.h" #include "ripngd/ripng_debug.h" /* If RFC2133 definition is used. */ #ifndef IPV6_JOIN_GROUP #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif #ifndef IPV6_LEAVE_GROUP #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif extern struct zebra_privs_t ripngd_privs; /* Static utility function. */ static void ripng_enable_apply (struct interface *); static void ripng_passive_interface_apply (struct interface *); static int ripng_enable_if_lookup (const char *); static int ripng_enable_network_lookup2 (struct connected *); static void ripng_enable_apply_all (void); /* Join to the all rip routers multicast group. */ static int ripng_multicast_join (struct interface *ifp) { int ret; struct ipv6_mreq mreq; int save_errno; if (if_is_up (ifp) && if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; /* * NetBSD 1.6.2 requires root to join groups on gif(4). * While this is bogus, privs are available and easy to use * for this call as a workaround. */ if (ripngd_privs.change (ZPRIVS_RAISE)) zlog_err ("ripng_multicast_join: could not raise privs"); ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreq, sizeof (mreq)); save_errno = errno; if (ripngd_privs.change (ZPRIVS_LOWER)) zlog_err ("ripng_multicast_join: could not lower privs"); if (ret < 0 && save_errno == EADDRINUSE) { /* * Group is already joined. This occurs due to sloppy group * management, in particular declining to leave the group on * an interface that has just gone down. */ zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); return 0; /* not an error */ } if (ret < 0) zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (save_errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* Leave from the all rip routers multicast group. */ static int ripng_multicast_leave (struct interface *ifp) { int ret; struct ipv6_mreq mreq; if (if_is_up (ifp) && if_is_multicast (ifp)) { memset (&mreq, 0, sizeof (mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &mreq, sizeof (mreq)); if (ret < 0) zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng %s leave from all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* How many link local IPv6 address could be used on the interface ? */ static int ripng_if_ipv6_lladdress_check (struct interface *ifp) { struct listnode *nn; struct connected *connected; int count = 0; for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected)) { struct prefix *p; p = connected->address; if ((p->family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6)) count++; } return count; } static int ripng_if_down (struct interface *ifp) { struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; if (ripng) { for (rp = route_top (ripng->table); rp; rp = route_next (rp)) if ((rinfo = rp->info) != NULL) { /* Routes got through this interface. */ if (rinfo->ifindex == ifp->ifindex && rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE) { ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, &rinfo->nexthop, rinfo->ifindex); ripng_redistribute_delete (rinfo->type, rinfo->sub_type, (struct prefix_ipv6 *)&rp->p, rinfo->ifindex); } else { /* All redistributed routes got through this interface, * but the static and system ones are kept. */ if ((rinfo->ifindex == ifp->ifindex) && (rinfo->type != ZEBRA_ROUTE_STATIC) && (rinfo->type != ZEBRA_ROUTE_SYSTEM)) ripng_redistribute_delete (rinfo->type, rinfo->sub_type, (struct prefix_ipv6 *) &rp->p, rinfo->ifindex); } } } ri = ifp->info; if (ri->running) { if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("turn off %s", ifp->name); /* Leave from multicast group. */ ripng_multicast_leave (ifp); ri->running = 0; } return 0; } /* Inteface link up message processing. */ int ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* Check if this interface is RIPng enabled or not. */ ripng_enable_apply (ifp); /* Check for a passive interface. */ ripng_passive_interface_apply (ifp); /* Apply distribute list to the all interface. */ ripng_distribute_update_interface (ifp); return 0; } /* Inteface link down message processing. */ int ripng_interface_down (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (ifp == NULL) return 0; ripng_if_down (ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); return 0; } /* Inteface addition message from zebra. */ int ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); /* Check is this interface is RIP enabled or not.*/ ripng_enable_apply (ifp); /* Apply distribute list to the interface. */ ripng_distribute_update_interface (ifp); /* Check interface routemap. */ ripng_if_rmap_update_interface (ifp); return 0; } int ripng_interface_delete (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; if (if_is_up (ifp)) { ripng_if_down(ifp); } zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } void ripng_interface_clean (void) { struct listnode *node, *nnode; struct interface *ifp; struct ripng_interface *ri; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } } } void ripng_interface_reset (void) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; ri->list[RIPNG_FILTER_IN] = NULL; ri->list[RIPNG_FILTER_OUT] = NULL; ri->prefix[RIPNG_FILTER_IN] = NULL; ri->prefix[RIPNG_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } ri->passive = 0; } } static void ripng_apply_address_add (struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || (ripng_enable_network_lookup2(ifc) >= 0)) ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL); } int ripng_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *c; struct prefix *p; c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (c == NULL) return 0; p = c->address; if (p->family == AF_INET6) { struct ripng_interface *ri = c->ifp->info; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng connected address %s/%d add", inet6_ntoa(p->u.prefix6), p->prefixlen); /* Check is this prefix needs to be redistributed. */ ripng_apply_address_add(c); /* Let's try once again whether the interface could be activated */ if (!ri->running) { /* Check if this interface is RIP enabled or not.*/ ripng_enable_apply (c->ifp); /* Apply distribute list to the interface. */ ripng_distribute_update_interface (c->ifp); /* Check interface routemap. */ ripng_if_rmap_update_interface (c->ifp); } } return 0; } static void ripng_apply_address_del (struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex); } int ripng_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; struct prefix *p; char buf[INET6_ADDRSTRLEN]; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); if (ifc) { p = ifc->address; if (p->family == AF_INET6) { if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug ("RIPng connected address %s/%d delete", inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN), p->prefixlen); /* Check wether this prefix needs to be removed. */ ripng_apply_address_del(ifc); } connected_free (ifc); } return 0; } /* RIPng enable interface vector. */ vector ripng_enable_if; /* RIPng enable network table. */ struct route_table *ripng_enable_network; /* Lookup RIPng enable network. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ static int ripng_enable_network_lookup_if (struct interface *ifp) { struct listnode *node; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { struct prefix *p; struct route_node *node; p = connected->address; if (p->family == AF_INET6) { address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; node = route_node_match (ripng_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } } return -1; } /* Check wether connected is within the ripng_enable_network table. */ static int ripng_enable_network_lookup2 (struct connected *connected) { struct prefix_ipv6 address; struct prefix *p; p = connected->address; if (p->family == AF_INET6) { struct route_node *node; address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */ node = route_node_match (ripng_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } return -1; } /* Add RIPng enable network. */ static int ripng_enable_network_add (struct prefix *p) { struct route_node *node; node = route_node_get (ripng_enable_network, p); if (node->info) { route_unlock_node (node); return -1; } else node->info = (char *) "enabled"; /* XXX: One should find a better solution than a generic one */ ripng_enable_apply_all(); return 1; } /* Delete RIPng enable network. */ static int ripng_enable_network_delete (struct prefix *p) { struct route_node *node; node = route_node_lookup (ripng_enable_network, p); if (node) { node->info = NULL; /* Unlock info lock. */ route_unlock_node (node); /* Unlock lookup lock. */ route_unlock_node (node); return 1; } return -1; } /* Lookup function. */ static int ripng_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (ripng_enable_if); i++) if ((str = vector_slot (ripng_enable_if, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } /* Add interface to ripng_enable_if. */ static int ripng_enable_if_add (const char *ifname) { int ret; ret = ripng_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (ripng_enable_if, strdup (ifname)); ripng_enable_apply_all(); return 1; } /* Delete interface from ripng_enable_if. */ static int ripng_enable_if_delete (const char *ifname) { int index; char *str; index = ripng_enable_if_lookup (ifname); if (index < 0) return -1; str = vector_slot (ripng_enable_if, index); free (str); vector_unset (ripng_enable_if, index); ripng_enable_apply_all(); return 1; } /* Wake up interface. */ static int ripng_interface_wakeup (struct thread *t) { struct interface *ifp; struct ripng_interface *ri; /* Get interface. */ ifp = THREAD_ARG (t); ri = ifp->info; ri->t_wakeup = NULL; /* Join to multicast group. */ if (ripng_multicast_join (ifp) < 0) { zlog_err ("multicast join failed, interface %s not running", ifp->name); return 0; } /* Set running flag. */ ri->running = 1; /* Send RIP request to the interface. */ ripng_request (ifp); return 0; } static void ripng_connect_set (struct interface *ifp, int set) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix *p; p = connected->address; if (p->family != AF_INET6) continue; address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6 (&address); if (set) { /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || (ripng_enable_network_lookup2(connected) >= 0)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL); } else { ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex); if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT)) ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, NULL); } } } /* Check RIPng is enabed on this interface. */ void ripng_enable_apply (struct interface *ifp) { int ret; struct ripng_interface *ri = NULL; /* Check interface. */ if (! if_is_up (ifp)) return; ri = ifp->info; /* Is this interface a candidate for RIPng ? */ ret = ripng_enable_network_lookup_if (ifp); /* If the interface is matched. */ if (ret > 0) ri->enable_network = 1; else ri->enable_network = 0; /* Check interface name configuration. */ ret = ripng_enable_if_lookup (ifp->name); if (ret >= 0) ri->enable_interface = 1; else ri->enable_interface = 0; /* any candidate interface MUST have a link-local IPv6 address */ if ((! ripng_if_ipv6_lladdress_check (ifp)) && (ri->enable_network || ri->enable_interface)) { ri->enable_network = 0; ri->enable_interface = 0; zlog_warn("Interface %s does not have any link-local address", ifp->name); } /* Update running status of the interface. */ if (ri->enable_network || ri->enable_interface) { { if (IS_RIPNG_DEBUG_EVENT) zlog_debug ("RIPng turn on %s", ifp->name); /* Add interface wake up thread. */ if (! ri->t_wakeup) ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup, ifp, 1); ripng_connect_set (ifp, 1); } } else { if (ri->running) { /* Might as well clean up the route table as well * ripng_if_down sets to 0 ri->running, and displays "turn off %s" **/ ripng_if_down(ifp); ripng_connect_set (ifp, 0); } } } /* Set distribute list to all interfaces. */ static void ripng_enable_apply_all (void) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_enable_apply (ifp); } /* Clear all network and neighbor configuration */ void ripng_clean_network () { unsigned int i; char *str; struct route_node *rn; /* ripng_enable_network */ for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn)) if (rn->info) { rn->info = NULL; route_unlock_node(rn); } /* ripng_enable_if */ for (i = 0; i < vector_active (ripng_enable_if); i++) if ((str = vector_slot (ripng_enable_if, i)) != NULL) { free (str); vector_slot (ripng_enable_if, i) = NULL; } } /* Vector to store passive-interface name. */ vector Vripng_passive_interface; /* Utility function for looking up passive interface settings. */ static int ripng_passive_interface_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (Vripng_passive_interface); i++) if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } void ripng_passive_interface_apply (struct interface *ifp) { int ret; struct ripng_interface *ri; ri = ifp->info; ret = ripng_passive_interface_lookup (ifp->name); if (ret < 0) ri->passive = 0; else ri->passive = 1; } static void ripng_passive_interface_apply_all (void) { struct interface *ifp; struct listnode *node; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) ripng_passive_interface_apply (ifp); } /* Passive interface. */ static int ripng_passive_interface_set (struct vty *vty, const char *ifname) { if (ripng_passive_interface_lookup (ifname) >= 0) return CMD_WARNING; vector_set (Vripng_passive_interface, strdup (ifname)); ripng_passive_interface_apply_all (); return CMD_SUCCESS; } static int ripng_passive_interface_unset (struct vty *vty, const char *ifname) { int i; char *str; i = ripng_passive_interface_lookup (ifname); if (i < 0) return CMD_WARNING; str = vector_slot (Vripng_passive_interface, i); free (str); vector_unset (Vripng_passive_interface, i); ripng_passive_interface_apply_all (); return CMD_SUCCESS; } /* Free all configured RIP passive-interface settings. */ void ripng_passive_interface_clean (void) { unsigned int i; char *str; for (i = 0; i < vector_active (Vripng_passive_interface); i++) if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) { free (str); vector_slot (Vripng_passive_interface, i) = NULL; } ripng_passive_interface_apply_all (); } /* Write RIPng enable network and interface to the vty. */ int ripng_network_write (struct vty *vty, int config_mode) { unsigned int i; const char *ifname; struct route_node *node; char buf[BUFSIZ]; /* Write enable network. */ for (node = route_top (ripng_enable_network); node; node = route_next (node)) if (node->info) { struct prefix *p = &node->p; vty_out (vty, "%s%s/%d%s", config_mode ? " network " : " ", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, VTY_NEWLINE); } /* Write enable interface. */ for (i = 0; i < vector_active (ripng_enable_if); i++) if ((ifname = vector_slot (ripng_enable_if, i)) != NULL) vty_out (vty, "%s%s%s", config_mode ? " network " : " ", ifname, VTY_NEWLINE); /* Write passive interface. */ if (config_mode) for (i = 0; i < vector_active (Vripng_passive_interface); i++) if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); return 0; } /* RIPng enable on specified interface or matched network. */ DEFUN (ripng_network, ripng_network_cmd, "network IF_OR_ADDR", "RIPng enable on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is IPv6 network or interface name. */ if (ret) ret = ripng_enable_network_add (&p); else ret = ripng_enable_if_add (argv[0]); if (ret < 0) { vty_out (vty, "There is same network configuration %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* RIPng enable on specified interface or matched network. */ DEFUN (no_ripng_network, no_ripng_network_cmd, "no network IF_OR_ADDR", NO_STR "RIPng enable on specified interface or network.\n" "Interface or address") { int ret; struct prefix p; ret = str2prefix (argv[0], &p); /* Given string is interface name. */ if (ret) ret = ripng_enable_network_delete (&p); else ret = ripng_enable_if_delete (argv[0]); if (ret < 0) { vty_out (vty, "can't find network %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon, ipv6_ripng_split_horizon_cmd, "ipv6 ripng split-horizon", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, ipv6_ripng_split_horizon_poisoned_reverse_cmd, "ipv6 ripng split-horizon poisoned-reverse", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; return CMD_SUCCESS; } DEFUN (no_ipv6_ripng_split_horizon, no_ipv6_ripng_split_horizon_cmd, "no ipv6 ripng split-horizon", NO_STR IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct ripng_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; return CMD_SUCCESS; } ALIAS (no_ipv6_ripng_split_horizon, no_ipv6_ripng_split_horizon_poisoned_reverse_cmd, "no ipv6 ripng split-horizon poisoned-reverse", NO_STR IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") DEFUN (ripng_passive_interface, ripng_passive_interface_cmd, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface name\n") { return ripng_passive_interface_set (vty, argv[0]); } DEFUN (no_ripng_passive_interface, no_ripng_passive_interface_cmd, "no passive-interface IFNAME", NO_STR "Suppress routing updates on an interface\n" "Interface name\n") { return ripng_passive_interface_unset (vty, argv[0]); } static struct ripng_interface * ri_new (void) { struct ripng_interface *ri; ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); /* Set default split-horizon behavior. If the interface is Frame Relay or SMDS is enabled, the default value for split-horizon is off. But currently Zebra does detect Frame Relay or SMDS interface. So all interface is set to split horizon. */ ri->split_horizon_default = RIPNG_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; return ri; } static int ripng_if_new_hook (struct interface *ifp) { ifp->info = ri_new (); return 0; } /* Called when interface structure deleted. */ static int ripng_if_delete_hook (struct interface *ifp) { XFREE (MTYPE_IF, ifp->info); ifp->info = NULL; return 0; } /* Configuration write function for ripngd. */ static int interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; struct ripng_interface *ri; int write = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; /* Do not display the interface if there is no * configuration about it. **/ if ((!ifp->desc) && (ri->split_horizon == ri->split_horizon_default)) continue; vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); /* Split horizon. */ if (ri->split_horizon != ri->split_horizon_default) { switch (ri->split_horizon) { case RIPNG_SPLIT_HORIZON: vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE); break; case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s", VTY_NEWLINE); break; case RIPNG_NO_SPLIT_HORIZON: default: vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE); break; } } vty_out (vty, "!%s", VTY_NEWLINE); write++; } return write; } /* ripngd's interface node. */ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; /* Initialization of interface. */ void ripng_if_init () { /* Interface initialize. */ iflist = list_new (); if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook); /* RIPng enable network init. */ ripng_enable_network = route_table_init (); /* RIPng enable interface init. */ ripng_enable_if = vector_init (1); /* RIPng passive interface. */ Vripng_passive_interface = vector_init (1); /* Install interface node. */ install_node (&interface_node, interface_config_write); /* Install commands. */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (RIPNG_NODE, &ripng_network_cmd); install_element (RIPNG_NODE, &no_ripng_network_cmd); install_element (RIPNG_NODE, &ripng_passive_interface_cmd); install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd); } quagga-0.99.24.1/ripngd/ripng_nexthop.h0000644000175000017500000000432212476520570014555 00000000000000/* RIPng nexthop support * Copyright (C) 6WIND Vincent Jardin * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIPNG_RIPNG_NEXTHOP_H #define _ZEBRA_RIPNG_RIPNG_NEXTHOP_H #include #include "linklist.h" #include "ripngd/ripng_route.h" #include "ripngd/ripngd.h" extern struct list * ripng_rte_new(void); extern void ripng_rte_free(struct list *ripng_rte_list); extern void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, struct ripng_info *rinfo, struct ripng_aggregate *aggregate); extern void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, struct sockaddr_in6 *to); /*** * 1 if A > B * 0 if A = B * -1 if A < B **/ static inline int addr6_cmp(struct in6_addr *A, struct in6_addr *B) { #ifndef s6_addr32 #if defined(SUNOS_5) /* Some SunOS define s6_addr32 only to kernel */ #define s6_addr32 _S6_un._S6_u32 #else #define s6_addr32 __u6_addr.__u6_addr32 #endif /* SUNOS_5 */ #endif /*s6_addr32*/ #define a(i) A->s6_addr32[i] #define b(i) B->s6_addr32[i] if (a(3) > b(3)) return 1; else if ((a(3) == b(3)) && (a(2) > b(2))) return 1; else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) > b(1))) return 1; else if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) > b(0))) return 1; if ((a(3) == b(3)) && (a(2) == b(2)) && (a(1) == b(1)) && (a(0) == b(0))) return 0; return -1; } #endif /* _ZEBRA_RIPNG_RIPNG_NEXTHOP_H */ quagga-0.99.24.1/ripngd/ripngd.h0000644000175000017500000002610212476520570013154 00000000000000/* * RIPng related value and structure. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIPNG_RIPNGD_H #define _ZEBRA_RIPNG_RIPNGD_H #include #include /* RIPng version and port number. */ #define RIPNG_V1 1 #define RIPNG_PORT_DEFAULT 521 #define RIPNG_VTY_PORT 2603 #define RIPNG_MAX_PACKET_SIZE 1500 #define RIPNG_PRIORITY_DEFAULT 0 /* RIPng commands. */ #define RIPNG_REQUEST 1 #define RIPNG_RESPONSE 2 /* RIPng metric and multicast group address. */ #define RIPNG_METRIC_INFINITY 16 #define RIPNG_METRIC_NEXTHOP 0xff #define RIPNG_GROUP "ff02::9" /* RIPng timers. */ #define RIPNG_UPDATE_TIMER_DEFAULT 30 #define RIPNG_TIMEOUT_TIMER_DEFAULT 180 #define RIPNG_GARBAGE_TIMER_DEFAULT 120 /* RIPng peer timeout value. */ #define RIPNG_PEER_TIMER_DEFAULT 180 /* Default config file name. */ #define RIPNG_DEFAULT_CONFIG "ripngd.conf" /* RIPng route types. */ #define RIPNG_ROUTE_RTE 0 #define RIPNG_ROUTE_STATIC 1 #define RIPNG_ROUTE_DEFAULT 2 #define RIPNG_ROUTE_REDISTRIBUTE 3 #define RIPNG_ROUTE_INTERFACE 4 #define RIPNG_ROUTE_AGGREGATE 5 /* Interface send/receive configuration. */ #define RIPNG_SEND_UNSPEC 0 #define RIPNG_SEND_OFF 1 #define RIPNG_RECEIVE_UNSPEC 0 #define RIPNG_RECEIVE_OFF 1 /* RIP default route's accept/announce methods. */ #define RIPNG_DEFAULT_ADVERTISE_UNSPEC 0 #define RIPNG_DEFAULT_ADVERTISE_NONE 1 #define RIPNG_DEFAULT_ADVERTISE 2 #define RIPNG_DEFAULT_ACCEPT_UNSPEC 0 #define RIPNG_DEFAULT_ACCEPT_NONE 1 #define RIPNG_DEFAULT_ACCEPT 2 /* Default value for "default-metric" command. */ #define RIPNG_DEFAULT_METRIC_DEFAULT 1 /* For max RTE calculation. */ #ifndef IPV6_HDRLEN #define IPV6_HDRLEN 40 #endif /* IPV6_HDRLEN */ #ifndef IFMINMTU #define IFMINMTU 576 #endif /* IFMINMTU */ /* RIPng structure. */ struct ripng { /* RIPng socket. */ int sock; /* RIPng Parameters.*/ u_char command; u_char version; unsigned long update_time; unsigned long timeout_time; unsigned long garbage_time; int max_mtu; int default_metric; int default_information; /* Input/output buffer of RIPng. */ struct stream *ibuf; struct stream *obuf; /* RIPng routing information base. */ struct route_table *table; /* RIPng only static route information. */ struct route_table *route; /* RIPng aggregate route information. */ struct route_table *aggregate; /* RIPng threads. */ struct thread *t_read; struct thread *t_write; struct thread *t_update; struct thread *t_garbage; struct thread *t_zebra; /* Triggered update hack. */ int trigger; struct thread *t_triggered_update; struct thread *t_triggered_interval; /* For redistribute route map. */ struct { char *name; struct route_map *map; int metric_config; u_int32_t metric; } route_map[ZEBRA_ROUTE_MAX]; }; /* Routing table entry. */ struct rte { struct in6_addr addr; /* RIPng destination prefix */ u_short tag; /* RIPng tag */ u_char prefixlen; /* Length of the RIPng prefix */ u_char metric; /* Metric of the RIPng route */ /* The nexthop is stored by the structure * ripng_nexthop within ripngd.c */ }; /* RIPNG send packet. */ struct ripng_packet { u_char command; u_char version; u_int16_t zero; struct rte rte[1]; }; /* Each route's information. */ struct ripng_info { /* This route's type. Static, ripng or aggregate. */ u_char type; /* Sub type for static route. */ u_char sub_type; /* RIPng specific information */ struct in6_addr nexthop; struct in6_addr from; /* Which interface does this route come from. */ unsigned int ifindex; /* Metric of this route. */ u_char metric; /* Tag field of RIPng packet.*/ u_int16_t tag; /* For aggregation. */ unsigned int suppress; /* Flags of RIPng route. */ #define RIPNG_RTF_FIB 1 #define RIPNG_RTF_CHANGED 2 u_char flags; /* Garbage collect timer. */ struct thread *t_timeout; struct thread *t_garbage_collect; /* Route-map features - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_short tag_out; struct route_node *rp; }; #ifdef notyet #if 0 /* RIPng tag structure. */ struct ripng_tag { /* Tag value. */ u_int16_t tag; /* Port. */ u_int16_t port; /* Multicast group. */ struct in6_addr maddr; /* Table number. */ int table; /* Distance. */ int distance; /* Split horizon. */ u_char split_horizon; /* Poison reverse. */ u_char poison_reverse; }; #endif /* 0 */ #endif /* not yet */ typedef enum { RIPNG_NO_SPLIT_HORIZON = 0, RIPNG_SPLIT_HORIZON, RIPNG_SPLIT_HORIZON_POISONED_REVERSE } split_horizon_policy_t; /* RIPng specific interface configuration. */ struct ripng_interface { /* RIPng is enabled on this interface. */ int enable_network; int enable_interface; /* RIPng is running on this interface. */ int running; /* Split horizon flag. */ split_horizon_policy_t split_horizon; split_horizon_policy_t split_horizon_default; /* For filter type slot. */ #define RIPNG_FILTER_IN 0 #define RIPNG_FILTER_OUT 1 #define RIPNG_FILTER_MAX 2 /* Access-list. */ struct access_list *list[RIPNG_FILTER_MAX]; /* Prefix-list. */ struct prefix_list *prefix[RIPNG_FILTER_MAX]; /* Route-map. */ struct route_map *routemap[RIPNG_FILTER_MAX]; #ifdef notyet #if 0 /* RIPng tag configuration. */ struct ripng_tag *rtag; #endif /* 0 */ #endif /* notyet */ /* Default information originate. */ u_char default_originate; /* Default information only. */ u_char default_only; /* Wake up thread. */ struct thread *t_wakeup; /* Passive interface. */ int passive; }; /* RIPng peer information. */ struct ripng_peer { /* Peer address. */ struct in6_addr addr; /* Peer RIPng tag value. */ int domain; /* Last update time. */ time_t uptime; /* Peer RIP version. */ u_char version; /* Statistics. */ int recv_badpackets; int recv_badroutes; /* Timeout thread. */ struct thread *t_timeout; }; /* All RIPng events. */ enum ripng_event { RIPNG_READ, RIPNG_ZEBRA, RIPNG_REQUEST_EVENT, RIPNG_UPDATE_EVENT, RIPNG_TRIGGERED_UPDATE, }; /* RIPng timer on/off macro. */ #define RIPNG_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), rinfo, (V)); \ } while (0) #define RIPNG_TIMER_OFF(T) \ do { \ if (T) \ { \ thread_cancel(T); \ (T) = NULL; \ } \ } while (0) /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) /* Extern variables. */ extern struct ripng *ripng; extern struct thread_master *master; /* Prototypes. */ extern void ripng_init (void); extern void ripng_reset (void); extern void ripng_clean (void); extern void ripng_clean_network (void); extern void ripng_interface_clean (void); extern void ripng_interface_reset (void); extern void ripng_passive_interface_clean (void); extern void ripng_if_init (void); extern void ripng_route_map_init (void); extern void ripng_route_map_reset (void); extern void ripng_terminate (void); /* zclient_init() is done by ripng_zebra.c:zebra_init() */ extern void zebra_init (void); extern void ripng_zclient_start (void); extern void ripng_zclient_reset (void); extern void ripng_offset_init (void); extern int config_write_ripng_offset_list (struct vty *); extern void ripng_peer_init (void); extern void ripng_peer_update (struct sockaddr_in6 *, u_char); extern void ripng_peer_bad_route (struct sockaddr_in6 *); extern void ripng_peer_bad_packet (struct sockaddr_in6 *); extern void ripng_peer_display (struct vty *); extern struct ripng_peer *ripng_peer_lookup (struct in6_addr *); extern struct ripng_peer *ripng_peer_lookup_next (struct in6_addr *); extern int ripng_offset_list_apply_in (struct prefix_ipv6 *, struct interface *, u_char *); extern int ripng_offset_list_apply_out (struct prefix_ipv6 *, struct interface *, u_char *); extern void ripng_offset_clean (void); extern struct ripng_info * ripng_info_new (void); extern void ripng_info_free (struct ripng_info *rinfo); extern void ripng_event (enum ripng_event, int); extern int ripng_request (struct interface *ifp); extern void ripng_redistribute_add (int, int, struct prefix_ipv6 *, unsigned int, struct in6_addr *); extern void ripng_redistribute_delete (int, int, struct prefix_ipv6 *, unsigned int); extern void ripng_redistribute_withdraw (int type); extern void ripng_distribute_update_interface (struct interface *); extern void ripng_if_rmap_update_interface (struct interface *); extern void ripng_zebra_ipv6_add (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex, u_char metric); extern void ripng_zebra_ipv6_delete (struct prefix_ipv6 *p, struct in6_addr *nexthop, unsigned int ifindex); extern void ripng_redistribute_clean (void); extern int ripng_redistribute_check (int); extern void ripng_redistribute_write (struct vty *, int); extern int ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p, struct in6_addr *nexthop, u_int16_t tag, u_char metric); extern int ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, struct interface *ifp); extern void ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv); extern int ripng_interface_up (int command, struct zclient *, zebra_size_t); extern int ripng_interface_down (int command, struct zclient *, zebra_size_t); extern int ripng_interface_add (int command, struct zclient *, zebra_size_t); extern int ripng_interface_delete (int command, struct zclient *, zebra_size_t); extern int ripng_interface_address_add (int command, struct zclient *, zebra_size_t); extern int ripng_interface_address_delete (int command, struct zclient *, zebra_size_t); extern int ripng_network_write (struct vty *, int); #endif /* _ZEBRA_RIPNG_RIPNGD_H */ quagga-0.99.24.1/ripngd/ripng_route.h0000644000175000017500000000321112476520570014222 00000000000000/* * RIPng daemon * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIPNG_ROUTE_H #define _ZEBRA_RIPNG_ROUTE_H struct ripng_aggregate { /* Aggregate route count. */ unsigned int count; /* Suppressed route count. */ unsigned int suppress; /* Metric of this route. */ u_char metric; /* Tag field of RIPng packet.*/ u_short tag; /* Route-map futures - this variables can be changed. */ struct in6_addr nexthop_out; u_char metric_set; u_char metric_out; u_short tag_out; }; extern void ripng_aggregate_increment (struct route_node *rp, struct ripng_info *rinfo); extern void ripng_aggregate_decrement (struct route_node *rp, struct ripng_info *rinfo); extern int ripng_aggregate_add (struct prefix *p); extern int ripng_aggregate_delete (struct prefix *p); #endif /* _ZEBRA_RIPNG_ROUTE_H */ quagga-0.99.24.1/ripngd/ripng_debug.h0000644000175000017500000000325012476520570014155 00000000000000/* * RIPng debug output routines * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIPNG_DEBUG_H #define _ZEBRA_RIPNG_DEBUG_H /* Debug flags. */ #define RIPNG_DEBUG_EVENT 0x01 #define RIPNG_DEBUG_PACKET 0x01 #define RIPNG_DEBUG_SEND 0x20 #define RIPNG_DEBUG_RECV 0x40 #define RIPNG_DEBUG_ZEBRA 0x01 /* Debug related macro. */ #define IS_RIPNG_DEBUG_EVENT (ripng_debug_event & RIPNG_DEBUG_EVENT) #define IS_RIPNG_DEBUG_PACKET (ripng_debug_packet & RIPNG_DEBUG_PACKET) #define IS_RIPNG_DEBUG_SEND (ripng_debug_packet & RIPNG_DEBUG_SEND) #define IS_RIPNG_DEBUG_RECV (ripng_debug_packet & RIPNG_DEBUG_RECV) #define IS_RIPNG_DEBUG_ZEBRA (ripng_debug_zebra & RIPNG_DEBUG_ZEBRA) extern unsigned long ripng_debug_event; extern unsigned long ripng_debug_packet; extern unsigned long ripng_debug_zebra; extern void ripng_debug_init (void); extern void ripng_debug_reset (void); #endif /* _ZEBRA_RIPNG_DEBUG_H */ quagga-0.99.24.1/ripngd/ripngd.conf.sample0000644000175000017500000000060612476520570015133 00000000000000! -*- rip -*- ! ! RIPngd sample configuration file ! ! $Id: ripngd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $ ! hostname ripngd password zebra ! ! debug ripng events ! debug ripng packet ! ! router ripng ! network sit1 ! route 3ffe:506::0/32 ! distribute-list local-only out sit1 ! !ipv6 access-list local-only permit 3ffe:506::0/32 !ipv6 access-list local-only deny any ! log stdout quagga-0.99.24.1/ripngd/Makefile.am0000644000175000017500000000132112476520570013550 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libripng.a sbin_PROGRAMS = ripngd libripng_a_SOURCES = \ ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c noinst_HEADERS = \ ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) ripngd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripngd.conf.sample quagga-0.99.24.1/ripngd/Makefile.in0000644000175000017500000006114412476521251013567 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ripngd$(EXEEXT) subdir = ripngd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libripng_a_AR = $(AR) $(ARFLAGS) libripng_a_LIBADD = am_libripng_a_OBJECTS = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \ ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \ ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT) \ ripng_offset.$(OBJEXT) ripng_peer.$(OBJEXT) \ ripng_nexthop.$(OBJEXT) libripng_a_OBJECTS = $(am_libripng_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = ripng_interface.$(OBJEXT) ripngd.$(OBJEXT) \ ripng_zebra.$(OBJEXT) ripng_route.$(OBJEXT) \ ripng_debug.$(OBJEXT) ripng_routemap.$(OBJEXT) \ ripng_offset.$(OBJEXT) ripng_peer.$(OBJEXT) \ ripng_nexthop.$(OBJEXT) am_ripngd_OBJECTS = ripng_main.$(OBJEXT) $(am__objects_1) ripngd_OBJECTS = $(am_ripngd_OBJECTS) ripngd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) DIST_SOURCES = $(libripng_a_SOURCES) $(ripngd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libripng.a libripng_a_SOURCES = \ ripng_interface.c ripngd.c ripng_zebra.c ripng_route.c ripng_debug.c \ ripng_routemap.c ripng_offset.c ripng_peer.c ripng_nexthop.c noinst_HEADERS = \ ripng_debug.h ripng_route.h ripngd.h ripng_nexthop.h ripngd_SOURCES = \ ripng_main.c $(libripng_a_SOURCES) ripngd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripngd.conf.sample all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ripngd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ripngd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libripng.a: $(libripng_a_OBJECTS) $(libripng_a_DEPENDENCIES) $(EXTRA_libripng_a_DEPENDENCIES) $(AM_V_at)-rm -f libripng.a $(AM_V_AR)$(libripng_a_AR) libripng.a $(libripng_a_OBJECTS) $(libripng_a_LIBADD) $(AM_V_at)$(RANLIB) libripng.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ripngd$(EXEEXT): $(ripngd_OBJECTS) $(ripngd_DEPENDENCIES) $(EXTRA_ripngd_DEPENDENCIES) @rm -f ripngd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ripngd_OBJECTS) $(ripngd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_nexthop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_offset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_peer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripng_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripngd.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/ripd/0000755000175000017500000000000012476521355011254 500000000000000quagga-0.99.24.1/ripd/RIPv2-MIB.txt0000644000175000017500000004051312476520570013245 00000000000000 RIPv2-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, Counter32, TimeTicks, IpAddress FROM SNMPv2-SMI TEXTUAL-CONVENTION, RowStatus FROM SNMPv2-TC MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF mib-2 FROM RFC1213-MIB; -- This MIB module uses the extended OBJECT-TYPE macro as -- defined in [9]. rip2 MODULE-IDENTITY LAST-UPDATED "9407272253Z" -- Wed Jul 27 22:53:04 PDT 1994 ORGANIZATION "IETF RIP-II Working Group" CONTACT-INFO " Fred Baker Postal: Cisco Systems 519 Lado Drive Santa Barbara, California 93111 Tel: +1 805 681 0115 E-Mail: fbaker@cisco.com Postal: Gary Malkin Xylogics, Inc. 53 Third Avenue Burlington, MA 01803 Phone: (617) 272-8140 EMail: gmalkin@Xylogics.COM" DESCRIPTION "The MIB module to describe the RIP2 Version 2 Protocol" ::= { mib-2 23 } -- RIP-2 Management Information Base -- the RouteTag type represents the contents of the -- Route Domain field in the packet header or route entry. -- The use of the Route Domain is deprecated. RouteTag ::= TEXTUAL-CONVENTION STATUS current DESCRIPTION "the RouteTag type represents the contents of the Route Domain field in the packet header or route entry" SYNTAX OCTET STRING (SIZE (2)) --4.1 Global Counters -- The RIP-2 Globals Group. -- Implementation of this group is mandatory for systems -- which implement RIP-2. -- These counters are intended to facilitate debugging quickly -- changing routes or failing neighbors rip2Globals OBJECT IDENTIFIER ::= { rip2 1 } rip2GlobalRouteChanges OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of route changes made to the IP Route Database by RIP. This does not include the refresh of a route's age." ::= { rip2Globals 1 } rip2GlobalQueries OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of responses sent to RIP queries from other systems." ::= { rip2Globals 2 } --4.2 RIP Interface Tables -- RIP Interfaces Groups -- Implementation of these Groups is mandatory for systems -- which implement RIP-2. -- The RIP Interface Status Table. rip2IfStatTable OBJECT-TYPE SYNTAX SEQUENCE OF Rip2IfStatEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A list of subnets which require separate status monitoring in RIP." ::= { rip2 2 } rip2IfStatEntry OBJECT-TYPE SYNTAX Rip2IfStatEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A Single Routing Domain in a single Subnet." INDEX { rip2IfStatAddress } ::= { rip2IfStatTable 1 } Rip2IfStatEntry ::= SEQUENCE { rip2IfStatAddress IpAddress, rip2IfStatRcvBadPackets Counter32, rip2IfStatRcvBadRoutes Counter32, rip2IfStatSentUpdates Counter32, rip2IfStatStatus RowStatus } rip2IfStatAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of this system on the indicated subnet. For unnumbered interfaces, the value 0.0.0.N, where the least significant 24 bits (N) is the ifIndex for the IP Interface in network byte order." ::= { rip2IfStatEntry 1 } rip2IfStatRcvBadPackets OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of RIP response packets received by the RIP process which were subsequently discarded for any reason (e.g. a version 0 packet, or an unknown command type)." ::= { rip2IfStatEntry 2 } rip2IfStatRcvBadRoutes OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of routes, in valid RIP packets, which were ignored for any reason (e.g. unknown address family, or invalid metric)." ::= { rip2IfStatEntry 3 } rip2IfStatSentUpdates OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of triggered RIP updates actually sent on this interface. This explicitly does NOT include full updates sent containing new information." ::= { rip2IfStatEntry 4 } rip2IfStatStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "Writing invalid has the effect of deleting this interface." ::= { rip2IfStatEntry 5 } -- The RIP Interface Configuration Table. rip2IfConfTable OBJECT-TYPE SYNTAX SEQUENCE OF Rip2IfConfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A list of subnets which require separate configuration in RIP." ::= { rip2 3 } rip2IfConfEntry OBJECT-TYPE SYNTAX Rip2IfConfEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A Single Routing Domain in a single Subnet." INDEX { rip2IfConfAddress } ::= { rip2IfConfTable 1 } Rip2IfConfEntry ::= SEQUENCE { rip2IfConfAddress IpAddress, rip2IfConfDomain RouteTag, rip2IfConfAuthType INTEGER, rip2IfConfAuthKey OCTET STRING (SIZE(0..16)), rip2IfConfSend INTEGER, rip2IfConfReceive INTEGER, rip2IfConfDefaultMetric INTEGER, rip2IfConfStatus RowStatus, rip2IfConfSrcAddress IpAddress } rip2IfConfAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address of this system on the indicated subnet. For unnumbered interfaces, the value 0.0.0.N, where the least significant 24 bits (N) is the ifIndex for the IP Interface in network byte order." ::= { rip2IfConfEntry 1 } rip2IfConfDomain OBJECT-TYPE SYNTAX RouteTag MAX-ACCESS read-create STATUS obsolete DESCRIPTION "Value inserted into the Routing Domain field of all RIP packets sent on this interface." DEFVAL { '0000'h } ::= { rip2IfConfEntry 2 } rip2IfConfAuthType OBJECT-TYPE SYNTAX INTEGER { noAuthentication (1), simplePassword (2), md5 (3) } MAX-ACCESS read-create STATUS current DESCRIPTION "The type of Authentication used on this interface." DEFVAL { noAuthentication } ::= { rip2IfConfEntry 3 } rip2IfConfAuthKey OBJECT-TYPE SYNTAX OCTET STRING (SIZE(0..16)) MAX-ACCESS read-create STATUS current DESCRIPTION "The value to be used as the Authentication Key whenever the corresponding instance of rip2IfConfAuthType has a value other than noAuthentication. A modification of the corresponding instance of rip2IfConfAuthType does not modify the rip2IfConfAuthKey value. If a string shorter than 16 octets is supplied, it will be left- justified and padded to 16 octets, on the right, with nulls (0x00). Reading this object always results in an OCTET STRING of length zero; authentication may not be bypassed by reading the MIB object." DEFVAL { ''h } ::= { rip2IfConfEntry 4 } rip2IfConfSend OBJECT-TYPE SYNTAX INTEGER { doNotSend (1), ripVersion1 (2), rip1Compatible (3), ripVersion2 (4), ripV1Demand (5), ripV2Demand (6) } MAX-ACCESS read-create STATUS current DESCRIPTION "What the router sends on this interface. ripVersion1 implies sending RIP updates compliant with RFC 1058. rip1Compatible implies broadcasting RIP-2 updates using RFC 1058 route subsumption rules. ripVersion2 implies multicasting RIP-2 updates. ripV1Demand indicates the use of Demand RIP on a WAN interface under RIP Version 1 rules. ripV2Demand indicates the use of Demand RIP on a WAN interface under Version 2 rules." DEFVAL { rip1Compatible } ::= { rip2IfConfEntry 5 } rip2IfConfReceive OBJECT-TYPE SYNTAX INTEGER { rip1 (1), rip2 (2), rip1OrRip2 (3), doNotRecieve (4) } MAX-ACCESS read-create STATUS current DESCRIPTION "This indicates which version of RIP updates are to be accepted. Note that rip2 and rip1OrRip2 implies reception of multicast packets." DEFVAL { rip1OrRip2 } ::= { rip2IfConfEntry 6 } rip2IfConfDefaultMetric OBJECT-TYPE SYNTAX INTEGER ( 0..15 ) MAX-ACCESS read-create STATUS current DESCRIPTION "This variable indicates the metric that is to be used for the default route entry in RIP updates originated on this interface. A value of zero indicates that no default route should be originated; in this case, a default route via another router may be propagated." ::= { rip2IfConfEntry 7 } rip2IfConfStatus OBJECT-TYPE SYNTAX RowStatus MAX-ACCESS read-create STATUS current DESCRIPTION "Writing invalid has the effect of deleting this interface." ::= { rip2IfConfEntry 8 } rip2IfConfSrcAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-create STATUS current DESCRIPTION "The IP Address this system will use as a source address on this interface. If it is a numbered interface, this MUST be the same value as rip2IfConfAddress. On unnumbered interfaces, it must be the value of rip2IfConfAddress for some interface on the system." ::= { rip2IfConfEntry 9 } --4.3 Peer Table -- Peer Table -- The RIP Peer Group -- Implementation of this Group is Optional -- This group provides information about active peer -- relationships intended to assist in debugging. An -- active peer is a router from which a valid RIP -- updated has been heard in the last 180 seconds. rip2PeerTable OBJECT-TYPE SYNTAX SEQUENCE OF Rip2PeerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "A list of RIP Peers." ::= { rip2 4 } rip2PeerEntry OBJECT-TYPE SYNTAX Rip2PeerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information regarding a single routing peer." INDEX { rip2PeerAddress, rip2PeerDomain } ::= { rip2PeerTable 1 } Rip2PeerEntry ::= SEQUENCE { rip2PeerAddress IpAddress, rip2PeerDomain RouteTag, rip2PeerLastUpdate TimeTicks, rip2PeerVersion INTEGER, rip2PeerRcvBadPackets Counter32, rip2PeerRcvBadRoutes Counter32 } rip2PeerAddress OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP Address that the peer is using as its source address. Note that on an unnumbered link, this may not be a member of any subnet on the system." ::= { rip2PeerEntry 1 } rip2PeerDomain OBJECT-TYPE SYNTAX RouteTag MAX-ACCESS read-only STATUS current DESCRIPTION "The value in the Routing Domain field in RIP packets received from the peer. As domain suuport is deprecated, this must be zero." ::= { rip2PeerEntry 2 } rip2PeerLastUpdate OBJECT-TYPE SYNTAX TimeTicks MAX-ACCESS read-only STATUS current DESCRIPTION "The value of sysUpTime when the most recent RIP update was received from this system." ::= { rip2PeerEntry 3 } rip2PeerVersion OBJECT-TYPE SYNTAX INTEGER ( 0..255 ) MAX-ACCESS read-only STATUS current DESCRIPTION "The RIP version number in the header of the last RIP packet received." ::= { rip2PeerEntry 4 } rip2PeerRcvBadPackets OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of RIP response packets from this peer discarded as invalid." ::= { rip2PeerEntry 5 } rip2PeerRcvBadRoutes OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of routes from this peer that were ignored because the entry format was invalid." ::= { rip2PeerEntry 6 } -- conformance information rip2Conformance OBJECT IDENTIFIER ::= { rip2 5 } rip2Groups OBJECT IDENTIFIER ::= { rip2Conformance 1 } rip2Compliances OBJECT IDENTIFIER ::= { rip2Conformance 2 } -- compliance statements rip2Compliance MODULE-COMPLIANCE STATUS current DESCRIPTION "The compliance statement " MODULE -- this module MANDATORY-GROUPS { rip2GlobalGroup, rip2IfStatGroup, rip2IfConfGroup, rip2PeerGroup } GROUP rip2GlobalGroup DESCRIPTION "This group defines global controls for RIP-II systems." GROUP rip2IfStatGroup DESCRIPTION "This group defines interface statistics for RIP-II systems." GROUP rip2IfConfGroup DESCRIPTION "This group defines interface configuration for RIP-II systems." GROUP rip2PeerGroup DESCRIPTION "This group defines peer information for RIP-II systems." ::= { rip2Compliances 1 } -- units of conformance rip2GlobalGroup OBJECT-GROUP OBJECTS { rip2GlobalRouteChanges, rip2GlobalQueries } STATUS current DESCRIPTION "This group defines global controls for RIP-II systems." ::= { rip2Groups 1 } rip2IfStatGroup OBJECT-GROUP OBJECTS { rip2IfStatAddress, rip2IfStatRcvBadPackets, rip2IfStatRcvBadRoutes, rip2IfStatSentUpdates, rip2IfStatStatus } STATUS current DESCRIPTION "This group defines interface statistics for RIP-II systems." ::= { rip2Groups 2 } rip2IfConfGroup OBJECT-GROUP OBJECTS { rip2IfConfAddress, rip2IfConfAuthType, rip2IfConfAuthKey, rip2IfConfSend, rip2IfConfReceive, rip2IfConfDefaultMetric, rip2IfConfStatus, rip2IfConfSrcAddress } STATUS current DESCRIPTION "This group defines interface configuration for RIP-II systems." ::= { rip2Groups 3 } rip2PeerGroup OBJECT-GROUP OBJECTS { rip2PeerAddress, rip2PeerDomain, rip2PeerLastUpdate, rip2PeerVersion, rip2PeerRcvBadPackets, rip2PeerRcvBadRoutes } STATUS current DESCRIPTION "This group defines peer information for RIP-II systems." ::= { rip2Groups 4 } END quagga-0.99.24.1/ripd/rip_main.c0000644000175000017500000001574212476520570013145 00000000000000/* RIPd main routine. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "thread.h" #include "command.h" #include "memory.h" #include "prefix.h" #include "filter.h" #include "keychain.h" #include "log.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "ripd/ripd.h" /* ripd options. */ static struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "dryrun", no_argument, NULL, 'C'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; /* ripd privileges */ zebra_capabilities_t _caps_p [] = { ZCAP_NET_RAW, ZCAP_BIND }; struct zebra_privs_t ripd_privs = { #if defined(QUAGGA_USER) .user = QUAGGA_USER, #endif #if defined QUAGGA_GROUP .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = 2, .cap_num_i = 0 }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR RIPD_DEFAULT_CONFIG; char *config_file = NULL; /* ripd program name */ /* Route retain mode flag. */ int retain_mode = 0; /* RIP VTY bind address. */ char *vty_addr = NULL; /* RIP VTY connection port. */ int vty_port = RIP_VTY_PORT; /* Master of threads. */ struct thread_master *master; /* Process ID saved for use by init system */ const char *pid_file = PATH_RIPD_PID; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\ Daemon which manages RIP version 1 and 2.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -C, --dryrun Check configuration for validity and exit\n\ -r, --retain When program terminates, retain added route by ripd.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); rip_clean (); rip_reset (); zlog_info ("ripd restarting!"); /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) rip_clean (); exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } static struct quagga_signal_t ripd_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Main routine of ripd. */ int main (int argc, char **argv) { char *p; int daemon_mode = 0; int dryrun = 0; char *progname; struct thread thread; /* Set umask before anything for security */ umask (0027); /* Get program name. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); /* First of all we need logging init. */ zlog_default = openzlog (progname, ZLOG_RIP, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* Command line option parse. */ while (1) { int opt; opt = getopt_long (argc, argv, "df:i:z:hA:P:u:g:rvC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'P': /* Deal with atoi() returning 0 on failure, and ripd not listening on rip port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = RIP_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'C': dryrun = 1; break; case 'u': ripd_privs.user = optarg; break; case 'g': ripd_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Prepare master thread. */ master = thread_master_create (); /* Library initialization. */ zprivs_init (&ripd_privs); signal_init (master, array_size(ripd_signals), ripd_signals); cmd_init (1); vty_init (master); memory_init (); keychain_init (); /* RIP related initialization. */ rip_init (); rip_if_init (); rip_zclient_init (); rip_peer_init (); /* Get configuration file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return (0); /* Change to the daemon program. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("RIPd daemon failed: %s", strerror(errno)); exit (1); } /* Pid file create. */ pid_output (pid_file); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, RIP_VTYSH_PATH); /* Print banner. */ zlog_notice ("RIPd %s starting: vty@%d", QUAGGA_VERSION, vty_port); /* Execute each thread. */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.24.1/ripd/rip_offset.c0000644000175000017500000002524612476520570013507 00000000000000/* RIP offset-list * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "filter.h" #include "command.h" #include "linklist.h" #include "memory.h" #include "ripd/ripd.h" #define RIP_OFFSET_LIST_IN 0 #define RIP_OFFSET_LIST_OUT 1 #define RIP_OFFSET_LIST_MAX 2 struct rip_offset_list { char *ifname; struct { char *alist_name; /* struct access_list *alist; */ int metric; } direct[RIP_OFFSET_LIST_MAX]; }; static struct list *rip_offset_list_master; static int strcmp_safe (const char *s1, const char *s2) { if (s1 == NULL && s2 == NULL) return 0; if (s1 == NULL) return -1; if (s2 == NULL) return 1; return strcmp (s1, s2); } static struct rip_offset_list * rip_offset_list_new (void) { return XCALLOC (MTYPE_RIP_OFFSET_LIST, sizeof (struct rip_offset_list)); } static void rip_offset_list_free (struct rip_offset_list *offset) { XFREE (MTYPE_RIP_OFFSET_LIST, offset); } static struct rip_offset_list * rip_offset_list_lookup (const char *ifname) { struct rip_offset_list *offset; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (rip_offset_list_master, node, nnode, offset)) { if (strcmp_safe (offset->ifname, ifname) == 0) return offset; } return NULL; } static struct rip_offset_list * rip_offset_list_get (const char *ifname) { struct rip_offset_list *offset; offset = rip_offset_list_lookup (ifname); if (offset) return offset; offset = rip_offset_list_new (); if (ifname) offset->ifname = strdup (ifname); listnode_add_sort (rip_offset_list_master, offset); return offset; } static int rip_offset_list_set (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct rip_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIP_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIP_OFFSET_LIST_OUT; else { vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); return CMD_WARNING; } /* Check metric. */ metric = atoi (metric_str); if (metric < 0 || metric > 16) { vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); return CMD_WARNING; } /* Get offset-list structure with interface name. */ offset = rip_offset_list_get (ifname); if (offset->direct[direct].alist_name) free (offset->direct[direct].alist_name); offset->direct[direct].alist_name = strdup (alist); offset->direct[direct].metric = metric; return CMD_SUCCESS; } static int rip_offset_list_unset (struct vty *vty, const char *alist, const char *direct_str, const char *metric_str, const char *ifname) { int direct; int metric; struct rip_offset_list *offset; /* Check direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = RIP_OFFSET_LIST_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RIP_OFFSET_LIST_OUT; else { vty_out (vty, "Invalid direction: %s%s", direct_str, VTY_NEWLINE); return CMD_WARNING; } /* Check metric. */ metric = atoi (metric_str); if (metric < 0 || metric > 16) { vty_out (vty, "Invalid metric: %s%s", metric_str, VTY_NEWLINE); return CMD_WARNING; } /* Get offset-list structure with interface name. */ offset = rip_offset_list_lookup (ifname); if (offset) { if (offset->direct[direct].alist_name) free (offset->direct[direct].alist_name); offset->direct[direct].alist_name = NULL; if (offset->direct[RIP_OFFSET_LIST_IN].alist_name == NULL && offset->direct[RIP_OFFSET_LIST_OUT].alist_name == NULL) { listnode_delete (rip_offset_list_master, offset); if (offset->ifname) free (offset->ifname); rip_offset_list_free (offset); } } else { vty_out (vty, "Can't find offset-list%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIP_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_IN].metric) #define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name) #define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIP_OFFSET_LIST_OUT].metric) /* If metric is modifed return 1. */ int rip_offset_list_apply_in (struct prefix_ipv4 *p, struct interface *ifp, u_int32_t *metric) { struct rip_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = rip_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_IN_METRIC (offset); return 1; } return 0; } /* Look up offset-list without interface name. */ offset = rip_offset_list_lookup (NULL); if (offset && OFFSET_LIST_IN_NAME (offset)) { alist = access_list_lookup (AFI_IP, OFFSET_LIST_IN_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_IN_METRIC (offset); return 1; } return 0; } return 0; } /* If metric is modifed return 1. */ int rip_offset_list_apply_out (struct prefix_ipv4 *p, struct interface *ifp, u_int32_t *metric) { struct rip_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ offset = rip_offset_list_lookup (ifp->name); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_OUT_METRIC (offset); return 1; } return 0; } /* Look up offset-list without interface name. */ offset = rip_offset_list_lookup (NULL); if (offset && OFFSET_LIST_OUT_NAME (offset)) { alist = access_list_lookup (AFI_IP, OFFSET_LIST_OUT_NAME (offset)); if (alist && access_list_apply (alist, (struct prefix *)p) == FILTER_PERMIT) { *metric += OFFSET_LIST_OUT_METRIC (offset); return 1; } return 0; } return 0; } DEFUN (rip_offset_list, rip_offset_list_cmd, "offset-list WORD (in|out) <0-16>", "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return rip_offset_list_set (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (rip_offset_list_ifname, rip_offset_list_ifname_cmd, "offset-list WORD (in|out) <0-16> IFNAME", "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return rip_offset_list_set (vty, argv[0], argv[1], argv[2], argv[3]); } DEFUN (no_rip_offset_list, no_rip_offset_list_cmd, "no offset-list WORD (in|out) <0-16>", NO_STR "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n") { return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], NULL); } DEFUN (no_rip_offset_list_ifname, no_rip_offset_list_ifname_cmd, "no offset-list WORD (in|out) <0-16> IFNAME", NO_STR "Modify RIP metric\n" "Access-list name\n" "For incoming updates\n" "For outgoing updates\n" "Metric value\n" "Interface to match\n") { return rip_offset_list_unset (vty, argv[0], argv[1], argv[2], argv[3]); } static int offset_list_cmp (struct rip_offset_list *o1, struct rip_offset_list *o2) { return strcmp_safe (o1->ifname, o2->ifname); } static void offset_list_del (struct rip_offset_list *offset) { if (OFFSET_LIST_IN_NAME (offset)) free (OFFSET_LIST_IN_NAME (offset)); if (OFFSET_LIST_OUT_NAME (offset)) free (OFFSET_LIST_OUT_NAME (offset)); if (offset->ifname) free (offset->ifname); rip_offset_list_free (offset); } void rip_offset_init () { rip_offset_list_master = list_new (); rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; rip_offset_list_master->del = (void (*)(void *)) offset_list_del; install_element (RIP_NODE, &rip_offset_list_cmd); install_element (RIP_NODE, &rip_offset_list_ifname_cmd); install_element (RIP_NODE, &no_rip_offset_list_cmd); install_element (RIP_NODE, &no_rip_offset_list_ifname_cmd); } void rip_offset_clean () { list_delete (rip_offset_list_master); rip_offset_list_master = list_new (); rip_offset_list_master->cmp = (int (*)(void *, void *)) offset_list_cmp; rip_offset_list_master->del = (void (*)(void *)) offset_list_del; } int config_write_rip_offset_list (struct vty *vty) { struct listnode *node, *nnode; struct rip_offset_list *offset; for (ALL_LIST_ELEMENTS (rip_offset_list_master, node, nnode, offset)) { if (! offset->ifname) { if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d%s", offset->direct[RIP_OFFSET_LIST_IN].alist_name, offset->direct[RIP_OFFSET_LIST_IN].metric, VTY_NEWLINE); if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d%s", offset->direct[RIP_OFFSET_LIST_OUT].alist_name, offset->direct[RIP_OFFSET_LIST_OUT].metric, VTY_NEWLINE); } else { if (offset->direct[RIP_OFFSET_LIST_IN].alist_name) vty_out (vty, " offset-list %s in %d %s%s", offset->direct[RIP_OFFSET_LIST_IN].alist_name, offset->direct[RIP_OFFSET_LIST_IN].metric, offset->ifname, VTY_NEWLINE); if (offset->direct[RIP_OFFSET_LIST_OUT].alist_name) vty_out (vty, " offset-list %s out %d %s%s", offset->direct[RIP_OFFSET_LIST_OUT].alist_name, offset->direct[RIP_OFFSET_LIST_OUT].metric, offset->ifname, VTY_NEWLINE); } } return 0; } quagga-0.99.24.1/ripd/rip_peer.c0000644000175000017500000001114412476520570013144 00000000000000/* RIP peer support * Copyright (C) 2000 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "command.h" #include "linklist.h" #include "thread.h" #include "memory.h" #include "ripd/ripd.h" /* Linked list of RIP peer. */ struct list *peer_list; static struct rip_peer * rip_peer_new (void) { return XCALLOC (MTYPE_RIP_PEER, sizeof (struct rip_peer)); } static void rip_peer_free (struct rip_peer *peer) { XFREE (MTYPE_RIP_PEER, peer); } struct rip_peer * rip_peer_lookup (struct in_addr *addr) { struct rip_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (IPV4_ADDR_SAME (&peer->addr, addr)) return peer; } return NULL; } struct rip_peer * rip_peer_lookup_next (struct in_addr *addr) { struct rip_peer *peer; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { if (htonl (peer->addr.s_addr) > htonl (addr->s_addr)) return peer; } return NULL; } /* RIP peer is timeout. */ static int rip_peer_timeout (struct thread *t) { struct rip_peer *peer; peer = THREAD_ARG (t); listnode_delete (peer_list, peer); rip_peer_free (peer); return 0; } /* Get RIP peer. At the same time update timeout thread. */ static struct rip_peer * rip_peer_get (struct in_addr *addr) { struct rip_peer *peer; peer = rip_peer_lookup (addr); if (peer) { if (peer->t_timeout) thread_cancel (peer->t_timeout); } else { peer = rip_peer_new (); peer->addr = *addr; listnode_add_sort (peer_list, peer); } /* Update timeout thread. */ peer->t_timeout = thread_add_timer (master, rip_peer_timeout, peer, RIP_PEER_TIMER_DEFAULT); /* Last update time set. */ time (&peer->uptime); return peer; } void rip_peer_update (struct sockaddr_in *from, u_char version) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->version = version; } void rip_peer_bad_route (struct sockaddr_in *from) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->recv_badroutes++; } void rip_peer_bad_packet (struct sockaddr_in *from) { struct rip_peer *peer; peer = rip_peer_get (&from->sin_addr); peer->recv_badpackets++; } /* Display peer uptime. */ static char * rip_peer_uptime (struct rip_peer *peer, char *buf, size_t len) { time_t uptime; struct tm *tm; /* If there is no connection has been done before print `never'. */ if (peer->uptime == 0) { snprintf (buf, len, "never "); return buf; } /* Get current time. */ uptime = time (NULL); uptime -= peer->uptime; tm = gmtime (&uptime); /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (uptime < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } void rip_peer_display (struct vty *vty) { struct rip_peer *peer; struct listnode *node, *nnode; #define RIP_UPTIME_LEN 25 char timebuf[RIP_UPTIME_LEN]; for (ALL_LIST_ELEMENTS (peer_list, node, nnode, peer)) { vty_out (vty, " %-16s %9d %9d %9d %s%s", inet_ntoa (peer->addr), peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIP_DISTANCE_DEFAULT, rip_peer_uptime (peer, timebuf, RIP_UPTIME_LEN), VTY_NEWLINE); } } static int rip_peer_list_cmp (struct rip_peer *p1, struct rip_peer *p2) { return htonl (p1->addr.s_addr) > htonl (p2->addr.s_addr); } void rip_peer_init (void) { peer_list = list_new (); peer_list->cmp = (int (*)(void *, void *)) rip_peer_list_cmp; } quagga-0.99.24.1/ripd/rip_routemap.c0000644000175000017500000006751412476520570014061 00000000000000/* RIPv2 routemap. * Copyright (C) 2005 6WIND * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "prefix.h" #include "routemap.h" #include "command.h" #include "filter.h" #include "log.h" #include "sockunion.h" /* for inet_aton () */ #include "plist.h" #include "ripd/ripd.h" struct rip_metric_modifier { enum { metric_increment, metric_decrement, metric_absolute } type; u_char metric; }; /* Add rip route map rule. */ static int rip_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int rip_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add rip route map rule. */ static int rip_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: /* rip, ripng and other protocols share the set metric command but only values from 0 to 16 are valid for rip and ripng if metric is out of range for rip and ripng, it is not for other protocols. Do not return an error */ if (strcmp(command, "metric")) { vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } } return CMD_SUCCESS; } /* Delete rip route map rule. */ static int rip_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Hook function for updating route_map assignment. */ /* ARGSUSED */ static void rip_route_map_update (const char *notused) { int i; if (rip) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rip->route_map[i].name) rip->route_map[i].map = route_map_lookup_by_name (rip->route_map[i].name); } } } /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *metric; u_int32_t check; struct rip_info *rinfo; if (type == RMAP_RIP) { metric = rule; rinfo = object; /* If external metric is available, the route-map should work on this one (for redistribute purpose) */ check = (rinfo->external_metric) ? rinfo->external_metric : rinfo->metric; if (check == *metric) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match metric' match statement. `arg' is METRIC value */ static void * route_match_metric_compile (const char *arg) { u_int32_t *metric; metric = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); *metric = atoi (arg); if(*metric > 0) return metric; XFREE (MTYPE_ROUTE_MAP_COMPILED, metric); return NULL; } /* Free route map's compiled `match metric' value. */ static void route_match_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, route_match_metric_compile, route_match_metric_free }; /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rip_info *rinfo; struct interface *ifp; char *ifname; if (type == RMAP_RIP) { ifname = rule; ifp = if_lookup_by_name(ifname); if (!ifp) return RMAP_NOMATCH; rinfo = object; if (rinfo->ifindex_out == ifp->ifindex || rinfo->ifindex == ifp->ifindex) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match interface' match statement. `arg' is IFNAME value */ /* XXX I don`t know if I need to check does interface exist? */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `match interface' value. */ static void route_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for interface matching. */ struct route_map_rule_cmd route_match_interface_cmd = { "interface", route_match_interface, route_match_interface_compile, route_match_interface_free }; /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; struct rip_info *rinfo; struct prefix_ipv4 p; if (type == RMAP_RIP) { rinfo = object; p.family = AF_INET; p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from; p.prefixlen = IPV4_MAX_BITLEN; alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip next-hop' match statement. `arg' should be access-list name. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `. */ static void route_match_ip_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip next-hop matching. */ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; struct rip_info *rinfo; struct prefix_ipv4 p; if (type == RMAP_RIP) { rinfo = object; p.family = AF_INET; p.prefix = (rinfo->nexthop.s_addr) ? rinfo->nexthop : rinfo->from; p.prefixlen = IPV4_MAX_BITLEN; plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, &p) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_address (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; if (type == RMAP_RIP) { alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, prefix) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip address' match statement. `arg' should be access-list name. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ static struct route_map_rule_cmd route_match_ip_address_cmd = { "ip address", route_match_ip_address, route_match_ip_address_compile, route_match_ip_address_free }; /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type == RMAP_RIP) { plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { "ip address prefix-list", route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; /* `match tag TAG' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_short *tag; struct rip_info *rinfo; if (type == RMAP_RIP) { tag = rule; rinfo = object; /* The information stored by rinfo is host ordered. */ if (rinfo->tag == *tag) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match tag' match statement. `arg' is TAG value */ static void * route_match_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `match tag' value. */ static void route_match_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag matching. */ struct route_map_rule_cmd route_match_tag_cmd = { "tag", route_match_tag, route_match_tag_compile, route_match_tag_free }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { if (type == RMAP_RIP) { struct rip_metric_modifier *mod; struct rip_info *rinfo; mod = rule; rinfo = object; if (mod->type == metric_increment) rinfo->metric_out += mod->metric; else if (mod->type == metric_decrement) rinfo->metric_out -= mod->metric; else if (mod->type == metric_absolute) rinfo->metric_out = mod->metric; if ((signed int)rinfo->metric_out < 1) rinfo->metric_out = 1; if (rinfo->metric_out > RIP_METRIC_INFINITY) rinfo->metric_out = RIP_METRIC_INFINITY; rinfo->metric_set = 1; } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { int len; const char *pnt; int type; long metric; char *endptr = NULL; struct rip_metric_modifier *mod; len = strlen (arg); pnt = arg; if (len == 0) return NULL; /* Examine first character. */ if (arg[0] == '+') { type = metric_increment; pnt++; } else if (arg[0] == '-') { type = metric_decrement; pnt++; } else type = metric_absolute; /* Check beginning with digit string. */ if (*pnt < '0' || *pnt > '9') return NULL; /* Convert string to integer. */ metric = strtol (pnt, &endptr, 10); if (metric == LONG_MAX || *endptr != '\0') return NULL; if (metric < 0 || metric > RIP_METRIC_INFINITY) return NULL; mod = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rip_metric_modifier)); mod->type = type; mod->metric = metric; return mod; } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set metric rule structure. */ static struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free, }; /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ip_nexthop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in_addr *address; struct rip_info *rinfo; if(type == RMAP_RIP) { /* Fetch routemap's rule information. */ address = rule; rinfo = object; /* Set next hop value. */ rinfo->nexthop_out = *address; } return RMAP_OKAY; } /* Route map `ip nexthop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ip_nexthop_compile (const char *arg) { int ret; struct in_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); ret = inet_aton (arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_ip_nexthop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = { "ip next-hop", route_set_ip_nexthop, route_set_ip_nexthop_compile, route_set_ip_nexthop_free }; /* `set tag TAG' */ /* Set tag to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_tag (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_short *tag; struct rip_info *rinfo; if(type == RMAP_RIP) { /* Fetch routemap's rule information. */ tag = rule; rinfo = object; /* Set next hop value. */ rinfo->tag_out = *tag; } return RMAP_OKAY; } /* Route map `tag' compile function. Given string is converted to u_short. */ static void * route_set_tag_compile (const char *arg) { u_short *tag; tag = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_short)); *tag = atoi (arg); return tag; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_tag_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for tag set. */ static struct route_map_rule_cmd route_set_tag_cmd = { "tag", route_set_tag, route_set_tag_compile, route_set_tag_free }; #define MATCH_STR "Match values from routing table\n" #define SET_STR "Set values in destination routing protocol\n" DEFUN (match_metric, match_metric_cmd, "match metric <0-4294967295>", MATCH_STR "Match metric of route\n" "Metric value\n") { return rip_route_match_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_match_metric, no_match_metric_cmd, "no match metric", NO_STR MATCH_STR "Match metric of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "metric", NULL); return rip_route_match_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_match_metric, no_match_metric_val_cmd, "no match metric <0-4294967295>", NO_STR MATCH_STR "Match metric of route\n" "Metric value\n") DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "Match first hop interface of route\n" "Interface name\n") { return rip_route_match_add (vty, vty->index, "interface", argv[0]); } DEFUN (no_match_interface, no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "interface", NULL); return rip_route_match_delete (vty, vty->index, "interface", argv[0]); } ALIAS (no_match_interface, no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return rip_route_match_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_match_ip_next_hop, no_match_ip_next_hop_cmd, "no match ip next-hop", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "ip next-hop", NULL); return rip_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD", MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return rip_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); } DEFUN (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return rip_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); } ALIAS (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return rip_route_match_add (vty, vty->index, "ip address", argv[0]); } DEFUN (no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "ip address", NULL); return rip_route_match_delete (vty, vty->index, "ip address", argv[0]); } ALIAS (no_match_ip_address, no_match_ip_address_val_cmd, "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD", MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return rip_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); } DEFUN (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return rip_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); } ALIAS (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_tag, match_tag_cmd, "match tag <0-65535>", MATCH_STR "Match tag of route\n" "Metric value\n") { return rip_route_match_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_match_tag, no_match_tag_cmd, "no match tag", NO_STR MATCH_STR "Match tag of route\n") { if (argc == 0) return rip_route_match_delete (vty, vty->index, "tag", NULL); return rip_route_match_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_match_tag, no_match_tag_val_cmd, "no match tag <0-65535>", NO_STR MATCH_STR "Match tag of route\n" "Metric value\n") /* set functions */ DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", SET_STR "Metric value for destination routing protocol\n" "Metric value\n") { return rip_route_set_add (vty, vty->index, "metric", argv[0]); } ALIAS (set_metric, set_metric_addsub_cmd, "set metric <+/-metric>", SET_STR "Metric value for destination routing protocol\n" "Add or subtract metric\n") DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric value for destination routing protocol\n") { if (argc == 0) return rip_route_set_delete (vty, vty->index, "metric", NULL); return rip_route_set_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_set_metric, no_set_metric_val_cmd, "no set metric (<0-4294967295>|<+/-metric>)", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n" "Add or subtract metric\n") DEFUN (set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D", SET_STR IP_STR "Next hop address\n" "IP address of next hop\n") { union sockunion su; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed next-hop address%s", VTY_NEWLINE); return CMD_WARNING; } return rip_route_set_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_set_ip_nexthop, no_set_ip_nexthop_cmd, "no set ip next-hop", NO_STR SET_STR IP_STR "Next hop address\n") { if (argc == 0) return rip_route_set_delete (vty, vty->index, "ip next-hop", NULL); return rip_route_set_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_set_ip_nexthop, no_set_ip_nexthop_val_cmd, "no set ip next-hop A.B.C.D", NO_STR SET_STR IP_STR "Next hop address\n" "IP address of next hop\n") DEFUN (set_tag, set_tag_cmd, "set tag <0-65535>", SET_STR "Tag value for routing protocol\n" "Tag value\n") { return rip_route_set_add (vty, vty->index, "tag", argv[0]); } DEFUN (no_set_tag, no_set_tag_cmd, "no set tag", NO_STR SET_STR "Tag value for routing protocol\n") { if (argc == 0) return rip_route_set_delete (vty, vty->index, "tag", NULL); return rip_route_set_delete (vty, vty->index, "tag", argv[0]); } ALIAS (no_set_tag, no_set_tag_val_cmd, "no set tag <0-65535>", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") void rip_route_map_reset () { ; } /* Route-map init */ void rip_route_map_init () { route_map_init (); route_map_init_vty (); route_map_add_hook (rip_route_map_update); route_map_delete_hook (rip_route_map_update); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_interface_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_tag_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_tag_cmd); install_element (RMAP_NODE, &match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_val_cmd); install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); install_element (RMAP_NODE, &match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_cmd); install_element (RMAP_NODE, &no_match_tag_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &set_metric_addsub_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); install_element (RMAP_NODE, &set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_cmd); install_element (RMAP_NODE, &no_set_tag_val_cmd); } quagga-0.99.24.1/ripd/rip_snmp.c0000644000175000017500000003512612476520570013174 00000000000000/* RIP SNMP support * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "table.h" #include "smux.h" #include "ripd/ripd.h" /* RIPv2-MIB. */ #define RIPV2MIB 1,3,6,1,2,1,23 /* RIPv2-MIB rip2Globals values. */ #define RIP2GLOBALROUTECHANGES 1 #define RIP2GLOBALQUERIES 2 /* RIPv2-MIB rip2IfStatEntry. */ #define RIP2IFSTATENTRY 1 /* RIPv2-MIB rip2IfStatTable. */ #define RIP2IFSTATADDRESS 1 #define RIP2IFSTATRCVBADPACKETS 2 #define RIP2IFSTATRCVBADROUTES 3 #define RIP2IFSTATSENTUPDATES 4 #define RIP2IFSTATSTATUS 5 /* RIPv2-MIB rip2IfConfTable. */ #define RIP2IFCONFADDRESS 1 #define RIP2IFCONFDOMAIN 2 #define RIP2IFCONFAUTHTYPE 3 #define RIP2IFCONFAUTHKEY 4 #define RIP2IFCONFSEND 5 #define RIP2IFCONFRECEIVE 6 #define RIP2IFCONFDEFAULTMETRIC 7 #define RIP2IFCONFSTATUS 8 #define RIP2IFCONFSRCADDRESS 9 /* RIPv2-MIB rip2PeerTable. */ #define RIP2PEERADDRESS 1 #define RIP2PEERDOMAIN 2 #define RIP2PEERLASTUPDATE 3 #define RIP2PEERVERSION 4 #define RIP2PEERRCVBADPACKETS 5 #define RIP2PEERRCVBADROUTES 6 /* SNMP value hack. */ #define COUNTER ASN_COUNTER #define INTEGER ASN_INTEGER #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR /* Define SNMP local variables. */ SNMP_LOCAL_VARIABLES /* RIP-MIB instances. */ oid rip_oid [] = { RIPV2MIB }; /* Interface cache table sorted by interface's address. */ struct route_table *rip_ifaddr_table; /* Hook functions. */ static u_char *rip2Globals (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfStatEntry (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2PeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); struct variable rip_variables[] = { /* RIP Global Counters. */ {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, 2, {1, 1}}, {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, 2, {1, 2}}, /* RIP Interface Tables. */ {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, 3, {2, 1, 1}}, {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 2}}, {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 3}}, {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 4}}, {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, 3, {2, 1, 5}}, {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, /* RIP Interface Configuration Table. */ 3, {3, 1, 1}}, {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 2}}, {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 3}}, {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 4}}, {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 5}}, {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 6}}, {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 7}}, {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 8}}, {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, 3, {3, 1, 9}}, {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, /* RIP Peer Table. */ 3, {4, 1, 1}}, {RIP2PEERDOMAIN, STRING, RONLY, rip2PeerTable, 3, {4, 1, 2}}, {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, 3, {4, 1, 3}}, {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, 3, {4, 1, 4}}, {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 5}}, {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 6}} }; extern struct thread_master *master; static u_char * rip2Globals (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Retrun global counter. */ switch (v->magic) { case RIP2GLOBALROUTECHANGES: return SNMP_INTEGER (rip_global_route_changes); break; case RIP2GLOBALQUERIES: return SNMP_INTEGER (rip_global_queries); break; default: return NULL; break; } return NULL; } void rip_ifaddr_add (struct interface *ifp, struct connected *ifc) { struct prefix *p; struct route_node *rn; p = ifc->address; if (p->family != AF_INET) return; rn = route_node_get (rip_ifaddr_table, p); rn->info = ifp; } void rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) { struct prefix *p; struct route_node *rn; struct interface *i; p = ifc->address; if (p->family != AF_INET) return; rn = route_node_lookup (rip_ifaddr_table, p); if (! rn) return; i = rn->info; if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) { rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } static struct interface * rip_ifaddr_lookup_next (struct in_addr *addr) { struct prefix_ipv4 p; struct route_node *rn; struct interface *ifp; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.prefix = *addr; rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); for (rn = route_next (rn); rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { ifp = rn->info; *addr = rn->p.u.prefix4; route_unlock_node (rn); return ifp; } return NULL; } static struct interface * rip2IfLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { int len; struct interface *ifp; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); return if_lookup_exact_address (*addr); } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); ifp = rip_ifaddr_lookup_next (addr); if (ifp == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); *length = v->namelen + sizeof (struct in_addr); return ifp; } return NULL; } static struct rip_peer * rip2PeerLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { int len; struct rip_peer *peer; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr) + 1) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); peer = rip_peer_lookup (addr); if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) return peer; return NULL; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); len = *length - v->namelen; peer = rip_peer_lookup (addr); if (peer) { if ((len < sizeof (struct in_addr) + 1) || (peer->domain > name[v->namelen + sizeof (struct in_addr)])) { oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } } peer = rip_peer_lookup_next (addr); if (! peer) return NULL; oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } return NULL; } static u_char * rip2IfStatEntry (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct interface *ifp; struct rip_interface *ri; static struct in_addr addr; static long valid = SNMP_VALID; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ ifp = rip2IfLookup (v, name, length, &addr, exact); if (! ifp) return NULL; /* Fetch rip_interface information. */ ri = ifp->info; switch (v->magic) { case RIP2IFSTATADDRESS: return SNMP_IPADDRESS (addr); break; case RIP2IFSTATRCVBADPACKETS: *var_len = sizeof (long); return (u_char *) &ri->recv_badpackets; case RIP2IFSTATRCVBADROUTES: *var_len = sizeof (long); return (u_char *) &ri->recv_badroutes; case RIP2IFSTATSENTUPDATES: *var_len = sizeof (long); return (u_char *) &ri->sent_updates; case RIP2IFSTATSTATUS: *var_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &valid; default: return NULL; } return NULL; } static long rip2IfConfSend (struct rip_interface *ri) { #define doNotSend 1 #define ripVersion1 2 #define rip1Compatible 3 #define ripVersion2 4 #define ripV1Demand 5 #define ripV2Demand 6 if (! ri->running) return doNotSend; if (ri->ri_send & RIPv2) return ripVersion2; else if (ri->ri_send & RIPv1) return ripVersion1; else if (rip) { if (rip->version_send == RIPv2) return ripVersion2; else if (rip->version_send == RIPv1) return ripVersion1; } return doNotSend; } static long rip2IfConfReceive (struct rip_interface *ri) { #define rip1 1 #define rip2 2 #define rip1OrRip2 3 #define doNotReceive 4 int recvv; if (! ri->running) return doNotReceive; recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive; if (recvv == RI_RIP_VERSION_1_AND_2) return rip1OrRip2; else if (recvv & RIPv2) return rip2; else if (recvv & RIPv1) return rip1; else return doNotReceive; } static u_char * rip2IfConfAddress (struct variable *v, oid name[], size_t *length, int exact, size_t *val_len, WriteMethod **write_method) { static struct in_addr addr; static long valid = SNMP_INVALID; static long domain = 0; static long config = 0; static u_int auth = 0; struct interface *ifp; struct rip_interface *ri; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ ifp = rip2IfLookup (v, name, length, &addr, exact); if (! ifp) return NULL; /* Fetch rip_interface information. */ ri = ifp->info; switch (v->magic) { case RIP2IFCONFADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &addr; case RIP2IFCONFDOMAIN: *val_len = 2; return (u_char *) &domain; case RIP2IFCONFAUTHTYPE: auth = ri->auth_type; *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *)&auth; case RIP2IFCONFAUTHKEY: *val_len = 0; return (u_char *) &domain; case RIP2IFCONFSEND: config = rip2IfConfSend (ri); *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &config; case RIP2IFCONFRECEIVE: config = rip2IfConfReceive (ri); *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &config; case RIP2IFCONFDEFAULTMETRIC: *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &ifp->metric; case RIP2IFCONFSTATUS: *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &valid; case RIP2IFCONFSRCADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &addr; default: return NULL; } return NULL; } static u_char * rip2PeerTable (struct variable *v, oid name[], size_t *length, int exact, size_t *val_len, WriteMethod **write_method) { static struct in_addr addr; static int domain = 0; static int version; /* static time_t uptime; */ struct rip_peer *peer; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ peer = rip2PeerLookup (v, name, length, &addr, exact); if (! peer) return NULL; switch (v->magic) { case RIP2PEERADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &peer->addr; case RIP2PEERDOMAIN: *val_len = 2; return (u_char *) &domain; case RIP2PEERLASTUPDATE: #if 0 /* We don't know the SNMP agent startup time. We have two choices here: * - assume ripd startup time equals SNMP agent startup time * - don't support this variable, at all * Currently, we do the latter... */ *val_len = sizeof (time_t); uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */ return (u_char *) &uptime; #else return (u_char *) NULL; #endif case RIP2PEERVERSION: *val_len = sizeof (int); version = peer->version; return (u_char *) &version; case RIP2PEERRCVBADPACKETS: *val_len = sizeof (int); return (u_char *) &peer->recv_badpackets; case RIP2PEERRCVBADROUTES: *val_len = sizeof (int); return (u_char *) &peer->recv_badroutes; default: return NULL; } return NULL; } /* Register RIPv2-MIB. */ void rip_snmp_init () { rip_ifaddr_table = route_table_init (); smux_init (master); REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); } #endif /* HAVE_SNMP */ quagga-0.99.24.1/ripd/rip_debug.c0000644000175000017500000001571512476520570013307 00000000000000/* RIP debug routines * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "ripd/rip_debug.h" /* For debug statement. */ unsigned long rip_debug_event = 0; unsigned long rip_debug_packet = 0; unsigned long rip_debug_zebra = 0; DEFUN (show_debugging_rip, show_debugging_rip_cmd, "show debugging rip", SHOW_STR DEBUG_STR RIP_STR) { vty_out (vty, "RIP debugging status:%s", VTY_NEWLINE); if (IS_RIP_DEBUG_EVENT) vty_out (vty, " RIP event debugging is on%s", VTY_NEWLINE); if (IS_RIP_DEBUG_PACKET) { if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) { vty_out (vty, " RIP packet debugging is on%s", VTY_NEWLINE); } else { if (IS_RIP_DEBUG_SEND) vty_out (vty, " RIP packet send debugging is on%s", VTY_NEWLINE); else vty_out (vty, " RIP packet receive debugging is on%s", VTY_NEWLINE); } } if (IS_RIP_DEBUG_ZEBRA) vty_out (vty, " RIP zebra debugging is on%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (debug_rip_events, debug_rip_events_cmd, "debug rip events", DEBUG_STR RIP_STR "RIP events\n") { rip_debug_event = RIP_DEBUG_EVENT; return CMD_WARNING; } DEFUN (debug_rip_packet, debug_rip_packet_cmd, "debug rip packet", DEBUG_STR RIP_STR "RIP packet\n") { rip_debug_packet = RIP_DEBUG_PACKET; rip_debug_packet |= RIP_DEBUG_SEND; rip_debug_packet |= RIP_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (debug_rip_packet_direct, debug_rip_packet_direct_cmd, "debug rip packet (recv|send)", DEBUG_STR RIP_STR "RIP packet\n" "RIP receive packet\n" "RIP send packet\n") { rip_debug_packet |= RIP_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) rip_debug_packet |= RIP_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) rip_debug_packet |= RIP_DEBUG_RECV; return CMD_SUCCESS; } /* N.B. the "detail" modifier is a no-op. we leave this command for legacy compatibility. */ DEFUN_DEPRECATED (debug_rip_packet_detail, debug_rip_packet_detail_cmd, "debug rip packet (recv|send) detail", DEBUG_STR RIP_STR "RIP packet\n" "RIP receive packet\n" "RIP send packet\n" "Detailed information display\n") { rip_debug_packet |= RIP_DEBUG_PACKET; if (strncmp ("send", argv[0], strlen (argv[0])) == 0) rip_debug_packet |= RIP_DEBUG_SEND; if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) rip_debug_packet |= RIP_DEBUG_RECV; return CMD_SUCCESS; } DEFUN (debug_rip_zebra, debug_rip_zebra_cmd, "debug rip zebra", DEBUG_STR RIP_STR "RIP and ZEBRA communication\n") { rip_debug_zebra = RIP_DEBUG_ZEBRA; return CMD_WARNING; } DEFUN (no_debug_rip_events, no_debug_rip_events_cmd, "no debug rip events", NO_STR DEBUG_STR RIP_STR "RIP events\n") { rip_debug_event = 0; return CMD_SUCCESS; } DEFUN (no_debug_rip_packet, no_debug_rip_packet_cmd, "no debug rip packet", NO_STR DEBUG_STR RIP_STR "RIP packet\n") { rip_debug_packet = 0; return CMD_SUCCESS; } DEFUN (no_debug_rip_packet_direct, no_debug_rip_packet_direct_cmd, "no debug rip packet (recv|send)", NO_STR DEBUG_STR RIP_STR "RIP packet\n" "RIP option set for receive packet\n" "RIP option set for send packet\n") { if (strncmp ("send", argv[0], strlen (argv[0])) == 0) { if (IS_RIP_DEBUG_RECV) rip_debug_packet &= ~RIP_DEBUG_SEND; else rip_debug_packet = 0; } else if (strncmp ("recv", argv[0], strlen (argv[0])) == 0) { if (IS_RIP_DEBUG_SEND) rip_debug_packet &= ~RIP_DEBUG_RECV; else rip_debug_packet = 0; } return CMD_SUCCESS; } DEFUN (no_debug_rip_zebra, no_debug_rip_zebra_cmd, "no debug rip zebra", NO_STR DEBUG_STR RIP_STR "RIP and ZEBRA communication\n") { rip_debug_zebra = 0; return CMD_WARNING; } /* Debug node. */ static struct cmd_node debug_node = { DEBUG_NODE, "", /* Debug node has no interface. */ 1 }; static int config_write_debug (struct vty *vty) { int write = 0; if (IS_RIP_DEBUG_EVENT) { vty_out (vty, "debug rip events%s", VTY_NEWLINE); write++; } if (IS_RIP_DEBUG_PACKET) { if (IS_RIP_DEBUG_SEND && IS_RIP_DEBUG_RECV) { vty_out (vty, "debug rip packet%s", VTY_NEWLINE); write++; } else { if (IS_RIP_DEBUG_SEND) vty_out (vty, "debug rip packet send%s", VTY_NEWLINE); else vty_out (vty, "debug rip packet recv%s", VTY_NEWLINE); write++; } } if (IS_RIP_DEBUG_ZEBRA) { vty_out (vty, "debug rip zebra%s", VTY_NEWLINE); write++; } return write; } void rip_debug_reset (void) { rip_debug_event = 0; rip_debug_packet = 0; rip_debug_zebra = 0; } void rip_debug_init (void) { rip_debug_event = 0; rip_debug_packet = 0; rip_debug_zebra = 0; install_node (&debug_node, config_write_debug); install_element (ENABLE_NODE, &show_debugging_rip_cmd); install_element (ENABLE_NODE, &debug_rip_events_cmd); install_element (ENABLE_NODE, &debug_rip_packet_cmd); install_element (ENABLE_NODE, &debug_rip_packet_direct_cmd); install_element (ENABLE_NODE, &debug_rip_packet_detail_cmd); install_element (ENABLE_NODE, &debug_rip_zebra_cmd); install_element (ENABLE_NODE, &no_debug_rip_events_cmd); install_element (ENABLE_NODE, &no_debug_rip_packet_cmd); install_element (ENABLE_NODE, &no_debug_rip_packet_direct_cmd); install_element (ENABLE_NODE, &no_debug_rip_zebra_cmd); install_element (CONFIG_NODE, &debug_rip_events_cmd); install_element (CONFIG_NODE, &debug_rip_packet_cmd); install_element (CONFIG_NODE, &debug_rip_packet_direct_cmd); install_element (CONFIG_NODE, &debug_rip_packet_detail_cmd); install_element (CONFIG_NODE, &debug_rip_zebra_cmd); install_element (CONFIG_NODE, &no_debug_rip_events_cmd); install_element (CONFIG_NODE, &no_debug_rip_packet_cmd); install_element (CONFIG_NODE, &no_debug_rip_packet_direct_cmd); install_element (CONFIG_NODE, &no_debug_rip_zebra_cmd); } quagga-0.99.24.1/ripd/rip_interface.c0000644000175000017500000014400012476520570014147 00000000000000/* Interface related function for RIP. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "if.h" #include "sockunion.h" #include "prefix.h" #include "memory.h" #include "network.h" #include "table.h" #include "log.h" #include "stream.h" #include "thread.h" #include "zclient.h" #include "filter.h" #include "sockopt.h" #include "privs.h" #include "zebra/connected.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" /* static prototypes */ static void rip_enable_apply (struct interface *); static void rip_passive_interface_apply (struct interface *); static int rip_if_down(struct interface *ifp); static int rip_enable_if_lookup (const char *ifname); static int rip_enable_network_lookup2 (struct connected *connected); static void rip_enable_apply_all (void); const struct message ri_version_msg[] = { {RI_RIP_VERSION_1, "1"}, {RI_RIP_VERSION_2, "2"}, {RI_RIP_VERSION_1_AND_2, "1 2"}, }; extern struct zebra_privs_t ripd_privs; /* RIP enabled network vector. */ vector rip_enable_interface; /* RIP enabled interface table. */ struct route_table *rip_enable_network; /* Vector to store passive-interface name. */ static int passive_default; /* are we in passive-interface default mode? */ vector Vrip_passive_nondefault; /* Join to the RIP version 2 multicast group. */ static int ipv4_multicast_join (int sock, struct in_addr group, struct in_addr ifa, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_ADD_MEMBERSHIP, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", safe_strerror (errno)); return ret; } /* Leave from the RIP version 2 multicast group. */ static int ipv4_multicast_leave (int sock, struct in_addr group, struct in_addr ifa, unsigned int ifindex) { int ret; ret = setsockopt_ipv4_multicast (sock, IP_DROP_MEMBERSHIP, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); return ret; } /* Allocate new RIP's interface configuration. */ static struct rip_interface * rip_interface_new (void) { struct rip_interface *ri; ri = XCALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); /* Default authentication type is simple password for Cisco compatibility. */ ri->auth_type = RIP_NO_AUTH; ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; /* Set default split-horizon behavior. If the interface is Frame Relay or SMDS is enabled, the default value for split-horizon is off. But currently Zebra does detect Frame Relay or SMDS interface. So all interface is set to split horizon. */ ri->split_horizon_default = RIP_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; return ri; } void rip_interface_multicast_set (int sock, struct connected *connected) { assert (connected != NULL); if (setsockopt_ipv4_multicast_if (sock, connected->ifp->ifindex) < 0) { zlog_warn ("Can't setsockopt IP_MULTICAST_IF on fd %d to " "ifindex %d for interface %s", sock, connected->ifp->ifindex, connected->ifp->name); } return; } /* Send RIP request packet to specified interface. */ static void rip_request_interface_send (struct interface *ifp, u_char version) { struct sockaddr_in to; /* RIPv2 support multicast. */ if (version == RIPv2 && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast request on %s", ifp->name); rip_request_send (NULL, ifp, version, NULL); return; } /* RIPv1 and non multicast interface. */ if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) { struct listnode *cnode, *cnnode; struct connected *connected; if (IS_RIP_DEBUG_EVENT) zlog_debug ("broadcast request to %s", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, connected)) { if (connected->address->family == AF_INET) { memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); if (connected->destination) /* use specified broadcast or peer destination addr */ to.sin_addr = connected->destination->u.prefix4; else if (connected->address->prefixlen < IPV4_MAX_PREFIXLEN) /* calculate the appropriate broadcast address */ to.sin_addr.s_addr = ipv4_broadcast_addr(connected->address->u.prefix4.s_addr, connected->address->prefixlen); else /* do not know where to send the packet */ continue; if (IS_RIP_DEBUG_EVENT) zlog_debug ("SEND request to %s", inet_ntoa (to.sin_addr)); rip_request_send (&to, ifp, version, connected); } } } } /* This will be executed when interface goes up. */ static void rip_request_interface (struct interface *ifp) { struct rip_interface *ri; /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ if (if_is_loopback (ifp)) return; /* If interface is down, don't send RIP packet. */ if (! if_is_operative (ifp)) return; /* Fetch RIP interface information. */ ri = ifp->info; /* If there is no version configuration in the interface, use rip's version setting. */ { int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send : ri->ri_send); if (vsend & RIPv1) rip_request_interface_send (ifp, RIPv1); if (vsend & RIPv2) rip_request_interface_send (ifp, RIPv2); } } #if 0 /* Send RIP request to the neighbor. */ static void rip_request_neighbor (struct in_addr addr) { struct sockaddr_in to; memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); to.sin_addr = addr; rip_request_send (&to, NULL, rip->version_send, NULL); } /* Request routes at all interfaces. */ static void rip_request_neighbor_all (void) { struct route_node *rp; if (! rip) return; if (IS_RIP_DEBUG_EVENT) zlog_debug ("request to the all neighbor"); /* Send request to all neighbor. */ for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) if (rp->info) rip_request_neighbor (rp->p.u.prefix4); } #endif /* Multicast packet receive socket. */ static int rip_multicast_join (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *ifc; if (if_is_operative (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast join at %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) { struct prefix_ipv4 *p; struct in_addr group; p = (struct prefix_ipv4 *) ifc->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0) return -1; else return 0; } } return 0; } /* Leave from multicast group. */ static void rip_multicast_leave (struct interface *ifp, int sock) { struct listnode *cnode; struct connected *connected; if (if_is_up (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast leave from %s", ifp->name); for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { struct prefix_ipv4 *p; struct in_addr group; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0) return; } } } /* Is there and address on interface that I could use ? */ static int rip_if_ipv4_address_check (struct interface *ifp) { struct listnode *nn; struct connected *connected; int count = 0; for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected)) { struct prefix *p; p = connected->address; if (p->family == AF_INET) count++; } return count; } /* Does this address belongs to me ? */ int if_check_address (struct in_addr addr) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct listnode *cnode; struct connected *connected; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) return 1; } } return 0; } /* Inteface link down message processing. */ int rip_interface_down (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist. */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; rip_if_down(ifp); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s index %d flags %llx metric %d mtu %d is down", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); return 0; } /* Inteface link up message processing */ int rip_interface_up (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; /* zebra_interface_state_read () updates interface structure in iflist. */ ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s index %d flags %#llx metric %d mtu %d is up", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu); /* Check if this interface is RIP enabled or not.*/ rip_enable_apply (ifp); /* Check for a passive interface */ rip_passive_interface_apply (ifp); /* Apply distribute list to the all interface. */ rip_distribute_update_interface (ifp); return 0; } /* Inteface addition message from zebra. */ int rip_interface_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface add %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu); /* Check if this interface is RIP enabled or not.*/ rip_enable_apply (ifp); /* Check for a passive interface */ rip_passive_interface_apply (ifp); /* Apply distribute list to the all interface. */ rip_distribute_update_interface (ifp); /* rip_request_neighbor_all (); */ /* Check interface routemap. */ rip_if_rmap_update_interface (ifp); return 0; } int rip_interface_delete (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; if (if_is_up (ifp)) { rip_if_down(ifp); } zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long) ifp->flags, ifp->metric, ifp->mtu); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ ifp->ifindex = IFINDEX_INTERNAL; return 0; } void rip_interface_clean (void) { struct listnode *node; struct interface *ifp; struct rip_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } } } void rip_interface_reset (void) { struct listnode *node; struct interface *ifp; struct rip_interface *ri; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; ri->ri_send = RI_RIP_UNSPEC; ri->ri_receive = RI_RIP_UNSPEC; ri->auth_type = RIP_NO_AUTH; if (ri->auth_str) { free (ri->auth_str); ri->auth_str = NULL; } if (ri->key_chain) { free (ri->key_chain); ri->key_chain = NULL; } ri->split_horizon = RIP_NO_SPLIT_HORIZON; ri->split_horizon_default = RIP_NO_SPLIT_HORIZON; ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; ri->prefix[RIP_FILTER_IN] = NULL; ri->prefix[RIP_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup); ri->t_wakeup = NULL; } ri->recv_badpackets = 0; ri->recv_badroutes = 0; ri->sent_updates = 0; ri->passive = 0; } } int rip_if_down(struct interface *ifp) { struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri = NULL; struct list *list = NULL; struct listnode *listnode = NULL, *nextnode = NULL; if (rip) for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo)) if (rinfo->ifindex == ifp->ifindex) rip_ecmp_delete (rinfo); ri = ifp->info; if (ri->running) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("turn off %s", ifp->name); /* Leave from multicast group. */ rip_multicast_leave (ifp, rip->sock); ri->running = 0; } return 0; } /* Needed for stop RIP process. */ void rip_if_down_all () { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_if_down (ifp); } static void rip_apply_address_add (struct connected *ifc) { struct prefix_ipv4 address; struct prefix *p; if (!rip) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = p->prefixlen; apply_mask_ipv4(&address); /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ if ((rip_enable_if_lookup(ifc->ifp->name) >= 0) || (rip_enable_network_lookup2(ifc) >= 0)) rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL, 0, 0); } int rip_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf); if (ifc == NULL) return 0; p = ifc->address; if (p->family == AF_INET) { if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("connected address %s/%d is added", inet_ntoa (p->u.prefix4), p->prefixlen); rip_enable_apply(ifc->ifp); /* Check if this prefix needs to be redistributed */ rip_apply_address_add(ifc); #ifdef HAVE_SNMP rip_ifaddr_add (ifc->ifp, ifc); #endif /* HAVE_SNMP */ } return 0; } static void rip_apply_address_del (struct connected *ifc) { struct prefix_ipv4 address; struct prefix *p; if (!rip) return; if (! if_is_up(ifc->ifp)) return; p = ifc->address; memset (&address, 0, sizeof (address)); address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = p->prefixlen; apply_mask_ipv4(&address); rip_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, ifc->ifp->ifindex); } int rip_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; struct prefix *p; ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf); if (ifc) { p = ifc->address; if (p->family == AF_INET) { if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("connected address %s/%d is deleted", inet_ntoa (p->u.prefix4), p->prefixlen); #ifdef HAVE_SNMP rip_ifaddr_delete (ifc->ifp, ifc); #endif /* HAVE_SNMP */ /* Chech wether this prefix needs to be removed */ rip_apply_address_del(ifc); } connected_free (ifc); } return 0; } /* Check interface is enabled by network statement. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ static int rip_enable_network_lookup_if (struct interface *ifp) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix *p; struct route_node *node; p = connected->address; if (p->family == AF_INET) { address.family = AF_INET; address.prefix = p->u.prefix4; address.prefixlen = IPV4_MAX_BITLEN; node = route_node_match (rip_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } } return -1; } /* Check wether connected is within the ripng_enable_network table. */ int rip_enable_network_lookup2 (struct connected *connected) { struct prefix_ipv4 address; struct prefix *p; p = connected->address; if (p->family == AF_INET) { struct route_node *node; address.family = p->family; address.prefix = p->u.prefix4; address.prefixlen = IPV4_MAX_BITLEN; /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within rip_enable_network */ node = route_node_match (rip_enable_network, (struct prefix *)&address); if (node) { route_unlock_node (node); return 1; } } return -1; } /* Add RIP enable network. */ static int rip_enable_network_add (struct prefix *p) { struct route_node *node; node = route_node_get (rip_enable_network, p); if (node->info) { route_unlock_node (node); return -1; } else node->info = (char *) "enabled"; /* XXX: One should find a better solution than a generic one */ rip_enable_apply_all(); return 1; } /* Delete RIP enable network. */ static int rip_enable_network_delete (struct prefix *p) { struct route_node *node; node = route_node_lookup (rip_enable_network, p); if (node) { node->info = NULL; /* Unlock info lock. */ route_unlock_node (node); /* Unlock lookup lock. */ route_unlock_node (node); /* XXX: One should find a better solution than a generic one */ rip_enable_apply_all (); return 1; } return -1; } /* Check interface is enabled by ifname statement. */ static int rip_enable_if_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (rip_enable_interface); i++) if ((str = vector_slot (rip_enable_interface, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } /* Add interface to rip_enable_if. */ static int rip_enable_if_add (const char *ifname) { int ret; ret = rip_enable_if_lookup (ifname); if (ret >= 0) return -1; vector_set (rip_enable_interface, strdup (ifname)); rip_enable_apply_all(); /* TODOVJ */ return 1; } /* Delete interface from rip_enable_if. */ static int rip_enable_if_delete (const char *ifname) { int index; char *str; index = rip_enable_if_lookup (ifname); if (index < 0) return -1; str = vector_slot (rip_enable_interface, index); free (str); vector_unset (rip_enable_interface, index); rip_enable_apply_all(); /* TODOVJ */ return 1; } /* Join to multicast group and send request to the interface. */ static int rip_interface_wakeup (struct thread *t) { struct interface *ifp; struct rip_interface *ri; /* Get interface. */ ifp = THREAD_ARG (t); ri = ifp->info; ri->t_wakeup = NULL; /* Join to multicast group. */ if (rip_multicast_join (ifp, rip->sock) < 0) { zlog_err ("multicast join failed, interface %s not running", ifp->name); return 0; } /* Set running flag. */ ri->running = 1; /* Send RIP request to the interface. */ rip_request_interface (ifp); return 0; } static void rip_connect_set (struct interface *ifp, int set) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv4 address; for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix *p; p = connected->address; if (p->family != AF_INET) continue; address.family = AF_INET; address.prefix = p->u.prefix4; address.prefixlen = p->prefixlen; apply_mask_ipv4 (&address); if (set) { /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ if ((rip_enable_if_lookup(connected->ifp->name) >= 0) || (rip_enable_network_lookup2(connected) >= 0)) rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL, 0, 0); } else { rip_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE, &address, connected->ifp->ifindex); if (rip_redistribute_check (ZEBRA_ROUTE_CONNECT)) rip_redistribute_add (ZEBRA_ROUTE_CONNECT, RIP_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, NULL, 0, 0); } } } /* Update interface status. */ void rip_enable_apply (struct interface *ifp) { int ret; struct rip_interface *ri = NULL; /* Check interface. */ if (! if_is_operative (ifp)) return; ri = ifp->info; /* Check network configuration. */ ret = rip_enable_network_lookup_if (ifp); /* If the interface is matched. */ if (ret > 0) ri->enable_network = 1; else ri->enable_network = 0; /* Check interface name configuration. */ ret = rip_enable_if_lookup (ifp->name); if (ret >= 0) ri->enable_interface = 1; else ri->enable_interface = 0; /* any interface MUST have an IPv4 address */ if ( ! rip_if_ipv4_address_check (ifp) ) { ri->enable_network = 0; ri->enable_interface = 0; } /* Update running status of the interface. */ if (ri->enable_network || ri->enable_interface) { { if (IS_RIP_DEBUG_EVENT) zlog_debug ("turn on %s", ifp->name); /* Add interface wake up thread. */ if (! ri->t_wakeup) ri->t_wakeup = thread_add_timer (master, rip_interface_wakeup, ifp, 1); rip_connect_set (ifp, 1); } } else { if (ri->running) { /* Might as well clean up the route table as well * rip_if_down sets to 0 ri->running, and displays "turn off %s" **/ rip_if_down(ifp); rip_connect_set (ifp, 0); } } } /* Apply network configuration to all interface. */ void rip_enable_apply_all () { struct interface *ifp; struct listnode *node, *nnode; /* Check each interface. */ for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_enable_apply (ifp); } int rip_neighbor_lookup (struct sockaddr_in *from) { struct prefix_ipv4 p; struct route_node *node; memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefix = from->sin_addr; p.prefixlen = IPV4_MAX_BITLEN; node = route_node_lookup (rip->neighbor, (struct prefix *) &p); if (node) { route_unlock_node (node); return 1; } return 0; } /* Add new RIP neighbor to the neighbor tree. */ static int rip_neighbor_add (struct prefix_ipv4 *p) { struct route_node *node; node = route_node_get (rip->neighbor, (struct prefix *) p); if (node->info) return -1; node->info = rip->neighbor; return 0; } /* Delete RIP neighbor from the neighbor tree. */ static int rip_neighbor_delete (struct prefix_ipv4 *p) { struct route_node *node; /* Lock for look up. */ node = route_node_lookup (rip->neighbor, (struct prefix *) p); if (! node) return -1; node->info = NULL; /* Unlock lookup lock. */ route_unlock_node (node); /* Unlock real neighbor information lock. */ route_unlock_node (node); return 0; } /* Clear all network and neighbor configuration. */ void rip_clean_network () { unsigned int i; char *str; struct route_node *rn; /* rip_enable_network. */ for (rn = route_top (rip_enable_network); rn; rn = route_next (rn)) if (rn->info) { rn->info = NULL; route_unlock_node (rn); } /* rip_enable_interface. */ for (i = 0; i < vector_active (rip_enable_interface); i++) if ((str = vector_slot (rip_enable_interface, i)) != NULL) { free (str); vector_slot (rip_enable_interface, i) = NULL; } } /* Utility function for looking up passive interface settings. */ static int rip_passive_nondefault_lookup (const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((str = vector_slot (Vrip_passive_nondefault, i)) != NULL) if (strcmp (str, ifname) == 0) return i; return -1; } void rip_passive_interface_apply (struct interface *ifp) { struct rip_interface *ri; ri = ifp->info; ri->passive = ((rip_passive_nondefault_lookup (ifp->name) < 0) ? passive_default : !passive_default); if (IS_RIP_DEBUG_ZEBRA) zlog_debug ("interface %s: passive = %d",ifp->name,ri->passive); } static void rip_passive_interface_apply_all (void) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_passive_interface_apply (ifp); } /* Passive interface. */ static int rip_passive_nondefault_set (struct vty *vty, const char *ifname) { if (rip_passive_nondefault_lookup (ifname) >= 0) return CMD_WARNING; vector_set (Vrip_passive_nondefault, strdup (ifname)); rip_passive_interface_apply_all (); return CMD_SUCCESS; } static int rip_passive_nondefault_unset (struct vty *vty, const char *ifname) { int i; char *str; i = rip_passive_nondefault_lookup (ifname); if (i < 0) return CMD_WARNING; str = vector_slot (Vrip_passive_nondefault, i); free (str); vector_unset (Vrip_passive_nondefault, i); rip_passive_interface_apply_all (); return CMD_SUCCESS; } /* Free all configured RIP passive-interface settings. */ void rip_passive_nondefault_clean (void) { unsigned int i; char *str; for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((str = vector_slot (Vrip_passive_nondefault, i)) != NULL) { free (str); vector_slot (Vrip_passive_nondefault, i) = NULL; } rip_passive_interface_apply_all (); } /* RIP enable network or interface configuration. */ DEFUN (rip_network, rip_network_cmd, "network (A.B.C.D/M|WORD)", "Enable routing on an IP network\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Interface name\n") { int ret; struct prefix_ipv4 p; ret = str2prefix_ipv4 (argv[0], &p); if (ret) ret = rip_enable_network_add ((struct prefix *) &p); else ret = rip_enable_if_add (argv[0]); if (ret < 0) { vty_out (vty, "There is a same network configuration %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* RIP enable network or interface configuration. */ DEFUN (no_rip_network, no_rip_network_cmd, "no network (A.B.C.D/M|WORD)", NO_STR "Enable routing on an IP network\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Interface name\n") { int ret; struct prefix_ipv4 p; ret = str2prefix_ipv4 (argv[0], &p); if (ret) ret = rip_enable_network_delete ((struct prefix *) &p); else ret = rip_enable_if_delete (argv[0]); if (ret < 0) { vty_out (vty, "Can't find network configuration %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* RIP neighbor configuration set. */ DEFUN (rip_neighbor, rip_neighbor_cmd, "neighbor A.B.C.D", "Specify a neighbor router\n" "Neighbor address\n") { int ret; struct prefix_ipv4 p; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } rip_neighbor_add (&p); return CMD_SUCCESS; } /* RIP neighbor configuration unset. */ DEFUN (no_rip_neighbor, no_rip_neighbor_cmd, "no neighbor A.B.C.D", NO_STR "Specify a neighbor router\n" "Neighbor address\n") { int ret; struct prefix_ipv4 p; ret = str2prefix_ipv4 (argv[0], &p); if (ret <= 0) { vty_out (vty, "Please specify address by A.B.C.D%s", VTY_NEWLINE); return CMD_WARNING; } rip_neighbor_delete (&p); return CMD_SUCCESS; } DEFUN (ip_rip_receive_version, ip_rip_receive_version_cmd, "ip rip receive version (1|2)", IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1. */ if (atoi (argv[0]) == 1) { ri->ri_receive = RI_RIP_VERSION_1; return CMD_SUCCESS; } if (atoi (argv[0]) == 2) { ri->ri_receive = RI_RIP_VERSION_2; return CMD_SUCCESS; } return CMD_WARNING; } DEFUN (ip_rip_receive_version_1, ip_rip_receive_version_1_cmd, "ip rip receive version 1 2", IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1 and 2. */ ri->ri_receive = RI_RIP_VERSION_1_AND_2; return CMD_SUCCESS; } DEFUN (ip_rip_receive_version_2, ip_rip_receive_version_2_cmd, "ip rip receive version 2 1", IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "RIP version 2\n" "RIP version 1\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1 and 2. */ ri->ri_receive = RI_RIP_VERSION_1_AND_2; return CMD_SUCCESS; } DEFUN (no_ip_rip_receive_version, no_ip_rip_receive_version_cmd, "no ip rip receive version", NO_STR IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; ri->ri_receive = RI_RIP_UNSPEC; return CMD_SUCCESS; } ALIAS (no_ip_rip_receive_version, no_ip_rip_receive_version_num_cmd, "no ip rip receive version (1|2)", NO_STR IP_STR "Routing Information Protocol\n" "Advertisement reception\n" "Version control\n" "Version 1\n" "Version 2\n") DEFUN (ip_rip_send_version, ip_rip_send_version_cmd, "ip rip send version (1|2)", IP_STR "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1. */ if (atoi (argv[0]) == 1) { ri->ri_send = RI_RIP_VERSION_1; return CMD_SUCCESS; } if (atoi (argv[0]) == 2) { ri->ri_send = RI_RIP_VERSION_2; return CMD_SUCCESS; } return CMD_WARNING; } DEFUN (ip_rip_send_version_1, ip_rip_send_version_1_cmd, "ip rip send version 1 2", IP_STR "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 1\n" "RIP version 2\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1 and 2. */ ri->ri_send = RI_RIP_VERSION_1_AND_2; return CMD_SUCCESS; } DEFUN (ip_rip_send_version_2, ip_rip_send_version_2_cmd, "ip rip send version 2 1", IP_STR "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "RIP version 2\n" "RIP version 1\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; /* Version 1 and 2. */ ri->ri_send = RI_RIP_VERSION_1_AND_2; return CMD_SUCCESS; } DEFUN (no_ip_rip_send_version, no_ip_rip_send_version_cmd, "no ip rip send version", NO_STR IP_STR "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; ri->ri_send = RI_RIP_UNSPEC; return CMD_SUCCESS; } ALIAS (no_ip_rip_send_version, no_ip_rip_send_version_num_cmd, "no ip rip send version (1|2)", NO_STR IP_STR "Routing Information Protocol\n" "Advertisement transmission\n" "Version control\n" "Version 1\n" "Version 2\n") DEFUN (ip_rip_authentication_mode, ip_rip_authentication_mode_cmd, "ip rip authentication mode (md5|text)", IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n") { struct interface *ifp; struct rip_interface *ri; int auth_type; ifp = (struct interface *)vty->index; ri = ifp->info; if ( (argc < 1) || (argc > 2) ) { vty_out (vty, "incorrect argument count%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp ("md5", argv[0], strlen (argv[0])) == 0) auth_type = RIP_AUTH_MD5; else if (strncmp ("text", argv[0], strlen (argv[0])) == 0) auth_type = RIP_AUTH_SIMPLE_PASSWORD; else { vty_out (vty, "mode should be md5 or text%s", VTY_NEWLINE); return CMD_WARNING; } if (argc == 1) { ri->auth_type = auth_type; return CMD_SUCCESS; } if ( (argc == 2) && (auth_type != RIP_AUTH_MD5) ) { vty_out (vty, "auth length argument only valid for md5%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp ("r", argv[1], 1) == 0) ri->md5_auth_len = RIP_AUTH_MD5_SIZE; else if (strncmp ("o", argv[1], 1) == 0) ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; else return CMD_WARNING; ri->auth_type = auth_type; return CMD_SUCCESS; } ALIAS (ip_rip_authentication_mode, ip_rip_authentication_mode_authlen_cmd, "ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFUN (no_ip_rip_authentication_mode, no_ip_rip_authentication_mode_cmd, "no ip rip authentication mode", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; ri->auth_type = RIP_NO_AUTH; ri->md5_auth_len = RIP_AUTH_MD5_COMPAT_SIZE; return CMD_SUCCESS; } ALIAS (no_ip_rip_authentication_mode, no_ip_rip_authentication_mode_type_cmd, "no ip rip authentication mode (md5|text)", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n") ALIAS (no_ip_rip_authentication_mode, no_ip_rip_authentication_mode_type_authlen_cmd, "no ip rip authentication mode (md5|text) auth-length (rfc|old-ripd)", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication mode\n" "Keyed message digest\n" "Clear text authentication\n" "MD5 authentication data length\n" "RFC compatible\n" "Old ripd compatible\n") DEFUN (ip_rip_authentication_string, ip_rip_authentication_string_cmd, "ip rip authentication string LINE", IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n" "Authentication string\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; if (strlen (argv[0]) > 16) { vty_out (vty, "%% RIPv2 authentication string must be shorter than 16%s", VTY_NEWLINE); return CMD_WARNING; } if (ri->key_chain) { vty_out (vty, "%% key-chain configuration exists%s", VTY_NEWLINE); return CMD_WARNING; } if (ri->auth_str) free (ri->auth_str); ri->auth_str = strdup (argv[0]); return CMD_SUCCESS; } DEFUN (no_ip_rip_authentication_string, no_ip_rip_authentication_string_cmd, "no ip rip authentication string", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *)vty->index; ri = ifp->info; if (ri->auth_str) free (ri->auth_str); ri->auth_str = NULL; return CMD_SUCCESS; } ALIAS (no_ip_rip_authentication_string, no_ip_rip_authentication_string2_cmd, "no ip rip authentication string LINE", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication string\n" "Authentication string\n") DEFUN (ip_rip_authentication_key_chain, ip_rip_authentication_key_chain_cmd, "ip rip authentication key-chain LINE", IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n" "name of key-chain\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *) vty->index; ri = ifp->info; if (ri->auth_str) { vty_out (vty, "%% authentication string configuration exists%s", VTY_NEWLINE); return CMD_WARNING; } if (ri->key_chain) free (ri->key_chain); ri->key_chain = strdup (argv[0]); return CMD_SUCCESS; } DEFUN (no_ip_rip_authentication_key_chain, no_ip_rip_authentication_key_chain_cmd, "no ip rip authentication key-chain", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n") { struct interface *ifp; struct rip_interface *ri; ifp = (struct interface *) vty->index; ri = ifp->info; if (ri->key_chain) free (ri->key_chain); ri->key_chain = NULL; return CMD_SUCCESS; } ALIAS (no_ip_rip_authentication_key_chain, no_ip_rip_authentication_key_chain2_cmd, "no ip rip authentication key-chain LINE", NO_STR IP_STR "Routing Information Protocol\n" "Authentication control\n" "Authentication key-chain\n" "name of key-chain\n") /* CHANGED: ip rip split-horizon Cisco and Zebra's command is ip split-horizon */ DEFUN (ip_rip_split_horizon, ip_rip_split_horizon_cmd, "ip rip split-horizon", IP_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ip_rip_split_horizon_poisoned_reverse, ip_rip_split_horizon_poisoned_reverse_cmd, "ip rip split-horizon poisoned-reverse", IP_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_SPLIT_HORIZON_POISONED_REVERSE; return CMD_SUCCESS; } /* CHANGED: no ip rip split-horizon Cisco and Zebra's command is no ip split-horizon */ DEFUN (no_ip_rip_split_horizon, no_ip_rip_split_horizon_cmd, "no ip rip split-horizon", NO_STR IP_STR "Routing Information Protocol\n" "Perform split horizon\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; ri->split_horizon = RIP_NO_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (no_ip_rip_split_horizon_poisoned_reverse, no_ip_rip_split_horizon_poisoned_reverse_cmd, "no ip rip split-horizon poisoned-reverse", NO_STR IP_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { struct interface *ifp; struct rip_interface *ri; ifp = vty->index; ri = ifp->info; switch( ri->split_horizon ) { case RIP_SPLIT_HORIZON_POISONED_REVERSE: ri->split_horizon = RIP_SPLIT_HORIZON; default: break; } return CMD_SUCCESS; } DEFUN (rip_passive_interface, rip_passive_interface_cmd, "passive-interface (IFNAME|default)", "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") { const char *ifname = argv[0]; if (!strcmp(ifname,"default")) { passive_default = 1; rip_passive_nondefault_clean(); return CMD_SUCCESS; } if (passive_default) return rip_passive_nondefault_unset (vty, ifname); else return rip_passive_nondefault_set (vty, ifname); } DEFUN (no_rip_passive_interface, no_rip_passive_interface_cmd, "no passive-interface (IFNAME|default)", NO_STR "Suppress routing updates on an interface\n" "Interface name\n" "default for all interfaces\n") { const char *ifname = argv[0]; if (!strcmp(ifname,"default")) { passive_default = 0; rip_passive_nondefault_clean(); return CMD_SUCCESS; } if (passive_default) return rip_passive_nondefault_set (vty, ifname); else return rip_passive_nondefault_unset (vty, ifname); } /* Write rip configuration of each interface. */ static int rip_interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { struct rip_interface *ri; ri = ifp->info; /* Do not display the interface if there is no * configuration about it. **/ if ((!ifp->desc) && (ri->split_horizon == ri->split_horizon_default) && (ri->ri_send == RI_RIP_UNSPEC) && (ri->ri_receive == RI_RIP_UNSPEC) && (ri->auth_type != RIP_AUTH_MD5) && (ri->md5_auth_len != RIP_AUTH_MD5_SIZE) && (!ri->auth_str) && (!ri->key_chain) ) continue; vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); /* Split horizon. */ if (ri->split_horizon != ri->split_horizon_default) { switch (ri->split_horizon) { case RIP_SPLIT_HORIZON: vty_out (vty, " ip rip split-horizon%s", VTY_NEWLINE); break; case RIP_SPLIT_HORIZON_POISONED_REVERSE: vty_out (vty, " ip rip split-horizon poisoned-reverse%s", VTY_NEWLINE); break; case RIP_NO_SPLIT_HORIZON: default: vty_out (vty, " no ip rip split-horizon%s", VTY_NEWLINE); break; } } /* RIP version setting. */ if (ri->ri_send != RI_RIP_UNSPEC) vty_out (vty, " ip rip send version %s%s", lookup (ri_version_msg, ri->ri_send), VTY_NEWLINE); if (ri->ri_receive != RI_RIP_UNSPEC) vty_out (vty, " ip rip receive version %s%s", lookup (ri_version_msg, ri->ri_receive), VTY_NEWLINE); /* RIP authentication. */ if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) vty_out (vty, " ip rip authentication mode text%s", VTY_NEWLINE); if (ri->auth_type == RIP_AUTH_MD5) { vty_out (vty, " ip rip authentication mode md5"); if (ri->md5_auth_len == RIP_AUTH_MD5_COMPAT_SIZE) vty_out (vty, " auth-length old-ripd"); else vty_out (vty, " auth-length rfc"); vty_out (vty, "%s", VTY_NEWLINE); } if (ri->auth_str) vty_out (vty, " ip rip authentication string %s%s", ri->auth_str, VTY_NEWLINE); if (ri->key_chain) vty_out (vty, " ip rip authentication key-chain %s%s", ri->key_chain, VTY_NEWLINE); vty_out (vty, "!%s", VTY_NEWLINE); } return 0; } int config_write_rip_network (struct vty *vty, int config_mode) { unsigned int i; char *ifname; struct route_node *node; /* Network type RIP enable interface statement. */ for (node = route_top (rip_enable_network); node; node = route_next (node)) if (node->info) vty_out (vty, "%s%s/%d%s", config_mode ? " network " : " ", inet_ntoa (node->p.u.prefix4), node->p.prefixlen, VTY_NEWLINE); /* Interface name RIP enable statement. */ for (i = 0; i < vector_active (rip_enable_interface); i++) if ((ifname = vector_slot (rip_enable_interface, i)) != NULL) vty_out (vty, "%s%s%s", config_mode ? " network " : " ", ifname, VTY_NEWLINE); /* RIP neighbors listing. */ for (node = route_top (rip->neighbor); node; node = route_next (node)) if (node->info) vty_out (vty, "%s%s%s", config_mode ? " neighbor " : " ", inet_ntoa (node->p.u.prefix4), VTY_NEWLINE); /* RIP passive interface listing. */ if (config_mode) { if (passive_default) vty_out (vty, " passive-interface default%s", VTY_NEWLINE); for (i = 0; i < vector_active (Vrip_passive_nondefault); i++) if ((ifname = vector_slot (Vrip_passive_nondefault, i)) != NULL) vty_out (vty, " %spassive-interface %s%s", (passive_default ? "no " : ""), ifname, VTY_NEWLINE); } return 0; } static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1, }; /* Called when interface structure allocated. */ static int rip_interface_new_hook (struct interface *ifp) { ifp->info = rip_interface_new (); return 0; } /* Called when interface structure deleted. */ static int rip_interface_delete_hook (struct interface *ifp) { XFREE (MTYPE_RIP_INTERFACE, ifp->info); ifp->info = NULL; return 0; } /* Allocate and initialize interface vector. */ void rip_if_init (void) { /* Default initial size of interface vector. */ if_init(); if_add_hook (IF_NEW_HOOK, rip_interface_new_hook); if_add_hook (IF_DELETE_HOOK, rip_interface_delete_hook); /* RIP network init. */ rip_enable_interface = vector_init (1); rip_enable_network = route_table_init (); /* RIP passive interface. */ Vrip_passive_nondefault = vector_init (1); /* Install interface node. */ install_node (&interface_node, rip_interface_config_write); /* Install commands. */ install_element (CONFIG_NODE, &interface_cmd); install_element (CONFIG_NODE, &no_interface_cmd); install_default (INTERFACE_NODE); install_element (INTERFACE_NODE, &interface_desc_cmd); install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (RIP_NODE, &rip_network_cmd); install_element (RIP_NODE, &no_rip_network_cmd); install_element (RIP_NODE, &rip_neighbor_cmd); install_element (RIP_NODE, &no_rip_neighbor_cmd); install_element (RIP_NODE, &rip_passive_interface_cmd); install_element (RIP_NODE, &no_rip_passive_interface_cmd); install_element (INTERFACE_NODE, &ip_rip_send_version_cmd); install_element (INTERFACE_NODE, &ip_rip_send_version_1_cmd); install_element (INTERFACE_NODE, &ip_rip_send_version_2_cmd); install_element (INTERFACE_NODE, &no_ip_rip_send_version_cmd); install_element (INTERFACE_NODE, &no_ip_rip_send_version_num_cmd); install_element (INTERFACE_NODE, &ip_rip_receive_version_cmd); install_element (INTERFACE_NODE, &ip_rip_receive_version_1_cmd); install_element (INTERFACE_NODE, &ip_rip_receive_version_2_cmd); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_cmd); install_element (INTERFACE_NODE, &no_ip_rip_receive_version_num_cmd); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_cmd); install_element (INTERFACE_NODE, &ip_rip_authentication_mode_authlen_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_mode_type_authlen_cmd); install_element (INTERFACE_NODE, &ip_rip_authentication_key_chain_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_key_chain2_cmd); install_element (INTERFACE_NODE, &ip_rip_authentication_string_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string_cmd); install_element (INTERFACE_NODE, &no_ip_rip_authentication_string2_cmd); install_element (INTERFACE_NODE, &ip_rip_split_horizon_cmd); install_element (INTERFACE_NODE, &ip_rip_split_horizon_poisoned_reverse_cmd); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_cmd); install_element (INTERFACE_NODE, &no_ip_rip_split_horizon_poisoned_reverse_cmd); } quagga-0.99.24.1/ripd/rip_zebra.c0000644000175000017500000004457112476520570013326 00000000000000/* RIPd and zebra interface. * Copyright (C) 1997, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "table.h" #include "stream.h" #include "memory.h" #include "routemap.h" #include "zclient.h" #include "log.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" #include "ripd/rip_interface.h" /* All information about zebra. */ struct zclient *zclient = NULL; /* Send ECMP routes to zebra. */ static void rip_zebra_ipv4_send (struct route_node *rp, u_char cmd) { static struct in_addr **nexthops = NULL; static unsigned int nexthops_len = 0; struct list *list = (struct list *)rp->info; struct zapi_ipv4 api; struct listnode *listnode = NULL; struct rip_info *rinfo = NULL; int count = 0; if (zclient->redist[ZEBRA_ROUTE_RIP]) { api.type = ZEBRA_ROUTE_RIP; api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; if (nexthops_len < listcount (list)) { nexthops_len = listcount (list); nexthops = XREALLOC (MTYPE_TMP, nexthops, nexthops_len * sizeof (struct in_addr *)); } SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { nexthops[count++] = &rinfo->nexthop; if (cmd == ZEBRA_IPV4_ROUTE_ADD) SET_FLAG (rinfo->flags, RIP_RTF_FIB); else UNSET_FLAG (rinfo->flags, RIP_RTF_FIB); } api.nexthop = nexthops; api.nexthop_num = count; api.ifindex_num = 0; rinfo = listgetdata (listhead (list)); SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = rinfo->metric; if (rinfo->distance && rinfo->distance != ZEBRA_RIP_DISTANCE_DEFAULT) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = rinfo->distance; } zapi_ipv4_route (cmd, zclient, (struct prefix_ipv4 *)&rp->p, &api); if (IS_RIP_DEBUG_ZEBRA) { if (rip->ecmp) zlog_debug ("%s: %s/%d nexthops %d", (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen, count); else zlog_debug ("%s: %s/%d", (cmd == ZEBRA_IPV4_ROUTE_ADD) ? \ "Install into zebra" : "Delete from zebra", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } rip_global_route_changes++; } } /* Add/update ECMP routes to zebra. */ void rip_zebra_ipv4_add (struct route_node *rp) { rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_ADD); } /* Delete ECMP routes from zebra. */ void rip_zebra_ipv4_delete (struct route_node *rp) { rip_zebra_ipv4_send (rp, ZEBRA_IPV4_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ static int rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; unsigned long ifindex; struct in_addr nexthop; struct prefix_ipv4 p; s = zclient->ibuf; ifindex = 0; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop.s_addr = stream_get_ipv4 (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); ifindex = stream_getl (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 255; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; /* Then fetch IPv4 prefixes. */ if (command == ZEBRA_IPV4_ROUTE_ADD) rip_redistribute_add (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex, &nexthop, api.metric, api.distance); else rip_redistribute_delete (api.type, RIP_ROUTE_REDISTRIBUTE, &p, ifindex); return 0; } void rip_zclient_reset (void) { zclient_reset (zclient); } /* RIP route-map set for redistribution */ static void rip_routemap_set (int type, const char *name) { if (rip->route_map[type].name) free(rip->route_map[type].name); rip->route_map[type].name = strdup (name); rip->route_map[type].map = route_map_lookup_by_name (name); } static void rip_redistribute_metric_set (int type, unsigned int metric) { rip->route_map[type].metric_config = 1; rip->route_map[type].metric = metric; } static int rip_metric_unset (int type, unsigned int metric) { #define DONT_CARE_METRIC_RIP 17 if (metric != DONT_CARE_METRIC_RIP && rip->route_map[type].metric != metric) return 1; rip->route_map[type].metric_config = 0; rip->route_map[type].metric = 0; return 0; } /* RIP route-map unset for redistribution */ static int rip_routemap_unset (int type, const char *name) { if (! rip->route_map[type].name || (name != NULL && strcmp(rip->route_map[type].name,name))) return 1; free (rip->route_map[type].name); rip->route_map[type].name = NULL; rip->route_map[type].map = NULL; return 0; } /* Redistribution types */ static struct { int type; int str_min_len; const char *str; } redist_type[] = { {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, {ZEBRA_ROUTE_CONNECT, 1, "connected"}, {ZEBRA_ROUTE_STATIC, 1, "static"}, {ZEBRA_ROUTE_OSPF, 1, "ospf"}, {ZEBRA_ROUTE_BGP, 2, "bgp"}, {ZEBRA_ROUTE_BABEL, 2, "babel"}, {0, 0, NULL} }; DEFUN (router_zebra, router_zebra_cmd, "router zebra", "Enable a routing process\n" "Make connection to zebra daemon\n") { vty->node = ZEBRA_NODE; zclient->enable = 1; zclient_start (zclient); return CMD_SUCCESS; } DEFUN (no_router_zebra, no_router_zebra_cmd, "no router zebra", NO_STR "Enable a routing process\n" "Make connection to zebra daemon\n") { zclient->enable = 0; zclient_stop (zclient); return CMD_SUCCESS; } #if 0 static int rip_redistribute_set (int type) { if (zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 1; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } #endif static int rip_redistribute_unset (int type) { if (! zclient->redist[type]) return CMD_SUCCESS; zclient->redist[type] = 0; if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); /* Remove the routes from RIP table. */ rip_redistribute_withdraw (type); return CMD_SUCCESS; } int rip_redistribute_check (int type) { return (zclient->redist[type]); } void rip_redistribute_clean (void) { int i; for (i = 0; redist_type[i].str; i++) { if (zclient->redist[redist_type[i].type]) { if (zclient->sock > 0) zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, redist_type[i].type); zclient->redist[redist_type[i].type] = 0; /* Remove the routes from RIP table. */ rip_redistribute_withdraw (redist_type[i].type); } } } DEFUN (rip_redistribute_rip, rip_redistribute_rip_cmd, "redistribute rip", "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { zclient->redist[ZEBRA_ROUTE_RIP] = 1; return CMD_SUCCESS; } DEFUN (no_rip_redistribute_rip, no_rip_redistribute_rip_cmd, "no redistribute rip", NO_STR "Redistribute information from another routing protocol\n" "Routing Information Protocol (RIP)\n") { zclient->redist[ZEBRA_ROUTE_RIP] = 0; return CMD_SUCCESS; } DEFUN (rip_redistribute_type, rip_redistribute_type_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD, REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD) { int i; for(i = 0; redist_type[i].str; i++) { if (strncmp (redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (no_rip_redistribute_type, no_rip_redistribute_type_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPD, NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD) { int i; for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { rip_metric_unset (redist_type[i].type, DONT_CARE_METRIC_RIP); rip_routemap_unset (redist_type[i].type,NULL); rip_redistribute_unset (redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (rip_redistribute_type_routemap, rip_redistribute_type_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD " route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Route map reference\n" "Pointer to route-map entries\n") { int i; for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { rip_routemap_set (redist_type[i].type, argv[1]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (no_rip_redistribute_type_routemap, no_rip_redistribute_type_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPD " route-map WORD", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Route map reference\n" "Pointer to route-map entries\n") { int i; for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { if (rip_routemap_unset (redist_type[i].type,argv[1])) return CMD_WARNING; rip_redistribute_unset (redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (rip_redistribute_type_metric, rip_redistribute_type_metric_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16>", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n") { int i; int metric; metric = atoi (argv[1]); for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { rip_redistribute_metric_set (redist_type[i].type, metric); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (no_rip_redistribute_type_metric, no_rip_redistribute_type_metric_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16>", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n") { int i; for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) return CMD_WARNING; rip_redistribute_unset (redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (rip_redistribute_type_metric_routemap, rip_redistribute_type_metric_routemap_cmd, "redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16> route-map WORD", REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") { int i; int metric; metric = atoi (argv[1]); for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { rip_redistribute_metric_set (redist_type[i].type, metric); rip_routemap_set (redist_type[i].type, argv[2]); zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } DEFUN (no_rip_redistribute_type_metric_routemap, no_rip_redistribute_type_metric_routemap_cmd, "no redistribute " QUAGGA_REDIST_STR_RIPD " metric <0-16> route-map WORD", NO_STR REDIST_STR QUAGGA_REDIST_HELP_STR_RIPD "Metric\n" "Metric value\n" "Route map reference\n" "Pointer to route-map entries\n") { int i; for (i = 0; redist_type[i].str; i++) { if (strncmp(redist_type[i].str, argv[0], redist_type[i].str_min_len) == 0) { if (rip_metric_unset (redist_type[i].type, atoi(argv[1]))) return CMD_WARNING; if (rip_routemap_unset (redist_type[i].type, argv[2])) { rip_redistribute_metric_set(redist_type[i].type, atoi(argv[1])); return CMD_WARNING; } rip_redistribute_unset (redist_type[i].type); return CMD_SUCCESS; } } vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } /* Default information originate. */ DEFUN (rip_default_information_originate, rip_default_information_originate_cmd, "default-information originate", "Control distribution of default route\n" "Distribute a default route\n") { struct prefix_ipv4 p; if (! rip->default_information) { memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; rip->default_information = 1; rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0, NULL, 0, 0); } return CMD_SUCCESS; } DEFUN (no_rip_default_information_originate, no_rip_default_information_originate_cmd, "no default-information originate", NO_STR "Control distribution of default route\n" "Distribute a default route\n") { struct prefix_ipv4 p; if (rip->default_information) { memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; rip->default_information = 0; rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p, 0); } return CMD_SUCCESS; } /* RIP configuration write function. */ static int config_write_zebra (struct vty *vty) { if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); return 1; } else if (! zclient->redist[ZEBRA_ROUTE_RIP]) { vty_out (vty, "router zebra%s", VTY_NEWLINE); vty_out (vty, " no redistribute rip%s", VTY_NEWLINE); return 1; } return 0; } int config_write_rip_redistribute (struct vty *vty, int config_mode) { int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != zclient->redist_default && zclient->redist[i]) { if (config_mode) { if (rip->route_map[i].metric_config) { if (rip->route_map[i].name) vty_out (vty, " redistribute %s metric %d route-map %s%s", zebra_route_string(i), rip->route_map[i].metric, rip->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s metric %d%s", zebra_route_string(i), rip->route_map[i].metric, VTY_NEWLINE); } else { if (rip->route_map[i].name) vty_out (vty, " redistribute %s route-map %s%s", zebra_route_string(i), rip->route_map[i].name, VTY_NEWLINE); else vty_out (vty, " redistribute %s%s", zebra_route_string(i), VTY_NEWLINE); } } else vty_out (vty, " %s", zebra_route_string(i)); } return 0; } /* Zebra node structure. */ static struct cmd_node zebra_node = { ZEBRA_NODE, "%s(config-router)# ", }; void rip_zclient_init () { /* Set default value to the zebra client structure. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_RIP); zclient->interface_add = rip_interface_add; zclient->interface_delete = rip_interface_delete; zclient->interface_address_add = rip_interface_address_add; zclient->interface_address_delete = rip_interface_address_delete; zclient->ipv4_route_add = rip_zebra_read_ipv4; zclient->ipv4_route_delete = rip_zebra_read_ipv4; zclient->interface_up = rip_interface_up; zclient->interface_down = rip_interface_down; /* Install zebra node. */ install_node (&zebra_node, config_write_zebra); /* Install command elements to zebra node. */ install_element (CONFIG_NODE, &router_zebra_cmd); install_element (CONFIG_NODE, &no_router_zebra_cmd); install_default (ZEBRA_NODE); install_element (ZEBRA_NODE, &rip_redistribute_rip_cmd); install_element (ZEBRA_NODE, &no_rip_redistribute_rip_cmd); /* Install command elements to rip node. */ install_element (RIP_NODE, &rip_redistribute_type_cmd); install_element (RIP_NODE, &rip_redistribute_type_routemap_cmd); install_element (RIP_NODE, &rip_redistribute_type_metric_cmd); install_element (RIP_NODE, &rip_redistribute_type_metric_routemap_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_routemap_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_metric_cmd); install_element (RIP_NODE, &no_rip_redistribute_type_metric_routemap_cmd); install_element (RIP_NODE, &rip_default_information_originate_cmd); install_element (RIP_NODE, &no_rip_default_information_originate_cmd); } quagga-0.99.24.1/ripd/ripd.c0000644000175000017500000034127612476520570012311 00000000000000/* RIP version 1 and 2. * Copyright (C) 2005 6WIND * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "command.h" #include "prefix.h" #include "table.h" #include "thread.h" #include "memory.h" #include "log.h" #include "stream.h" #include "filter.h" #include "sockunion.h" #include "sockopt.h" #include "routemap.h" #include "if_rmap.h" #include "plist.h" #include "distribute.h" #include "md5.h" #include "keychain.h" #include "privs.h" #include "ripd/ripd.h" #include "ripd/rip_debug.h" /* UDP receive buffer size */ #define RIP_UDP_RCV_BUF 41600 /* privileges global */ extern struct zebra_privs_t ripd_privs; /* RIP Structure. */ struct rip *rip = NULL; /* RIP neighbor address table. */ struct route_table *rip_neighbor_table; /* RIP route changes. */ long rip_global_route_changes = 0; /* RIP queries. */ long rip_global_queries = 0; /* Prototypes. */ static void rip_event (enum rip_event, int); static void rip_output_process (struct connected *, struct sockaddr_in *, int, u_char); static int rip_triggered_update (struct thread *); static int rip_update_jitter (unsigned long); /* RIP output routes type. */ enum { rip_all_route, rip_changed_route }; /* RIP command strings. */ static const struct message rip_msg[] = { {RIP_REQUEST, "REQUEST"}, {RIP_RESPONSE, "RESPONSE"}, {RIP_TRACEON, "TRACEON"}, {RIP_TRACEOFF, "TRACEOFF"}, {RIP_POLL, "POLL"}, {RIP_POLL_ENTRY, "POLL ENTRY"}, {0, NULL}, }; /* Utility function to set boradcast option to the socket. */ static int sockopt_broadcast (int sock) { int ret; int on = 1; ret = setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof on); if (ret < 0) { zlog_warn ("can't set sockopt SO_BROADCAST to socket %d", sock); return -1; } return 0; } static int rip_route_rte (struct rip_info *rinfo) { return (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE); } static struct rip_info * rip_info_new (void) { return XCALLOC (MTYPE_RIP_INFO, sizeof (struct rip_info)); } void rip_info_free (struct rip_info *rinfo) { XFREE (MTYPE_RIP_INFO, rinfo); } /* RIP route garbage collect timer. */ static int rip_garbage_collect (struct thread *t) { struct rip_info *rinfo; struct route_node *rp; rinfo = THREAD_ARG (t); rinfo->t_garbage_collect = NULL; /* Off timeout timer. */ RIP_TIMER_OFF (rinfo->t_timeout); /* Get route_node pointer. */ rp = rinfo->rp; /* Unlock route_node. */ listnode_delete (rp->info, rinfo); if (list_isempty ((struct list *)rp->info)) { list_free (rp->info); rp->info = NULL; route_unlock_node (rp); } /* Free RIP routing information. */ rip_info_free (rinfo); return 0; } static void rip_timeout_update (struct rip_info *rinfo); /* Add new route to the ECMP list. * RETURN: the new entry added in the list, or NULL if it is not the first * entry and ECMP is not allowed. */ struct rip_info * rip_ecmp_add (struct rip_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct rip_info *rinfo = NULL; struct list *list = NULL; if (rp->info == NULL) rp->info = list_new (); list = (struct list *)rp->info; /* If ECMP is not allowed and some entry already exists in the list, * do nothing. */ if (listcount (list) && !rip->ecmp) return NULL; rinfo = rip_info_new (); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); listnode_add (list, rinfo); if (rip_route_rte (rinfo)) { rip_timeout_update (rinfo); rip_zebra_ipv4_add (rp); } /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ struct rip_info * rip_ecmp_replace (struct rip_info *rinfo_new) { struct route_node *rp = rinfo_new->rp; struct list *list = (struct list *)rp->info; struct rip_info *rinfo = NULL, *tmp_rinfo = NULL; struct listnode *node = NULL, *nextnode = NULL; if (list == NULL || listcount (list) == 0) return rip_ecmp_add (rinfo_new); /* Get the first entry */ rinfo = listgetdata (listhead (list)); /* Learnt route replaced by a local one. Delete it from zebra. */ if (rip_route_rte (rinfo) && !rip_route_rte (rinfo_new)) if (CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) rip_zebra_ipv4_delete (rp); /* Re-use the first entry, and delete the others. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIP_TIMER_OFF (tmp_rinfo->t_timeout); RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); rip_info_free (tmp_rinfo); } RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); memcpy (rinfo, rinfo_new, sizeof (struct rip_info)); if (rip_route_rte (rinfo)) { rip_timeout_update (rinfo); /* The ADD message implies an update. */ rip_zebra_ipv4_add (rp); } /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Delete one route from the ECMP list. * RETURN: * null - the entry is freed, and other entries exist in the list * the entry - the entry is the last one in the list; its metric is set * to INFINITY, and the garbage collector is started for it */ struct rip_info * rip_ecmp_delete (struct rip_info *rinfo) { struct route_node *rp = rinfo->rp; struct list *list = (struct list *)rp->info; RIP_TIMER_OFF (rinfo->t_timeout); if (listcount (list) > 1) { /* Some other ECMP entries still exist. Just delete this entry. */ RIP_TIMER_OFF (rinfo->t_garbage_collect); listnode_delete (list, rinfo); if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) /* The ADD message implies the update. */ rip_zebra_ipv4_add (rp); rip_info_free (rinfo); rinfo = NULL; } else { assert (rinfo == listgetdata (listhead (list))); /* This is the only entry left in the list. We must keep it in * the list for garbage collection time, with INFINITY metric. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); if (rip_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIP_RTF_FIB)) rip_zebra_ipv4_delete (rp); } /* Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update (see section 2.5). */ rip_event (RIP_TRIGGERED_UPDATE, 0); return rinfo; } /* Timeout RIP routes. */ static int rip_timeout (struct thread *t) { rip_ecmp_delete ((struct rip_info *)THREAD_ARG (t)); return 0; } static void rip_timeout_update (struct rip_info *rinfo) { if (rinfo->metric != RIP_METRIC_INFINITY) { RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_ON (rinfo->t_timeout, rip_timeout, rip->timeout_time); } } static int rip_incoming_filter (struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; /* Input distribute-list filtering. */ if (ri->list[RIP_FILTER_IN]) { if (access_list_apply (ri->list[RIP_FILTER_IN], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIP_FILTER_IN]) { if (prefix_list_apply (ri->prefix[RIP_FILTER_IN], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list in", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } static int rip_outgoing_filter (struct prefix_ipv4 *p, struct rip_interface *ri) { struct distribute *dist; struct access_list *alist; struct prefix_list *plist; if (ri->list[RIP_FILTER_OUT]) { if (access_list_apply (ri->list[RIP_FILTER_OUT], (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by distribute out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } if (ri->prefix[RIP_FILTER_OUT]) { if (prefix_list_apply (ri->prefix[RIP_FILTER_OUT], (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by prefix-list out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); if (alist) { if (access_list_apply (alist, (struct prefix *) p) == FILTER_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by distribute out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); if (plist) { if (prefix_list_apply (plist, (struct prefix *) p) == PREFIX_DENY) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d filtered by prefix-list out", inet_ntoa (p->prefix), p->prefixlen); return -1; } } } } return 0; } /* Check nexthop address validity. */ static int rip_nexthop_check (struct in_addr *addr) { struct listnode *node; struct listnode *cnode; struct interface *ifp; struct connected *ifc; struct prefix *p; /* If nexthop address matches local configured address then it is invalid nexthop. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, ifc)) { p = ifc->address; if (p->family == AF_INET && IPV4_ADDR_SAME (&p->u.prefix4, addr)) return -1; } } return 0; } /* RIP add route to routing table. */ static void rip_rte_process (struct rte *rte, struct sockaddr_in *from, struct interface *ifp) { int ret; struct prefix_ipv4 p; struct route_node *rp; struct rip_info *rinfo = NULL, newinfo; struct rip_interface *ri; struct in_addr *nexthop; int same = 0; unsigned char old_dist, new_dist; struct list *list = NULL; struct listnode *node = NULL; /* Make prefix structure. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefix = rte->prefix; p.prefixlen = ip_masklen (rte->mask); /* Make sure mask is applied. */ apply_mask_ipv4 (&p); /* Apply input filters. */ ri = ifp->info; ret = rip_incoming_filter (&p, ri); if (ret < 0) return; memset (&newinfo, 0, sizeof (newinfo)); newinfo.type = ZEBRA_ROUTE_RIP; newinfo.sub_type = RIP_ROUTE_RTE; newinfo.nexthop = rte->nexthop; newinfo.from = from->sin_addr; newinfo.ifindex = ifp->ifindex; newinfo.metric = rte->metric; newinfo.metric_out = rte->metric; /* XXX */ newinfo.tag = ntohs (rte->tag); /* XXX */ /* Modify entry according to the interface routemap. */ if (ri->routemap[RIP_FILTER_IN]) { int ret; /* The object should be of the type of rip_info */ ret = route_map_apply (ri->routemap[RIP_FILTER_IN], (struct prefix *) &p, RMAP_RIP, &newinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIP %s/%d is filtered by route-map in", inet_ntoa (p.prefix), p.prefixlen); return; } /* Get back the object */ rte->nexthop = newinfo.nexthop_out; rte->tag = htons (newinfo.tag_out); /* XXX */ rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */ } /* Once the entry has been validated, update the metric by adding the cost of the network on wich the message arrived. If the result is greater than infinity, use infinity (RFC2453 Sec. 3.9.2) */ /* Zebra ripd can handle offset-list in. */ ret = rip_offset_list_apply_in (&p, ifp, &rte->metric); /* If offset-list does not modify the metric use interface's metric. */ if (!ret) rte->metric += ifp->metric ? ifp->metric : 1; if (rte->metric > RIP_METRIC_INFINITY) rte->metric = RIP_METRIC_INFINITY; /* Set nexthop pointer. */ if (rte->nexthop.s_addr == 0) nexthop = &from->sin_addr; else nexthop = &rte->nexthop; /* Check if nexthop address is myself, then do nothing. */ if (rip_nexthop_check (nexthop) < 0) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("Nexthop address %s is myself", inet_ntoa (*nexthop)); return; } /* Get index for the prefix. */ rp = route_node_get (rip->table, (struct prefix *) &p); newinfo.rp = rp; newinfo.nexthop = *nexthop; newinfo.metric = rte->metric; newinfo.tag = ntohs (rte->tag); newinfo.distance = rip_distance_apply (&newinfo); new_dist = newinfo.distance ? newinfo.distance : ZEBRA_RIP_DISTANCE_DEFAULT; /* Check to see whether there is already RIP route on the table. */ if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, node, rinfo)) { /* Need to compare with redistributed entry or local entry */ if (!rip_route_rte (rinfo)) break; if (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && IPV4_ADDR_SAME (&rinfo->nexthop, nexthop)) break; if (!listnextnode (node)) { /* Not found in the list */ if (rte->metric > rinfo->metric) { /* New route has a greater metric. Discard it. */ route_unlock_node (rp); return; } if (rte->metric < rinfo->metric) /* New route has a smaller metric. Replace the ECMP list * with the new one in below. */ break; /* Metrics are same. We compare the distances. */ old_dist = rinfo->distance ? \ rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; if (new_dist > old_dist) { /* New route has a greater distance. Discard it. */ route_unlock_node (rp); return; } if (new_dist < old_dist) /* New route has a smaller distance. Replace the ECMP list * with the new one in below. */ break; /* Metrics and distances are both same. Keep "rinfo" null and * the new route is added in the ECMP list in below. */ } } if (rinfo) { /* Local static route. */ if (rinfo->type == ZEBRA_ROUTE_RIP && ((rinfo->sub_type == RIP_ROUTE_STATIC) || (rinfo->sub_type == RIP_ROUTE_DEFAULT)) && rinfo->metric != RIP_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Redistributed route check. */ if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->metric != RIP_METRIC_INFINITY) { old_dist = rinfo->distance; /* Only routes directly connected to an interface (nexthop == 0) * may have a valid NULL distance */ if (rinfo->nexthop.s_addr != 0) old_dist = old_dist ? old_dist : ZEBRA_RIP_DISTANCE_DEFAULT; /* If imported route does not have STRICT precedence, mark it as a ghost */ if (new_dist <= old_dist && rte->metric != RIP_METRIC_INFINITY) rip_ecmp_replace (&newinfo); route_unlock_node (rp); return; } } if (!rinfo) { if (rp->info) route_unlock_node (rp); /* Now, check to see whether there is already an explicit route for the destination prefix. If there is no such route, add this route to the routing table, unless the metric is infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIP_METRIC_INFINITY) rip_ecmp_add (&newinfo); } else { /* Route is there but we are not sure the route is RIP or not. */ /* If there is an existing route, compare the next hop address to the address of the router from which the datagram came. If this datagram is from the same router as the existing route, reinitialize the timeout. */ same = (IPV4_ADDR_SAME (&rinfo->from, &from->sin_addr) && (rinfo->ifindex == ifp->ifindex)); old_dist = rinfo->distance ? \ rinfo->distance : ZEBRA_RIP_DISTANCE_DEFAULT; /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different than the old one; or, if the new metric is lower than the old one, or if the tag has been changed; or if there is a route with a lower administrave distance; or an update of the distance on the actual route; do the following actions: */ if ((same && rinfo->metric != rte->metric) || (rte->metric < rinfo->metric) || ((same) && (rinfo->metric == rte->metric) && (newinfo.tag != rinfo->tag)) || (old_dist > new_dist) || ((old_dist != new_dist) && same)) { if (listcount (list) == 1) { if (newinfo.metric != RIP_METRIC_INFINITY) rip_ecmp_replace (&newinfo); else rip_ecmp_delete (rinfo); } else { if (newinfo.metric < rinfo->metric) rip_ecmp_replace (&newinfo); else if (newinfo.metric > rinfo->metric) rip_ecmp_delete (rinfo); else if (new_dist < old_dist) rip_ecmp_replace (&newinfo); else if (new_dist > old_dist) rip_ecmp_delete (rinfo); else { int update = CHECK_FLAG (rinfo->flags, RIP_RTF_FIB) ? 1 : 0; assert (newinfo.metric != RIP_METRIC_INFINITY); RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); memcpy (rinfo, &newinfo, sizeof (struct rip_info)); rip_timeout_update (rinfo); if (update) rip_zebra_ipv4_add (rp); /* - Set the route change flag on the first entry. */ rinfo = listgetdata (listhead (list)); SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); rip_event (RIP_TRIGGERED_UPDATE, 0); } } } else /* same & no change */ rip_timeout_update (rinfo); /* Unlock tempolary lock of the route. */ route_unlock_node (rp); } } /* Dump RIP packet */ static void rip_packet_dump (struct rip_packet *packet, int size, const char *sndrcv) { caddr_t lim; struct rte *rte; const char *command_str; char pbuf[BUFSIZ], nbuf[BUFSIZ]; u_char netmask = 0; u_char *p; /* Set command string. */ if (packet->command > 0 && packet->command < RIP_COMMAND_MAX) command_str = lookup (rip_msg, packet->command); else command_str = "unknown"; /* Dump packet header. */ zlog_debug ("%s %s version %d packet size %d", sndrcv, command_str, packet->version, size); /* Dump each routing table entry. */ rte = packet->rte; for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) { if (packet->version == RIPv2) { netmask = ip_masklen (rte->mask); if (rte->family == htons (RIP_FAMILY_AUTH)) { if (rte->tag == htons (RIP_AUTH_SIMPLE_PASSWORD)) { p = (u_char *)&rte->prefix; zlog_debug (" family 0x%X type %d auth string: %s", ntohs (rte->family), ntohs (rte->tag), p); } else if (rte->tag == htons (RIP_AUTH_MD5)) { struct rip_md5_info *md5; md5 = (struct rip_md5_info *) &packet->rte; zlog_debug (" family 0x%X type %d (MD5 authentication)", ntohs (md5->family), ntohs (md5->type)); zlog_debug (" RIP-2 packet len %d Key ID %d" " Auth Data len %d", ntohs (md5->packet_len), md5->keyid, md5->auth_len); zlog_debug (" Sequence Number %ld", (u_long) ntohl (md5->sequence)); } else if (rte->tag == htons (RIP_AUTH_DATA)) { p = (u_char *)&rte->prefix; zlog_debug (" family 0x%X type %d (MD5 data)", ntohs (rte->family), ntohs (rte->tag)); zlog_debug (" MD5: %02X%02X%02X%02X%02X%02X%02X%02X" "%02X%02X%02X%02X%02X%02X%02X", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); } else { zlog_debug (" family 0x%X type %d (Unknown auth type)", ntohs (rte->family), ntohs (rte->tag)); } } else zlog_debug (" %s/%d -> %s family %d tag %d metric %ld", inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), netmask, inet_ntop (AF_INET, &rte->nexthop, nbuf, BUFSIZ), ntohs (rte->family), ntohs (rte->tag), (u_long) ntohl (rte->metric)); } else { zlog_debug (" %s family %d tag %d metric %ld", inet_ntop (AF_INET, &rte->prefix, pbuf, BUFSIZ), ntohs (rte->family), ntohs (rte->tag), (u_long)ntohl (rte->metric)); } } } /* Check if the destination address is valid (unicast; not net 0 or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't check net 0 because we accept default route. */ static int rip_destination_check (struct in_addr addr) { u_int32_t destination; /* Convert to host byte order. */ destination = ntohl (addr.s_addr); if (IPV4_NET127 (destination)) return 0; /* Net 0 may match to the default route. */ if (IPV4_NET0 (destination) && destination != 0) return 0; /* Unicast address must belong to class A, B, C. */ if (IN_CLASSA (destination)) return 1; if (IN_CLASSB (destination)) return 1; if (IN_CLASSC (destination)) return 1; return 0; } /* RIP version 2 authentication. */ static int rip_auth_simple_password (struct rte *rte, struct sockaddr_in *from, struct interface *ifp) { struct rip_interface *ri; char *auth_str; if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 simple password authentication from %s", inet_ntoa (from->sin_addr)); ri = ifp->info; if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD || rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD)) return 0; /* Simple password authentication. */ if (ri->auth_str) { auth_str = (char *) &rte->prefix; if (strncmp (auth_str, ri->auth_str, 16) == 0) return 1; } if (ri->key_chain) { struct keychain *keychain; struct key *key; keychain = keychain_lookup (ri->key_chain); if (keychain == NULL) return 0; key = key_match_for_accept (keychain, (char *) &rte->prefix); if (key) return 1; } return 0; } /* RIP version 2 authentication with MD5. */ static int rip_auth_md5 (struct rip_packet *packet, struct sockaddr_in *from, int length, struct interface *ifp) { struct rip_interface *ri; struct rip_md5_info *md5; struct rip_md5_data *md5data; struct keychain *keychain; struct key *key; MD5_CTX ctx; u_char digest[RIP_AUTH_MD5_SIZE]; u_int16_t packet_len; char auth_str[RIP_AUTH_MD5_SIZE]; if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 MD5 authentication from %s", inet_ntoa (from->sin_addr)); ri = ifp->info; md5 = (struct rip_md5_info *) &packet->rte; /* Check auth type. */ if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5)) return 0; /* If the authentication length is less than 16, then it must be wrong for * any interpretation of rfc2082. Some implementations also interpret * this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka RIP_AUTH_MD5_COMPAT_SIZE. */ if ( !((md5->auth_len == RIP_AUTH_MD5_SIZE) || (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE))) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 MD5 authentication, strange authentication " "length field %d", md5->auth_len); return 0; } /* grab and verify check packet length */ packet_len = ntohs (md5->packet_len); if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIPv2 MD5 authentication, packet length field %d " "greater than received length %d!", md5->packet_len, length); return 0; } /* retrieve authentication data */ md5data = (struct rip_md5_data *) (((u_char *) packet) + packet_len); memset (auth_str, 0, RIP_AUTH_MD5_SIZE); if (ri->key_chain) { keychain = keychain_lookup (ri->key_chain); if (keychain == NULL) return 0; key = key_lookup_for_accept (keychain, md5->keyid); if (key == NULL) return 0; strncpy (auth_str, key->string, RIP_AUTH_MD5_SIZE); } else if (ri->auth_str) strncpy (auth_str, ri->auth_str, RIP_AUTH_MD5_SIZE); if (auth_str[0] == 0) return 0; /* MD5 digest authentication. */ memset (&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); if (memcmp (md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0) return packet_len; else return 0; } /* Pick correct auth string for sends, prepare auth_str buffer for use. * (left justified and padded). * * presumes one of ri or key is valid, and that the auth strings they point * to are nul terminated. If neither are present, auth_str will be fully * zero padded. * */ static void rip_auth_prepare_str_send (struct rip_interface *ri, struct key *key, char *auth_str, int len) { assert (ri || key); memset (auth_str, 0, len); if (key && key->string) strncpy (auth_str, key->string, len); else if (ri->auth_str) strncpy (auth_str, ri->auth_str, len); return; } /* Write RIPv2 simple password authentication information * * auth_str is presumed to be 2 bytes and correctly prepared * (left justified and zero padded). */ static void rip_auth_simple_write (struct stream *s, char *auth_str, int len) { assert (s && len == RIP_AUTH_SIMPLE_SIZE); stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_SIMPLE_PASSWORD); stream_put (s, auth_str, RIP_AUTH_SIMPLE_SIZE); return; } /* write RIPv2 MD5 "authentication header" * (uses the auth key data field) * * Digest offset field is set to 0. * * returns: offset of the digest offset field, which must be set when * length to the auth-data MD5 digest is known. */ static size_t rip_auth_md5_ah_write (struct stream *s, struct rip_interface *ri, struct key *key) { size_t doff = 0; assert (s && ri && ri->auth_type == RIP_AUTH_MD5); /* MD5 authentication. */ stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_MD5); /* MD5 AH digest offset field. * * Set to placeholder value here, to true value when RIP-2 Packet length * is known. Actual value is set in .....(). */ doff = stream_get_endp(s); stream_putw (s, 0); /* Key ID. */ if (key) stream_putc (s, key->index % 256); else stream_putc (s, 1); /* Auth Data Len. Set 16 for MD5 authentication data. Older ripds * however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for this * to be configurable. */ stream_putc (s, ri->md5_auth_len); /* Sequence Number (non-decreasing). */ /* RFC2080: The value used in the sequence number is arbitrary, but two suggestions are the time of the message's creation or a simple message counter. */ stream_putl (s, time (NULL)); /* Reserved field must be zero. */ stream_putl (s, 0); stream_putl (s, 0); return doff; } /* If authentication is in used, write the appropriate header * returns stream offset to which length must later be written * or 0 if this is not required */ static size_t rip_auth_header_write (struct stream *s, struct rip_interface *ri, struct key *key, char *auth_str, int len) { assert (ri->auth_type != RIP_NO_AUTH); switch (ri->auth_type) { case RIP_AUTH_SIMPLE_PASSWORD: rip_auth_prepare_str_send (ri, key, auth_str, len); rip_auth_simple_write (s, auth_str, len); return 0; case RIP_AUTH_MD5: return rip_auth_md5_ah_write (s, ri, key); } assert (1); return 0; } /* Write RIPv2 MD5 authentication data trailer */ static void rip_auth_md5_set (struct stream *s, struct rip_interface *ri, size_t doff, char *auth_str, int authlen) { unsigned long len; MD5_CTX ctx; unsigned char digest[RIP_AUTH_MD5_SIZE]; /* Make it sure this interface is configured as MD5 authentication. */ assert ((ri->auth_type == RIP_AUTH_MD5) && (authlen == RIP_AUTH_MD5_SIZE)); assert (doff > 0); /* Get packet length. */ len = stream_get_endp(s); /* Check packet length. */ if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) { zlog_err ("rip_auth_md5_set(): packet length %ld is less than minimum length.", len); return; } /* Set the digest offset length in the header */ stream_putw_at (s, doff, len); /* Set authentication data. */ stream_putw (s, RIP_FAMILY_AUTH); stream_putw (s, RIP_AUTH_DATA); /* Generate a digest for the RIP packet. */ memset(&ctx, 0, sizeof(ctx)); MD5Init(&ctx); MD5Update(&ctx, STREAM_DATA (s), stream_get_endp (s)); MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE); MD5Final(digest, &ctx); /* Copy the digest to the packet. */ stream_write (s, digest, RIP_AUTH_MD5_SIZE); } /* RIP routing information. */ static void rip_response_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct connected *ifc) { caddr_t lim; struct rte *rte; struct prefix_ipv4 ifaddr; struct prefix_ipv4 ifaddrclass; int subnetted; /* We don't know yet. */ subnetted = -1; /* The Response must be ignored if it is not from the RIP port. (RFC2453 - Sec. 3.9.2)*/ if (from->sin_port != htons(RIP_PORT_DEFAULT)) { zlog_info ("response doesn't come from RIP port: %d", from->sin_port); rip_peer_bad_packet (from); return; } /* The datagram's IPv4 source address should be checked to see whether the datagram is from a valid neighbor; the source of the datagram must be on a directly connected network (RFC2453 - Sec. 3.9.2) */ if (if_lookup_address(from->sin_addr) == NULL) { zlog_info ("This datagram doesn't came from a valid neighbor: %s", inet_ntoa (from->sin_addr)); rip_peer_bad_packet (from); return; } /* It is also worth checking to see whether the response is from one of the router's own addresses. */ ; /* Alredy done in rip_read () */ /* Update RIP peer. */ rip_peer_update (from, packet->version); /* Set RTE pointer. */ rte = packet->rte; for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++) { /* RIPv2 authentication check. */ /* If the Address Family Identifier of the first (and only the first) entry in the message is 0xFFFF, then the remainder of the entry contains the authentication. */ /* If the packet gets here it means authentication enabled */ /* Check is done in rip_read(). So, just skipping it */ if (packet->version == RIPv2 && rte == packet->rte && rte->family == htons(RIP_FAMILY_AUTH)) continue; if (rte->family != htons(AF_INET)) { /* Address family check. RIP only supports AF_INET. */ zlog_info ("Unsupported family %d from %s.", ntohs (rte->family), inet_ntoa (from->sin_addr)); continue; } /* - is the destination address valid (e.g., unicast; not net 0 or 127) */ if (! rip_destination_check (rte->prefix)) { zlog_info ("Network is net 0 or net 127 or it is not unicast network"); rip_peer_bad_route (from); continue; } /* Convert metric value to host byte order. */ rte->metric = ntohl (rte->metric); /* - is the metric valid (i.e., between 1 and 16, inclusive) */ if (! (rte->metric >= 1 && rte->metric <= 16)) { zlog_info ("Route's metric is not in the 1-16 range."); rip_peer_bad_route (from); continue; } /* RIPv1 does not have nexthop value. */ if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) { zlog_info ("RIPv1 packet with nexthop value %s", inet_ntoa (rte->nexthop)); rip_peer_bad_route (from); continue; } /* That is, if the provided information is ignored, a possibly sub-optimal, but absolutely valid, route may be taken. If the received Next Hop is not directly reachable, it should be treated as 0.0.0.0. */ if (packet->version == RIPv2 && rte->nexthop.s_addr != 0) { u_int32_t addrval; /* Multicast address check. */ addrval = ntohl (rte->nexthop.s_addr); if (IN_CLASSD (addrval)) { zlog_info ("Nexthop %s is multicast address, skip this rte", inet_ntoa (rte->nexthop)); continue; } if (! if_lookup_address (rte->nexthop)) { struct route_node *rn; struct rip_info *rinfo; rn = route_node_match_ipv4 (rip->table, &rte->nexthop); if (rn) { rinfo = rn->info; if (rinfo->type == ZEBRA_ROUTE_RIP && rinfo->sub_type == RIP_ROUTE_RTE) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("Next hop %s is on RIP network. Set nexthop to the packet's originator", inet_ntoa (rte->nexthop)); rte->nexthop = rinfo->from; } else { if (IS_RIP_DEBUG_EVENT) zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); rte->nexthop.s_addr = 0; } route_unlock_node (rn); } else { if (IS_RIP_DEBUG_EVENT) zlog_debug ("Next hop %s is not directly reachable. Treat it as 0.0.0.0", inet_ntoa (rte->nexthop)); rte->nexthop.s_addr = 0; } } } /* For RIPv1, there won't be a valid netmask. This is a best guess at the masks. If everyone was using old Ciscos before the 'ip subnet zero' option, it would be almost right too :-) Cisco summarize ripv1 advertisments to the classful boundary (/16 for class B's) except when the RIP packet does to inside the classful network in question. */ if ((packet->version == RIPv1 && rte->prefix.s_addr != 0) || (packet->version == RIPv2 && (rte->prefix.s_addr != 0 && rte->mask.s_addr == 0))) { u_int32_t destination; if (subnetted == -1) { memcpy (&ifaddr, ifc->address, sizeof (struct prefix_ipv4)); memcpy (&ifaddrclass, &ifaddr, sizeof (struct prefix_ipv4)); apply_classful_mask_ipv4 (&ifaddrclass); subnetted = 0; if (ifaddr.prefixlen > ifaddrclass.prefixlen) subnetted = 1; } destination = ntohl (rte->prefix.s_addr); if (IN_CLASSA (destination)) masklen2ip (8, &rte->mask); else if (IN_CLASSB (destination)) masklen2ip (16, &rte->mask); else if (IN_CLASSC (destination)) masklen2ip (24, &rte->mask); if (subnetted == 1) masklen2ip (ifaddrclass.prefixlen, (struct in_addr *) &destination); if ((subnetted == 1) && ((rte->prefix.s_addr & destination) == ifaddrclass.prefix.s_addr)) { masklen2ip (ifaddr.prefixlen, &rte->mask); if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) masklen2ip (32, &rte->mask); if (IS_RIP_DEBUG_EVENT) zlog_debug ("Subnetted route %s", inet_ntoa (rte->prefix)); } else { if ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr) continue; } if (IS_RIP_DEBUG_EVENT) { zlog_debug ("Resultant route %s", inet_ntoa (rte->prefix)); zlog_debug ("Resultant mask %s", inet_ntoa (rte->mask)); } } /* In case of RIPv2, if prefix in RTE is not netmask applied one ignore the entry. */ if ((packet->version == RIPv2) && (rte->mask.s_addr != 0) && ((rte->prefix.s_addr & rte->mask.s_addr) != rte->prefix.s_addr)) { zlog_warn ("RIPv2 address %s is not mask /%d applied one", inet_ntoa (rte->prefix), ip_masklen (rte->mask)); rip_peer_bad_route (from); continue; } /* Default route's netmask is ignored. */ if (packet->version == RIPv2 && (rte->prefix.s_addr == 0) && (rte->mask.s_addr != 0)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("Default route with non-zero netmask. Set zero to netmask"); rte->mask.s_addr = 0; } /* Routing table updates. */ rip_rte_process (rte, from, ifc->ifp); } } /* Make socket for RIP protocol. */ static int rip_create_socket (struct sockaddr_in *from) { int ret; int sock; struct sockaddr_in addr; memset (&addr, 0, sizeof (struct sockaddr_in)); if (!from) { addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ } else { memcpy(&addr, from, sizeof(addr)); } /* sending port must always be the RIP port */ addr.sin_port = htons (RIP_PORT_DEFAULT); /* Make datagram socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_err("Cannot create UDP socket: %s", safe_strerror(errno)); exit (1); } sockopt_broadcast (sock); sockopt_reuseaddr (sock); sockopt_reuseport (sock); #ifdef RIP_RECVMSG setsockopt_pktinfo (sock); #endif /* RIP_RECVMSG */ #ifdef IPTOS_PREC_INTERNETCONTROL setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); #endif if (ripd_privs.change (ZPRIVS_RAISE)) zlog_err ("rip_create_socket: could not raise privs"); setsockopt_so_recvbuf (sock, RIP_UDP_RCV_BUF); if ( (ret = bind (sock, (struct sockaddr *) & addr, sizeof (addr))) < 0) { int save_errno = errno; if (ripd_privs.change (ZPRIVS_LOWER)) zlog_err ("rip_create_socket: could not lower privs"); zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__, sock, inet_ntoa(addr.sin_addr), (int) ntohs(addr.sin_port), safe_strerror(save_errno)); close (sock); return ret; } if (ripd_privs.change (ZPRIVS_LOWER)) zlog_err ("rip_create_socket: could not lower privs"); return sock; } /* RIP packet send to destination address, on interface denoted by * by connected argument. NULL to argument denotes destination should be * should be RIP multicast group */ static int rip_send_packet (u_char * buf, int size, struct sockaddr_in *to, struct connected *ifc) { int ret, send_sock; struct sockaddr_in sin; assert (ifc != NULL); if (IS_RIP_DEBUG_PACKET) { #define ADDRESS_SIZE 20 char dst[ADDRESS_SIZE]; dst[ADDRESS_SIZE - 1] = '\0'; if (to) { strncpy (dst, inet_ntoa(to->sin_addr), ADDRESS_SIZE - 1); } else { sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); strncpy (dst, inet_ntoa(sin.sin_addr), ADDRESS_SIZE - 1); } #undef ADDRESS_SIZE zlog_debug("rip_send_packet %s > %s (%s)", inet_ntoa(ifc->address->u.prefix4), dst, ifc->ifp->name); } if ( CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY) ) { /* * ZEBRA_IFA_SECONDARY is set on linux when an interface is configured * with multiple addresses on the same subnet: the first address * on the subnet is configured "primary", and all subsequent addresses * on that subnet are treated as "secondary" addresses. * In order to avoid routing-table bloat on other rip listeners, * we do not send out RIP packets with ZEBRA_IFA_SECONDARY source addrs. * XXX Since Linux is the only system for which the ZEBRA_IFA_SECONDARY * flag is set, we would end up sending a packet for a "secondary" * source address on non-linux systems. */ if (IS_RIP_DEBUG_PACKET) zlog_debug("duplicate dropped"); return 0; } /* Make destination address. */ memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* When destination is specified, use it's port and address. */ if (to) { sin.sin_port = to->sin_port; sin.sin_addr = to->sin_addr; send_sock = rip->sock; } else { struct sockaddr_in from; sin.sin_port = htons (RIP_PORT_DEFAULT); sin.sin_addr.s_addr = htonl (INADDR_RIP_GROUP); /* multicast send should bind to local interface address */ memset (&from, 0, sizeof (from)); from.sin_family = AF_INET; from.sin_port = htons (RIP_PORT_DEFAULT); from.sin_addr = ifc->address->u.prefix4; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN from.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* * we have to open a new socket for each packet because this * is the most portable way to bind to a different source * ipv4 address for each packet. */ if ( (send_sock = rip_create_socket (&from)) < 0) { zlog_warn("rip_send_packet could not create socket."); return -1; } rip_interface_multicast_set (send_sock, ifc); } ret = sendto (send_sock, buf, size, 0, (struct sockaddr *)&sin, sizeof (struct sockaddr_in)); if (IS_RIP_DEBUG_EVENT) zlog_debug ("SEND to %s.%d", inet_ntoa(sin.sin_addr), ntohs (sin.sin_port)); if (ret < 0) zlog_warn ("can't send packet : %s", safe_strerror (errno)); if (!to) close(send_sock); return ret; } /* Add redistributed route to RIP table. */ void rip_redistribute_add (int type, int sub_type, struct prefix_ipv4 *p, unsigned int ifindex, struct in_addr *nexthop, unsigned int metric, unsigned char distance) { int ret; struct route_node *rp = NULL; struct rip_info *rinfo = NULL, newinfo; struct list *list = NULL; /* Redistribute route */ ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_get (rip->table, (struct prefix *) p); memset (&newinfo, 0, sizeof (struct rip_info)); newinfo.type = type; newinfo.sub_type = sub_type; newinfo.ifindex = ifindex; newinfo.metric = 1; newinfo.external_metric = metric; newinfo.distance = distance; newinfo.rp = rp; if (nexthop) newinfo.nexthop = *nexthop; if ((list = rp->info) != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); if (rinfo->type == ZEBRA_ROUTE_CONNECT && rinfo->sub_type == RIP_ROUTE_INTERFACE && rinfo->metric != RIP_METRIC_INFINITY) { route_unlock_node (rp); return; } /* Manually configured RIP route check. */ if (rinfo->type == ZEBRA_ROUTE_RIP && ((rinfo->sub_type == RIP_ROUTE_STATIC) || (rinfo->sub_type == RIP_ROUTE_DEFAULT)) ) { if (type != ZEBRA_ROUTE_RIP || ((sub_type != RIP_ROUTE_STATIC) && (sub_type != RIP_ROUTE_DEFAULT))) { route_unlock_node (rp); return; } } rinfo = rip_ecmp_replace (&newinfo); route_unlock_node (rp); } else rinfo = rip_ecmp_add (&newinfo); if (IS_RIP_DEBUG_EVENT) { if (!nexthop) zlog_debug ("Redistribute new prefix %s/%d on the interface %s", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); else zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s", inet_ntoa(p->prefix), p->prefixlen, inet_ntoa(rinfo->nexthop), ifindex2ifname(ifindex)); } rip_event (RIP_TRIGGERED_UPDATE, 0); } /* Delete redistributed route from RIP table. */ void rip_redistribute_delete (int type, int sub_type, struct prefix_ipv4 *p, unsigned int ifindex) { int ret; struct route_node *rp; struct rip_info *rinfo; ret = rip_destination_check (p->prefix); if (! ret) return; rp = route_node_lookup (rip->table, (struct prefix *) p); if (rp) { struct list *list = rp->info; if (list != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); if (rinfo != NULL && rinfo->type == type && rinfo->sub_type == sub_type && rinfo->ifindex == ifindex) { /* Perform poisoned reverse. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; if (IS_RIP_DEBUG_EVENT) zlog_debug ("Poisone %s/%d on the interface %s with an " "infinity metric [delete]", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(ifindex)); rip_event (RIP_TRIGGERED_UPDATE, 0); } } route_unlock_node (rp); } } /* Response to request called from rip_read ().*/ static void rip_request_process (struct rip_packet *packet, int size, struct sockaddr_in *from, struct connected *ifc) { caddr_t lim; struct rte *rte; struct prefix_ipv4 p; struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri; /* Does not reponse to the requests on the loopback interfaces */ if (if_is_loopback (ifc->ifp)) return; /* Check RIP process is enabled on this interface. */ ri = ifc->ifp->info; if (! ri->running) return; /* When passive interface is specified, suppress responses */ if (ri->passive) return; /* RIP peer update. */ rip_peer_update (from, packet->version); lim = ((caddr_t) packet) + size; rte = packet->rte; /* The Request is processed entry by entry. If there are no entries, no response is given. */ if (lim == (caddr_t) rte) return; /* There is one special case. If there is exactly one entry in the request, and it has an address family identifier of zero and a metric of infinity (i.e., 16), then this is a request to send the entire routing table. */ if (lim == ((caddr_t) (rte + 1)) && ntohs (rte->family) == 0 && ntohl (rte->metric) == RIP_METRIC_INFINITY) { /* All route with split horizon */ rip_output_process (ifc, from, rip_all_route, packet->version); } else { /* Examine the list of RTEs in the Request one by one. For each entry, look up the destination in the router's routing database and, if there is a route, put that route's metric in the metric field of the RTE. If there is no explicit route to the specified destination, put infinity in the metric field. Once all the entries have been filled in, change the command from Request to Response and send the datagram back to the requestor. */ p.family = AF_INET; for (; ((caddr_t) rte) < lim; rte++) { p.prefix = rte->prefix; p.prefixlen = ip_masklen (rte->mask); apply_mask_ipv4 (&p); rp = route_node_lookup (rip->table, (struct prefix *) &p); if (rp) { rinfo = listgetdata (listhead ((struct list *)rp->info)); rte->metric = htonl (rinfo->metric); route_unlock_node (rp); } else rte->metric = htonl (RIP_METRIC_INFINITY); } packet->command = RIP_RESPONSE; rip_send_packet ((u_char *)packet, size, from, ifc); } rip_global_queries++; } #if RIP_RECVMSG /* Set IPv6 packet info to the socket. */ static int setsockopt_pktinfo (int sock) { int ret; int val = 1; ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); if (ret < 0) zlog_warn ("Can't setsockopt IP_PKTINFO : %s", safe_strerror (errno)); return ret; } /* Read RIP packet by recvmsg function. */ int rip_recvmsg (int sock, u_char *buf, int size, struct sockaddr_in *from, int *ifindex) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *ptr; char adata[1024]; msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = size; ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL; ptr = CMSG_NXTHDR(&msg, ptr)) if (ptr->cmsg_level == IPPROTO_IP && ptr->cmsg_type == IP_PKTINFO) { struct in_pktinfo *pktinfo; int i; pktinfo = (struct in_pktinfo *) CMSG_DATA (ptr); i = pktinfo->ipi_ifindex; } return ret; } /* RIP packet read function. */ int rip_read_new (struct thread *t) { int ret; int sock; char buf[RIP_PACKET_MAXSIZ]; struct sockaddr_in from; unsigned int ifindex; /* Fetch socket then register myself. */ sock = THREAD_FD (t); rip_event (RIP_READ, sock); /* Read RIP packet. */ ret = rip_recvmsg (sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex); if (ret < 0) { zlog_warn ("Can't read RIP packet: %s", safe_strerror (errno)); return ret; } return ret; } #endif /* RIP_RECVMSG */ /* First entry point of RIP packet. */ static int rip_read (struct thread *t) { int sock; int ret; int rtenum; union rip_buf rip_buf; struct rip_packet *packet; struct sockaddr_in from; int len; int vrecv; socklen_t fromlen; struct interface *ifp; struct connected *ifc; struct rip_interface *ri; /* Fetch socket then register myself. */ sock = THREAD_FD (t); rip->t_read = NULL; /* Add myself to tne next event */ rip_event (RIP_READ, sock); /* RIPd manages only IPv4. */ memset (&from, 0, sizeof (struct sockaddr_in)); fromlen = sizeof (struct sockaddr_in); len = recvfrom (sock, (char *)&rip_buf.buf, sizeof (rip_buf.buf), 0, (struct sockaddr *) &from, &fromlen); if (len < 0) { zlog_info ("recvfrom failed: %s", safe_strerror (errno)); return len; } /* Check is this packet comming from myself? */ if (if_check_address (from.sin_addr)) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("ignore packet comes from myself"); return -1; } /* Which interface is this packet comes from. */ ifp = if_lookup_address (from.sin_addr); /* RIP packet received */ if (IS_RIP_DEBUG_EVENT) zlog_debug ("RECV packet from %s port %d on %s", inet_ntoa (from.sin_addr), ntohs (from.sin_port), ifp ? ifp->name : "unknown"); /* If this packet come from unknown interface, ignore it. */ if (ifp == NULL) { zlog_info ("rip_read: cannot find interface for packet from %s port %d", inet_ntoa(from.sin_addr), ntohs (from.sin_port)); return -1; } ifc = connected_lookup_address (ifp, from.sin_addr); if (ifc == NULL) { zlog_info ("rip_read: cannot find connected address for packet from %s " "port %d on interface %s", inet_ntoa(from.sin_addr), ntohs (from.sin_port), ifp->name); return -1; } /* Packet length check. */ if (len < RIP_PACKET_MINSIZ) { zlog_warn ("packet size %d is smaller than minimum size %d", len, RIP_PACKET_MINSIZ); rip_peer_bad_packet (&from); return len; } if (len > RIP_PACKET_MAXSIZ) { zlog_warn ("packet size %d is larger than max size %d", len, RIP_PACKET_MAXSIZ); rip_peer_bad_packet (&from); return len; } /* Packet alignment check. */ if ((len - RIP_PACKET_MINSIZ) % 20) { zlog_warn ("packet size %d is wrong for RIP packet alignment", len); rip_peer_bad_packet (&from); return len; } /* Set RTE number. */ rtenum = ((len - RIP_PACKET_MINSIZ) / 20); /* For easy to handle. */ packet = &rip_buf.rip_packet; /* RIP version check. */ if (packet->version == 0) { zlog_info ("version 0 with command %d received.", packet->command); rip_peer_bad_packet (&from); return -1; } /* Dump RIP packet. */ if (IS_RIP_DEBUG_RECV) rip_packet_dump (packet, len, "RECV"); /* RIP version adjust. This code should rethink now. RFC1058 says that "Version 1 implementations are to ignore this extra data and process only the fields specified in this document.". So RIPv3 packet should be treated as RIPv1 ignoring must be zero field. */ if (packet->version > RIPv2) packet->version = RIPv2; /* Is RIP running or is this RIP neighbor ?*/ ri = ifp->info; if (! ri->running && ! rip_neighbor_lookup (&from)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("RIP is not enabled on interface %s.", ifp->name); rip_peer_bad_packet (&from); return -1; } /* RIP Version check. RFC2453, 4.6 and 5.1 */ vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive); if ((packet->version == RIPv1) && !(vrecv & RIPv1)) { if (IS_RIP_DEBUG_PACKET) zlog_debug (" packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet (&from); return -1; } if ((packet->version == RIPv2) && !(vrecv & RIPv2)) { if (IS_RIP_DEBUG_PACKET) zlog_debug (" packet's v%d doesn't fit to if version spec", packet->version); rip_peer_bad_packet (&from); return -1; } /* RFC2453 5.2 If the router is not configured to authenticate RIP-2 messages, then RIP-1 and unauthenticated RIP-2 messages will be accepted; authenticated RIP-2 messages shall be discarded. */ if ((ri->auth_type == RIP_NO_AUTH) && rtenum && (packet->version == RIPv2) && (packet->rte->family == htons(RIP_FAMILY_AUTH))) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("packet RIPv%d is dropped because authentication disabled", packet->version); rip_peer_bad_packet (&from); return -1; } /* RFC: If the router is configured to authenticate RIP-2 messages, then RIP-1 messages and RIP-2 messages which pass authentication testing shall be accepted; unauthenticated and failed authentication RIP-2 messages shall be discarded. For maximum security, RIP-1 messages should be ignored when authentication is in use (see section 4.1); otherwise, the routing information from authenticated messages will be propagated by RIP-1 routers in an unauthenticated manner. */ /* We make an exception for RIPv1 REQUEST packets, to which we'll * always reply regardless of authentication settings, because: * * - if there other authorised routers on-link, the REQUESTor can * passively obtain the routing updates anyway * - if there are no other authorised routers on-link, RIP can * easily be disabled for the link to prevent giving out information * on state of this routers RIP routing table.. * * I.e. if RIPv1 has any place anymore these days, it's as a very * simple way to distribute routing information (e.g. to embedded * hosts / appliances) and the ability to give out RIPv1 * routing-information freely, while still requiring RIPv2 * authentication for any RESPONSEs might be vaguely useful. */ if (ri->auth_type != RIP_NO_AUTH && packet->version == RIPv1) { /* Discard RIPv1 messages other than REQUESTs */ if (packet->command != RIP_REQUEST) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv1" " dropped because authentication enabled"); rip_peer_bad_packet (&from); return -1; } } else if (ri->auth_type != RIP_NO_AUTH) { const char *auth_desc; if (rtenum == 0) { /* There definitely is no authentication in the packet. */ if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 authentication failed: no auth RTE in packet"); rip_peer_bad_packet (&from); return -1; } /* First RTE must be an Authentication Family RTE */ if (packet->rte->family != htons(RIP_FAMILY_AUTH)) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2" " dropped because authentication enabled"); rip_peer_bad_packet (&from); return -1; } /* Check RIPv2 authentication. */ switch (ntohs(packet->rte->tag)) { case RIP_AUTH_SIMPLE_PASSWORD: auth_desc = "simple"; ret = rip_auth_simple_password (packet->rte, &from, ifp); break; case RIP_AUTH_MD5: auth_desc = "MD5"; ret = rip_auth_md5 (packet, &from, len, ifp); /* Reset RIP packet length to trim MD5 data. */ len = ret; break; default: ret = 0; auth_desc = "unknown type"; if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 Unknown authentication type %d", ntohs (packet->rte->tag)); } if (ret) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 %s authentication success", auth_desc); } else { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIPv2 %s authentication failure", auth_desc); rip_peer_bad_packet (&from); return -1; } } /* Process each command. */ switch (packet->command) { case RIP_RESPONSE: rip_response_process (packet, len, &from, ifc); break; case RIP_REQUEST: case RIP_POLL: rip_request_process (packet, len, &from, ifc); break; case RIP_TRACEON: case RIP_TRACEOFF: zlog_info ("Obsolete command %s received, please sent it to routed", lookup (rip_msg, packet->command)); rip_peer_bad_packet (&from); break; case RIP_POLL_ENTRY: zlog_info ("Obsolete command %s received", lookup (rip_msg, packet->command)); rip_peer_bad_packet (&from); break; default: zlog_info ("Unknown RIP command %d received", packet->command); rip_peer_bad_packet (&from); break; } return len; } /* Write routing table entry to the stream and return next index of the routing table entry in the stream. */ static int rip_write_rte (int num, struct stream *s, struct prefix_ipv4 *p, u_char version, struct rip_info *rinfo) { struct in_addr mask; /* Write routing table entry. */ if (version == RIPv1) { stream_putw (s, AF_INET); stream_putw (s, 0); stream_put_ipv4 (s, p->prefix.s_addr); stream_put_ipv4 (s, 0); stream_put_ipv4 (s, 0); stream_putl (s, rinfo->metric_out); } else { masklen2ip (p->prefixlen, &mask); stream_putw (s, AF_INET); stream_putw (s, rinfo->tag_out); stream_put_ipv4 (s, p->prefix.s_addr); stream_put_ipv4 (s, mask.s_addr); stream_put_ipv4 (s, rinfo->nexthop_out.s_addr); stream_putl (s, rinfo->metric_out); } return ++num; } /* Send update to the ifp or spcified neighbor. */ void rip_output_process (struct connected *ifc, struct sockaddr_in *to, int route_type, u_char version) { int ret; struct stream *s; struct route_node *rp; struct rip_info *rinfo; struct rip_interface *ri; struct prefix_ipv4 *p; struct prefix_ipv4 classfull; struct prefix_ipv4 ifaddrclass; struct key *key = NULL; /* this might need to made dynamic if RIP ever supported auth methods with larger key string sizes */ char auth_str[RIP_AUTH_SIMPLE_SIZE]; size_t doff = 0; /* offset of digest offset field */ int num = 0; int rtemax; int subnetted = 0; struct list *list = NULL; struct listnode *listnode = NULL; /* Logging output event. */ if (IS_RIP_DEBUG_EVENT) { if (to) zlog_debug ("update routes to neighbor %s", inet_ntoa (to->sin_addr)); else zlog_debug ("update routes on interface %s ifindex %d", ifc->ifp->name, ifc->ifp->ifindex); } /* Set output stream. */ s = rip->obuf; /* Reset stream and RTE counter. */ stream_reset (s); rtemax = RIP_MAX_RTE; /* Get RIP interface. */ ri = ifc->ifp->info; /* If output interface is in simple password authentication mode, we need space for authentication data. */ if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD) rtemax -= 1; /* If output interface is in MD5 authentication mode, we need space for authentication header and data. */ if (ri->auth_type == RIP_AUTH_MD5) rtemax -= 2; /* If output interface is in simple password authentication mode and string or keychain is specified we need space for auth. data */ if (ri->auth_type != RIP_NO_AUTH) { if (ri->key_chain) { struct keychain *keychain; keychain = keychain_lookup (ri->key_chain); if (keychain) key = key_lookup_for_send (keychain); } /* to be passed to auth functions later */ rip_auth_prepare_str_send (ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE); } if (version == RIPv1) { memcpy (&ifaddrclass, ifc->address, sizeof (struct prefix_ipv4)); apply_classful_mask_ipv4 (&ifaddrclass); subnetted = 0; if (ifc->address->prefixlen > ifaddrclass.prefixlen) subnetted = 1; } for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL && listcount (list) != 0) { rinfo = listgetdata (listhead (list)); /* For RIPv1, if we are subnetted, output subnets in our network */ /* that have the same mask as the output "interface". For other */ /* networks, only the classfull version is output. */ if (version == RIPv1) { p = (struct prefix_ipv4 *) &rp->p; if (IS_RIP_DEBUG_PACKET) zlog_debug("RIPv1 mask check, %s/%d considered for output", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); if (subnetted && prefix_match ((struct prefix *) &ifaddrclass, &rp->p)) { if ((ifc->address->prefixlen != rp->p.prefixlen) && (rp->p.prefixlen != 32)) continue; } else { memcpy (&classfull, &rp->p, sizeof(struct prefix_ipv4)); apply_classful_mask_ipv4(&classfull); if (rp->p.u.prefix4.s_addr != 0 && classfull.prefixlen != rp->p.prefixlen) continue; } if (IS_RIP_DEBUG_PACKET) zlog_debug("RIPv1 mask check, %s/%d made it through", inet_ntoa (rp->p.u.prefix4), rp->p.prefixlen); } else p = (struct prefix_ipv4 *) &rp->p; /* Apply output filters. */ ret = rip_outgoing_filter (p, ri); if (ret < 0) continue; /* Changed route only output. */ if (route_type == rip_changed_route && (! (rinfo->flags & RIP_RTF_CHANGED))) continue; /* Split horizon. */ /* if (split_horizon == rip_split_horizon) */ if (ri->split_horizon == RIP_SPLIT_HORIZON) { /* * We perform split horizon for RIP and connected route. * For rip routes, we want to suppress the route if we would * end up sending the route back on the interface that we * learned it from, with a higher metric. For connected routes, * we suppress the route if the prefix is a subset of the * source address that we are going to use for the packet * (in order to handle the case when multiple subnets are * configured on the same interface). */ int suppress = 0; struct rip_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && tmp_rinfo->ifindex == ifc->ifp->ifindex) { suppress = 1; break; } if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) suppress = 1; if (suppress) continue; } /* Preparation for route-map. */ rinfo->metric_set = 0; rinfo->nexthop_out.s_addr = 0; rinfo->metric_out = rinfo->metric; rinfo->tag_out = rinfo->tag; rinfo->ifindex_out = ifc->ifp->ifindex; /* In order to avoid some local loops, * if the RIP route has a nexthop via this interface, keep the nexthop, * otherwise set it to 0. The nexthop should not be propagated * beyond the local broadcast/multicast area in order * to avoid an IGP multi-level recursive look-up. * see (4.4) */ if (rinfo->ifindex == ifc->ifp->ifindex) rinfo->nexthop_out = rinfo->nexthop; /* Interface route-map */ if (ri->routemap[RIP_FILTER_OUT]) { ret = route_map_apply (ri->routemap[RIP_FILTER_OUT], (struct prefix *) p, RMAP_RIP, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("RIP %s/%d is filtered by route-map out", inet_ntoa (p->prefix), p->prefixlen); continue; } } /* Apply redistribute route map - continue, if deny */ if (rip->route_map[rinfo->type].name && rinfo->sub_type != RIP_ROUTE_INTERFACE) { ret = route_map_apply (rip->route_map[rinfo->type].map, (struct prefix *)p, RMAP_RIP, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIP_DEBUG_PACKET) zlog_debug ("%s/%d is filtered by route-map", inet_ntoa (p->prefix), p->prefixlen); continue; } } /* When route-map does not set metric. */ if (! rinfo->metric_set) { /* If redistribute metric is set. */ if (rip->route_map[rinfo->type].metric_config && rinfo->metric != RIP_METRIC_INFINITY) { rinfo->metric_out = rip->route_map[rinfo->type].metric; } else { /* If the route is not connected or localy generated one, use default-metric value*/ if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT && rinfo->metric != RIP_METRIC_INFINITY) rinfo->metric_out = rip->default_metric; } } /* Apply offset-list */ if (rinfo->metric != RIP_METRIC_INFINITY) rip_offset_list_apply_out (p, ifc->ifp, &rinfo->metric_out); if (rinfo->metric_out > RIP_METRIC_INFINITY) rinfo->metric_out = RIP_METRIC_INFINITY; /* Perform split-horizon with poisoned reverse * for RIP and connected routes. **/ if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) { /* * We perform split horizon for RIP and connected route. * For rip routes, we want to suppress the route if we would * end up sending the route back on the interface that we * learned it from, with a higher metric. For connected routes, * we suppress the route if the prefix is a subset of the * source address that we are going to use for the packet * (in order to handle the case when multiple subnets are * configured on the same interface). */ struct rip_info *tmp_rinfo = NULL; for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo)) if (tmp_rinfo->type == ZEBRA_ROUTE_RIP && tmp_rinfo->ifindex == ifc->ifp->ifindex) rinfo->metric_out = RIP_METRIC_INFINITY; if (tmp_rinfo->type == ZEBRA_ROUTE_CONNECT && prefix_match((struct prefix *)p, ifc->address)) rinfo->metric_out = RIP_METRIC_INFINITY; } /* Prepare preamble, auth headers, if needs be */ if (num == 0) { stream_putc (s, RIP_RESPONSE); stream_putc (s, version); stream_putw (s, 0); /* auth header for !v1 && !no_auth */ if ( (ri->auth_type != RIP_NO_AUTH) && (version != RIPv1) ) doff = rip_auth_header_write (s, ri, key, auth_str, RIP_AUTH_SIMPLE_SIZE); } /* Write RTE to the stream. */ num = rip_write_rte (num, s, p, version, rinfo); if (num == rtemax) { if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc); if (ret >= 0 && IS_RIP_DEBUG_SEND) rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), stream_get_endp(s), "SEND"); num = 0; stream_reset (s); } } /* Flush unwritten RTE. */ if (num != 0) { if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5) rip_auth_md5_set (s, ri, doff, auth_str, RIP_AUTH_SIMPLE_SIZE); ret = rip_send_packet (STREAM_DATA (s), stream_get_endp (s), to, ifc); if (ret >= 0 && IS_RIP_DEBUG_SEND) rip_packet_dump ((struct rip_packet *)STREAM_DATA (s), stream_get_endp (s), "SEND"); num = 0; stream_reset (s); } /* Statistics updates. */ ri->sent_updates++; } /* Send RIP packet to the interface. */ static void rip_update_interface (struct connected *ifc, u_char version, int route_type) { struct sockaddr_in to; /* When RIP version is 2 and multicast enable interface. */ if (version == RIPv2 && if_is_multicast (ifc->ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_debug ("multicast announce on %s ", ifc->ifp->name); rip_output_process (ifc, NULL, route_type, version); return; } /* If we can't send multicast packet, send it with unicast. */ if (if_is_broadcast (ifc->ifp) || if_is_pointopoint (ifc->ifp)) { if (ifc->address->family == AF_INET) { /* Destination address and port setting. */ memset (&to, 0, sizeof (struct sockaddr_in)); if (ifc->destination) /* use specified broadcast or peer destination addr */ to.sin_addr = ifc->destination->u.prefix4; else if (ifc->address->prefixlen < IPV4_MAX_PREFIXLEN) /* calculate the appropriate broadcast address */ to.sin_addr.s_addr = ipv4_broadcast_addr(ifc->address->u.prefix4.s_addr, ifc->address->prefixlen); else /* do not know where to send the packet */ return; to.sin_port = htons (RIP_PORT_DEFAULT); if (IS_RIP_DEBUG_EVENT) zlog_debug("%s announce to %s on %s", CONNECTED_PEER(ifc) ? "unicast" : "broadcast", inet_ntoa (to.sin_addr), ifc->ifp->name); rip_output_process (ifc, &to, route_type, version); } } } /* Update send to all interface and neighbor. */ static void rip_update_process (int route_type) { struct listnode *node; struct listnode *ifnode, *ifnnode; struct connected *connected; struct interface *ifp; struct rip_interface *ri; struct route_node *rp; struct sockaddr_in to; struct prefix_ipv4 *p; /* Send RIP update to each interface. */ for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { if (if_is_loopback (ifp)) continue; if (! if_is_operative (ifp)) continue; /* Fetch RIP interface information. */ ri = ifp->info; /* When passive interface is specified, suppress announce to the interface. */ if (ri->passive) continue; if (ri->running) { /* * If there is no version configuration in the interface, * use rip's version setting. */ int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send : ri->ri_send); if (IS_RIP_DEBUG_EVENT) zlog_debug("SEND UPDATE to %s ifindex %d", (ifp->name ? ifp->name : "_unknown_"), ifp->ifindex); /* send update on each connected network */ for (ALL_LIST_ELEMENTS (ifp->connected, ifnode, ifnnode, connected)) { if (connected->address->family == AF_INET) { if (vsend & RIPv1) rip_update_interface (connected, RIPv1, route_type); if ((vsend & RIPv2) && if_is_multicast(ifp)) rip_update_interface (connected, RIPv2, route_type); } } } } /* RIP send updates to each neighbor. */ for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) if (rp->info != NULL) { p = (struct prefix_ipv4 *) &rp->p; ifp = if_lookup_address (p->prefix); if (! ifp) { zlog_warn ("Neighbor %s doesnt have connected interface!", inet_ntoa (p->prefix)); continue; } if ( (connected = connected_lookup_address (ifp, p->prefix)) == NULL) { zlog_warn ("Neighbor %s doesnt have connected network", inet_ntoa (p->prefix)); continue; } /* Set destination address and port */ memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_addr = p->prefix; to.sin_port = htons (RIP_PORT_DEFAULT); /* RIP version is rip's configuration. */ rip_output_process (connected, &to, route_type, rip->version_send); } } /* RIP's periodical timer. */ static int rip_update (struct thread *t) { /* Clear timer pointer. */ rip->t_update = NULL; if (IS_RIP_DEBUG_EVENT) zlog_debug ("update timer fire!"); /* Process update output. */ rip_update_process (rip_all_route); /* Triggered updates may be suppressed if a regular update is due by the time the triggered update would be sent. */ if (rip->t_triggered_interval) { thread_cancel (rip->t_triggered_interval); rip->t_triggered_interval = NULL; } rip->trigger = 0; /* Register myself. */ rip_event (RIP_UPDATE_EVENT, 0); return 0; } /* Walk down the RIP routing table then clear changed flag. */ static void rip_clear_changed_flag (void) { struct route_node *rp; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { UNSET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* This flag can be set only on the first entry. */ break; } } /* Triggered update interval timer. */ static int rip_triggered_interval (struct thread *t) { int rip_triggered_update (struct thread *); rip->t_triggered_interval = NULL; if (rip->trigger) { rip->trigger = 0; rip_triggered_update (t); } return 0; } /* Execute triggered update. */ static int rip_triggered_update (struct thread *t) { int interval; /* Clear thred pointer. */ rip->t_triggered_update = NULL; /* Cancel interval timer. */ if (rip->t_triggered_interval) { thread_cancel (rip->t_triggered_interval); rip->t_triggered_interval = NULL; } rip->trigger = 0; /* Logging triggered update. */ if (IS_RIP_DEBUG_EVENT) zlog_debug ("triggered update!"); /* Split Horizon processing is done when generating triggered updates as well as normal updates (see section 2.6). */ rip_update_process (rip_changed_route); /* Once all of the triggered updates have been generated, the route change flags should be cleared. */ rip_clear_changed_flag (); /* After a triggered update is sent, a timer should be set for a random interval between 1 and 5 seconds. If other changes that would trigger updates occur before the timer expires, a single update is triggered when the timer expires. */ interval = (random () % 5) + 1; rip->t_triggered_interval = thread_add_timer (master, rip_triggered_interval, NULL, interval); return 0; } /* Withdraw redistributed route. */ void rip_redistribute_withdraw (int type) { struct route_node *rp; struct rip_info *rinfo = NULL; struct list *list = NULL; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); if (rinfo->type == type && rinfo->sub_type != RIP_ROUTE_INTERFACE) { /* Perform poisoned reverse. */ rinfo->metric = RIP_METRIC_INFINITY; RIP_TIMER_ON (rinfo->t_garbage_collect, rip_garbage_collect, rip->garbage_time); RIP_TIMER_OFF (rinfo->t_timeout); rinfo->flags |= RIP_RTF_CHANGED; if (IS_RIP_DEBUG_EVENT) { struct prefix_ipv4 *p = (struct prefix_ipv4 *) &rp->p; zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [withdraw]", inet_ntoa(p->prefix), p->prefixlen, ifindex2ifname(rinfo->ifindex)); } rip_event (RIP_TRIGGERED_UPDATE, 0); } } } /* Create new RIP instance and set it to global variable. */ static int rip_create (void) { rip = XCALLOC (MTYPE_RIP, sizeof (struct rip)); /* Set initial value. */ rip->version_send = RI_RIP_VERSION_2; rip->version_recv = RI_RIP_VERSION_1_AND_2; rip->update_time = RIP_UPDATE_TIMER_DEFAULT; rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; /* Initialize RIP routig table. */ rip->table = route_table_init (); rip->route = route_table_init (); rip->neighbor = route_table_init (); /* Make output stream. */ rip->obuf = stream_new (1500); /* Make socket. */ rip->sock = rip_create_socket (NULL); if (rip->sock < 0) return rip->sock; /* Create read and timer thread. */ rip_event (RIP_READ, rip->sock); rip_event (RIP_UPDATE_EVENT, 1); return 0; } /* Sned RIP request to the destination. */ int rip_request_send (struct sockaddr_in *to, struct interface *ifp, u_char version, struct connected *connected) { struct rte *rte; struct rip_packet rip_packet; struct listnode *node, *nnode; memset (&rip_packet, 0, sizeof (rip_packet)); rip_packet.command = RIP_REQUEST; rip_packet.version = version; rte = rip_packet.rte; rte->metric = htonl (RIP_METRIC_INFINITY); if (connected) { /* * connected is only sent for ripv1 case, or when * interface does not support multicast. Caller loops * over each connected address for this case. */ if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), to, connected) != sizeof (rip_packet)) return -1; else return sizeof (rip_packet); } /* send request on each connected network */ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected)) { struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; if (rip_send_packet ((u_char *) &rip_packet, sizeof (rip_packet), to, connected) != sizeof (rip_packet)) return -1; } return sizeof (rip_packet); } static int rip_update_jitter (unsigned long time) { #define JITTER_BOUND 4 /* We want to get the jitter to +/- 1/JITTER_BOUND the interval. Given that, we cannot let time be less than JITTER_BOUND seconds. The RIPv2 RFC says jitter should be small compared to update_time. We consider 1/JITTER_BOUND to be small. */ int jitter_input = time; int jitter; if (jitter_input < JITTER_BOUND) jitter_input = JITTER_BOUND; jitter = (((rand () % ((jitter_input * 2) + 1)) - jitter_input)); return jitter/JITTER_BOUND; } void rip_event (enum rip_event event, int sock) { int jitter = 0; switch (event) { case RIP_READ: rip->t_read = thread_add_read (master, rip_read, NULL, sock); break; case RIP_UPDATE_EVENT: if (rip->t_update) { thread_cancel (rip->t_update); rip->t_update = NULL; } jitter = rip_update_jitter (rip->update_time); rip->t_update = thread_add_timer (master, rip_update, NULL, sock ? 2 : rip->update_time + jitter); break; case RIP_TRIGGERED_UPDATE: if (rip->t_triggered_interval) rip->trigger = 1; else if (! rip->t_triggered_update) rip->t_triggered_update = thread_add_event (master, rip_triggered_update, NULL, 0); break; default: break; } } DEFUN (router_rip, router_rip_cmd, "router rip", "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { int ret; /* If rip is not enabled before. */ if (! rip) { ret = rip_create (); if (ret < 0) { zlog_info ("Can't create RIP"); return CMD_WARNING; } } vty->node = RIP_NODE; vty->index = rip; return CMD_SUCCESS; } DEFUN (no_router_rip, no_router_rip_cmd, "no router rip", NO_STR "Enable a routing process\n" "Routing Information Protocol (RIP)\n") { if (rip) rip_clean (); return CMD_SUCCESS; } DEFUN (rip_version, rip_version_cmd, "version <1-2>", "Set routing protocol version\n" "version\n") { int version; version = atoi (argv[0]); if (version != RIPv1 && version != RIPv2) { vty_out (vty, "invalid rip version %d%s", version, VTY_NEWLINE); return CMD_WARNING; } rip->version_send = version; rip->version_recv = version; return CMD_SUCCESS; } DEFUN (no_rip_version, no_rip_version_cmd, "no version", NO_STR "Set routing protocol version\n") { /* Set RIP version to the default. */ rip->version_send = RI_RIP_VERSION_2; rip->version_recv = RI_RIP_VERSION_1_AND_2; return CMD_SUCCESS; } ALIAS (no_rip_version, no_rip_version_val_cmd, "no version <1-2>", NO_STR "Set routing protocol version\n" "version\n") DEFUN (rip_route, rip_route_cmd, "route A.B.C.D/M", "RIP static route configuration\n" "IP prefix /\n") { int ret; struct prefix_ipv4 p; struct route_node *node; ret = str2prefix_ipv4 (argv[0], &p); if (ret < 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv4 (&p); /* For router rip configuration. */ node = route_node_get (rip->route, (struct prefix *) &p); if (node->info) { vty_out (vty, "There is already same static route.%s", VTY_NEWLINE); route_unlock_node (node); return CMD_WARNING; } node->info = (char *)"static"; rip_redistribute_add (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0, NULL, 0, 0); return CMD_SUCCESS; } DEFUN (no_rip_route, no_rip_route_cmd, "no route A.B.C.D/M", NO_STR "RIP static route configuration\n" "IP prefix /\n") { int ret; struct prefix_ipv4 p; struct route_node *node; ret = str2prefix_ipv4 (argv[0], &p); if (ret < 0) { vty_out (vty, "Malformed address%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv4 (&p); /* For router rip configuration. */ node = route_node_lookup (rip->route, (struct prefix *) &p); if (! node) { vty_out (vty, "Can't find route %s.%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } rip_redistribute_delete (ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0); route_unlock_node (node); node->info = NULL; route_unlock_node (node); return CMD_SUCCESS; } #if 0 static void rip_update_default_metric (void) { struct route_node *np; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; for (np = route_top (rip->table); np; np = route_next (np)) if ((list = np->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) if (rinfo->type != ZEBRA_ROUTE_RIP && rinfo->type != ZEBRA_ROUTE_CONNECT) rinfo->metric = rip->default_metric; } #endif DEFUN (rip_default_metric, rip_default_metric_cmd, "default-metric <1-16>", "Set a metric of redistribute routes\n" "Default metric\n") { if (rip) { rip->default_metric = atoi (argv[0]); /* rip_update_default_metric (); */ } return CMD_SUCCESS; } DEFUN (no_rip_default_metric, no_rip_default_metric_cmd, "no default-metric", NO_STR "Set a metric of redistribute routes\n" "Default metric\n") { if (rip) { rip->default_metric = RIP_DEFAULT_METRIC_DEFAULT; /* rip_update_default_metric (); */ } return CMD_SUCCESS; } ALIAS (no_rip_default_metric, no_rip_default_metric_val_cmd, "no default-metric <1-16>", NO_STR "Set a metric of redistribute routes\n" "Default metric\n") DEFUN (rip_timers, rip_timers_cmd, "timers basic <5-2147483647> <5-2147483647> <5-2147483647>", "Adjust routing timers\n" "Basic routing protocol update timers\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") { unsigned long update; unsigned long timeout; unsigned long garbage; char *endptr = NULL; unsigned long RIP_TIMER_MAX = 2147483647; unsigned long RIP_TIMER_MIN = 5; update = strtoul (argv[0], &endptr, 10); if (update > RIP_TIMER_MAX || update < RIP_TIMER_MIN || *endptr != '\0') { vty_out (vty, "update timer value error%s", VTY_NEWLINE); return CMD_WARNING; } timeout = strtoul (argv[1], &endptr, 10); if (timeout > RIP_TIMER_MAX || timeout < RIP_TIMER_MIN || *endptr != '\0') { vty_out (vty, "timeout timer value error%s", VTY_NEWLINE); return CMD_WARNING; } garbage = strtoul (argv[2], &endptr, 10); if (garbage > RIP_TIMER_MAX || garbage < RIP_TIMER_MIN || *endptr != '\0') { vty_out (vty, "garbage timer value error%s", VTY_NEWLINE); return CMD_WARNING; } /* Set each timer value. */ rip->update_time = update; rip->timeout_time = timeout; rip->garbage_time = garbage; /* Reset update timer thread. */ rip_event (RIP_UPDATE_EVENT, 0); return CMD_SUCCESS; } DEFUN (no_rip_timers, no_rip_timers_cmd, "no timers basic", NO_STR "Adjust routing timers\n" "Basic routing protocol update timers\n") { /* Set each timer value to the default. */ rip->update_time = RIP_UPDATE_TIMER_DEFAULT; rip->timeout_time = RIP_TIMEOUT_TIMER_DEFAULT; rip->garbage_time = RIP_GARBAGE_TIMER_DEFAULT; /* Reset update timer thread. */ rip_event (RIP_UPDATE_EVENT, 0); return CMD_SUCCESS; } ALIAS (no_rip_timers, no_rip_timers_val_cmd, "no timers basic <0-65535> <0-65535> <0-65535>", NO_STR "Adjust routing timers\n" "Basic routing protocol update timers\n" "Routing table update timer value in second. Default is 30.\n" "Routing information timeout timer. Default is 180.\n" "Garbage collection timer. Default is 120.\n") struct route_table *rip_distance_table; struct rip_distance { /* Distance value for the IP source prefix. */ u_char distance; /* Name of the access-list to be matched. */ char *access_list; }; static struct rip_distance * rip_distance_new (void) { return XCALLOC (MTYPE_RIP_DISTANCE, sizeof (struct rip_distance)); } static void rip_distance_free (struct rip_distance *rdistance) { XFREE (MTYPE_RIP_DISTANCE, rdistance); } static int rip_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; u_char distance; struct route_node *rn; struct rip_distance *rdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); /* Get RIP distance node. */ rn = route_node_get (rip_distance_table, (struct prefix *) &p); if (rn->info) { rdistance = rn->info; route_unlock_node (rn); } else { rdistance = rip_distance_new (); rn->info = rdistance; } /* Set distance value. */ rdistance->distance = distance; /* Reset access-list configuration. */ if (rdistance->access_list) { free (rdistance->access_list); rdistance->access_list = NULL; } if (access_list_str) rdistance->access_list = strdup (access_list_str); return CMD_SUCCESS; } static int rip_distance_unset (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; struct route_node *rn; struct rip_distance *rdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } rn = route_node_lookup (rip_distance_table, (struct prefix *)&p); if (! rn) { vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } rdistance = rn->info; if (rdistance->access_list) free (rdistance->access_list); rip_distance_free (rdistance); rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); return CMD_SUCCESS; } static void rip_distance_reset (void) { struct route_node *rn; struct rip_distance *rdistance; for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) if ((rdistance = rn->info) != NULL) { if (rdistance->access_list) free (rdistance->access_list); rip_distance_free (rdistance); rn->info = NULL; route_unlock_node (rn); } } /* Apply RIP information to distance method. */ u_char rip_distance_apply (struct rip_info *rinfo) { struct route_node *rn; struct prefix_ipv4 p; struct rip_distance *rdistance; struct access_list *alist; if (! rip) return 0; memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefix = rinfo->from; p.prefixlen = IPV4_MAX_BITLEN; /* Check source address. */ rn = route_node_match (rip_distance_table, (struct prefix *) &p); if (rn) { rdistance = rn->info; route_unlock_node (rn); if (rdistance->access_list) { alist = access_list_lookup (AFI_IP, rdistance->access_list); if (alist == NULL) return 0; if (access_list_apply (alist, &rinfo->rp->p) == FILTER_DENY) return 0; return rdistance->distance; } else return rdistance->distance; } if (rip->distance) return rip->distance; return 0; } static void rip_distance_show (struct vty *vty) { struct route_node *rn; struct rip_distance *rdistance; int header = 1; char buf[BUFSIZ]; vty_out (vty, " Distance: (default is %d)%s", rip->distance ? rip->distance :ZEBRA_RIP_DISTANCE_DEFAULT, VTY_NEWLINE); for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) if ((rdistance = rn->info) != NULL) { if (header) { vty_out (vty, " Address Distance List%s", VTY_NEWLINE); header = 0; } sprintf (buf, "%s/%d", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen); vty_out (vty, " %-20s %4d %s%s", buf, rdistance->distance, rdistance->access_list ? rdistance->access_list : "", VTY_NEWLINE); } } DEFUN (rip_distance, rip_distance_cmd, "distance <1-255>", "Administrative distance\n" "Distance value\n") { rip->distance = atoi (argv[0]); return CMD_SUCCESS; } DEFUN (no_rip_distance, no_rip_distance_cmd, "no distance <1-255>", NO_STR "Administrative distance\n" "Distance value\n") { rip->distance = 0; return CMD_SUCCESS; } DEFUN (rip_distance_source, rip_distance_source_cmd, "distance <1-255> A.B.C.D/M", "Administrative distance\n" "Distance value\n" "IP source prefix\n") { rip_distance_set (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_rip_distance_source, no_rip_distance_source_cmd, "no distance <1-255> A.B.C.D/M", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n") { rip_distance_unset (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (rip_distance_source_access_list, rip_distance_source_access_list_cmd, "distance <1-255> A.B.C.D/M WORD", "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { rip_distance_set (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_rip_distance_source_access_list, no_rip_distance_source_access_list_cmd, "no distance <1-255> A.B.C.D/M WORD", NO_STR "Administrative distance\n" "Distance value\n" "IP source prefix\n" "Access list name\n") { rip_distance_unset (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } /* Update ECMP routes to zebra when ECMP is disabled. */ static void rip_ecmp_disable (void) { struct route_node *rp; struct rip_info *rinfo, *tmp_rinfo; struct list *list; struct listnode *node, *nextnode; if (!rip) return; for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL && listcount (list) > 1) { rinfo = listgetdata (listhead (list)); if (!rip_route_rte (rinfo)) continue; /* Drop all other entries, except the first one. */ for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo)) if (tmp_rinfo != rinfo) { RIP_TIMER_OFF (tmp_rinfo->t_timeout); RIP_TIMER_OFF (tmp_rinfo->t_garbage_collect); list_delete_node (list, node); rip_info_free (tmp_rinfo); } /* Update zebra. */ rip_zebra_ipv4_add (rp); /* Set the route change flag. */ SET_FLAG (rinfo->flags, RIP_RTF_CHANGED); /* Signal the output process to trigger an update. */ rip_event (RIP_TRIGGERED_UPDATE, 0); } } DEFUN (rip_allow_ecmp, rip_allow_ecmp_cmd, "allow-ecmp", "Allow Equal Cost MultiPath\n") { if (rip->ecmp) { vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE); return CMD_WARNING; } rip->ecmp = 1; zlog_info ("ECMP is enabled."); return CMD_SUCCESS; } DEFUN (no_rip_allow_ecmp, no_rip_allow_ecmp_cmd, "no allow-ecmp", NO_STR "Allow Equal Cost MultiPath\n") { if (!rip->ecmp) { vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE); return CMD_WARNING; } rip->ecmp = 0; zlog_info ("ECMP is disabled."); rip_ecmp_disable (); return CMD_SUCCESS; } /* Print out routes update time. */ static void rip_vty_out_uptime (struct vty *vty, struct rip_info *rinfo) { time_t clock; struct tm *tm; #define TIME_BUF 25 char timebuf [TIME_BUF]; struct thread *thread; if ((thread = rinfo->t_timeout) != NULL) { clock = thread_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } else if ((thread = rinfo->t_garbage_collect) != NULL) { clock = thread_timer_remain_second (thread); tm = gmtime (&clock); strftime (timebuf, TIME_BUF, "%M:%S", tm); vty_out (vty, "%5s", timebuf); } } static const char * rip_route_type_print (int sub_type) { switch (sub_type) { case RIP_ROUTE_RTE: return "n"; case RIP_ROUTE_STATIC: return "s"; case RIP_ROUTE_DEFAULT: return "d"; case RIP_ROUTE_REDISTRIBUTE: return "r"; case RIP_ROUTE_INTERFACE: return "i"; default: return "?"; } } DEFUN (show_ip_rip, show_ip_rip_cmd, "show ip rip", SHOW_STR IP_STR "Show RIP routes\n") { struct route_node *np; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; if (! rip) return CMD_SUCCESS; vty_out (vty, "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP%s" "Sub-codes:%s" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s" " (i) - interface%s%s" " Network Next Hop Metric From Tag Time%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (np = route_top (rip->table); np; np = route_next (np)) if ((list = np->info) != NULL) for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { int len; len = vty_out (vty, "%c(%s) %s/%d", /* np->lock, For debugging. */ zebra_route_char(rinfo->type), rip_route_type_print (rinfo->sub_type), inet_ntoa (np->p.u.prefix4), np->p.prefixlen); len = 24 - len; if (len > 0) vty_out (vty, "%*s", len, " "); if (rinfo->nexthop.s_addr) vty_out (vty, "%-20s %2d ", inet_ntoa (rinfo->nexthop), rinfo->metric); else vty_out (vty, "0.0.0.0 %2d ", rinfo->metric); /* Route which exist in kernel routing table. */ if ((rinfo->type == ZEBRA_ROUTE_RIP) && (rinfo->sub_type == RIP_ROUTE_RTE)) { vty_out (vty, "%-15s ", inet_ntoa (rinfo->from)); vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else if (rinfo->metric == RIP_METRIC_INFINITY) { vty_out (vty, "self "); vty_out (vty, "%3d ", rinfo->tag); rip_vty_out_uptime (vty, rinfo); } else { if (rinfo->external_metric) { len = vty_out (vty, "self (%s:%d)", zebra_route_string(rinfo->type), rinfo->external_metric); len = 16 - len; if (len > 0) vty_out (vty, "%*s", len, " "); } else vty_out (vty, "self "); vty_out (vty, "%3d", rinfo->tag); } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } /* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */ DEFUN (show_ip_rip_status, show_ip_rip_status_cmd, "show ip rip status", SHOW_STR IP_STR "Show RIP routes\n" "IP routing protocol process parameters and statistics\n") { struct listnode *node; struct interface *ifp; struct rip_interface *ri; extern const struct message ri_version_msg[]; const char *send_version; const char *receive_version; if (! rip) return CMD_SUCCESS; vty_out (vty, "Routing Protocol is \"rip\"%s", VTY_NEWLINE); vty_out (vty, " Sending updates every %ld seconds with +/-50%%,", rip->update_time); vty_out (vty, " next due in %lu seconds%s", thread_timer_remain_second(rip->t_update), VTY_NEWLINE); vty_out (vty, " Timeout after %ld seconds,", rip->timeout_time); vty_out (vty, " garbage collect after %ld seconds%s", rip->garbage_time, VTY_NEWLINE); /* Filtering status show. */ config_show_distribute (vty); /* Default metric information. */ vty_out (vty, " Default redistribution metric is %d%s", rip->default_metric, VTY_NEWLINE); /* Redistribute information. */ vty_out (vty, " Redistributing:"); config_write_rip_redistribute (vty, 0); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " Default version control: send version %s,", lookup(ri_version_msg,rip->version_send)); if (rip->version_recv == RI_RIP_VERSION_1_AND_2) vty_out (vty, " receive any version %s", VTY_NEWLINE); else vty_out (vty, " receive version %s %s", lookup(ri_version_msg,rip->version_recv), VTY_NEWLINE); vty_out (vty, " Interface Send Recv Key-chain%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if (!ri->running) continue; if (ri->enable_network || ri->enable_interface) { if (ri->ri_send == RI_RIP_UNSPEC) send_version = lookup (ri_version_msg, rip->version_send); else send_version = lookup (ri_version_msg, ri->ri_send); if (ri->ri_receive == RI_RIP_UNSPEC) receive_version = lookup (ri_version_msg, rip->version_recv); else receive_version = lookup (ri_version_msg, ri->ri_receive); vty_out (vty, " %-17s%-3s %-3s %s%s", ifp->name, send_version, receive_version, ri->key_chain ? ri->key_chain : "", VTY_NEWLINE); } } vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE); config_write_rip_network (vty, 0); { int found_passive = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { ri = ifp->info; if ((ri->enable_network || ri->enable_interface) && ri->passive) { if (!found_passive) { vty_out (vty, " Passive Interface(s):%s", VTY_NEWLINE); found_passive = 1; } vty_out (vty, " %s%s", ifp->name, VTY_NEWLINE); } } } vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE); vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE); rip_peer_display (vty); rip_distance_show (vty); return CMD_SUCCESS; } /* RIP configuration write function. */ static int config_write_rip (struct vty *vty) { int write = 0; struct route_node *rn; struct rip_distance *rdistance; if (rip) { /* Router RIP statement. */ vty_out (vty, "router rip%s", VTY_NEWLINE); write++; /* RIP version statement. Default is RIP version 2. */ if (rip->version_send != RI_RIP_VERSION_2 || rip->version_recv != RI_RIP_VERSION_1_AND_2) vty_out (vty, " version %d%s", rip->version_send, VTY_NEWLINE); /* RIP timer configuration. */ if (rip->update_time != RIP_UPDATE_TIMER_DEFAULT || rip->timeout_time != RIP_TIMEOUT_TIMER_DEFAULT || rip->garbage_time != RIP_GARBAGE_TIMER_DEFAULT) vty_out (vty, " timers basic %lu %lu %lu%s", rip->update_time, rip->timeout_time, rip->garbage_time, VTY_NEWLINE); /* Default information configuration. */ if (rip->default_information) { if (rip->default_information_route_map) vty_out (vty, " default-information originate route-map %s%s", rip->default_information_route_map, VTY_NEWLINE); else vty_out (vty, " default-information originate%s", VTY_NEWLINE); } /* Redistribute configuration. */ config_write_rip_redistribute (vty, 1); /* RIP offset-list configuration. */ config_write_rip_offset_list (vty); /* RIP enabled network and interface configuration. */ config_write_rip_network (vty, 1); /* RIP default metric configuration */ if (rip->default_metric != RIP_DEFAULT_METRIC_DEFAULT) vty_out (vty, " default-metric %d%s", rip->default_metric, VTY_NEWLINE); /* Distribute configuration. */ write += config_write_distribute (vty); /* Interface routemap configuration */ write += config_write_if_rmap (vty); /* Distance configuration. */ if (rip->distance) vty_out (vty, " distance %d%s", rip->distance, VTY_NEWLINE); /* RIP source IP prefix distance configuration. */ for (rn = route_top (rip_distance_table); rn; rn = route_next (rn)) if ((rdistance = rn->info) != NULL) vty_out (vty, " distance %d %s/%d %s%s", rdistance->distance, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, rdistance->access_list ? rdistance->access_list : "", VTY_NEWLINE); /* ECMP configuration. */ if (rip->ecmp) vty_out (vty, " allow-ecmp%s", VTY_NEWLINE); /* RIP static route configuration. */ for (rn = route_top (rip->route); rn; rn = route_next (rn)) if (rn->info) vty_out (vty, " route %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); } return write; } /* RIP node structure. */ static struct cmd_node rip_node = { RIP_NODE, "%s(config-router)# ", 1 }; /* Distribute-list update functions. */ static void rip_distribute_update (struct distribute *dist) { struct interface *ifp; struct rip_interface *ri; struct access_list *alist; struct prefix_list *plist; if (! dist->ifname) return; ifp = if_lookup_by_name (dist->ifname); if (ifp == NULL) return; ri = ifp->info; if (dist->list[DISTRIBUTE_IN]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_IN]); if (alist) ri->list[RIP_FILTER_IN] = alist; else ri->list[RIP_FILTER_IN] = NULL; } else ri->list[RIP_FILTER_IN] = NULL; if (dist->list[DISTRIBUTE_OUT]) { alist = access_list_lookup (AFI_IP, dist->list[DISTRIBUTE_OUT]); if (alist) ri->list[RIP_FILTER_OUT] = alist; else ri->list[RIP_FILTER_OUT] = NULL; } else ri->list[RIP_FILTER_OUT] = NULL; if (dist->prefix[DISTRIBUTE_IN]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_IN]); if (plist) ri->prefix[RIP_FILTER_IN] = plist; else ri->prefix[RIP_FILTER_IN] = NULL; } else ri->prefix[RIP_FILTER_IN] = NULL; if (dist->prefix[DISTRIBUTE_OUT]) { plist = prefix_list_lookup (AFI_IP, dist->prefix[DISTRIBUTE_OUT]); if (plist) ri->prefix[RIP_FILTER_OUT] = plist; else ri->prefix[RIP_FILTER_OUT] = NULL; } else ri->prefix[RIP_FILTER_OUT] = NULL; } void rip_distribute_update_interface (struct interface *ifp) { struct distribute *dist; dist = distribute_lookup (ifp->name); if (dist) rip_distribute_update (dist); } /* Update all interface's distribute list. */ /* ARGSUSED */ static void rip_distribute_update_all (struct prefix_list *notused) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_distribute_update_interface (ifp); } /* ARGSUSED */ static void rip_distribute_update_all_wrapper(struct access_list *notused) { rip_distribute_update_all(NULL); } /* Delete all added rip route. */ void rip_clean (void) { int i; struct route_node *rp; struct rip_info *rinfo = NULL; struct list *list = NULL; struct listnode *listnode = NULL; if (rip) { /* Clear RIP routes */ for (rp = route_top (rip->table); rp; rp = route_next (rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata (listhead (list)); if (rip_route_rte (rinfo)) rip_zebra_ipv4_delete (rp); for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo)) { RIP_TIMER_OFF (rinfo->t_timeout); RIP_TIMER_OFF (rinfo->t_garbage_collect); rip_info_free (rinfo); } list_delete (list); rp->info = NULL; route_unlock_node (rp); } /* Cancel RIP related timers. */ RIP_TIMER_OFF (rip->t_update); RIP_TIMER_OFF (rip->t_triggered_update); RIP_TIMER_OFF (rip->t_triggered_interval); /* Cancel read thread. */ if (rip->t_read) { thread_cancel (rip->t_read); rip->t_read = NULL; } /* Close RIP socket. */ if (rip->sock >= 0) { close (rip->sock); rip->sock = -1; } /* Static RIP route configuration. */ for (rp = route_top (rip->route); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* RIP neighbor configuration. */ for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) if (rp->info) { rp->info = NULL; route_unlock_node (rp); } /* Redistribute related clear. */ if (rip->default_information_route_map) free (rip->default_information_route_map); for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (rip->route_map[i].name) free (rip->route_map[i].name); XFREE (MTYPE_ROUTE_TABLE, rip->table); XFREE (MTYPE_ROUTE_TABLE, rip->route); XFREE (MTYPE_ROUTE_TABLE, rip->neighbor); XFREE (MTYPE_RIP, rip); rip = NULL; } rip_clean_network (); rip_passive_nondefault_clean (); rip_offset_clean (); rip_interface_clean (); rip_distance_reset (); rip_redistribute_clean (); } /* Reset all values to the default settings. */ void rip_reset (void) { /* Reset global counters. */ rip_global_route_changes = 0; rip_global_queries = 0; /* Call ripd related reset functions. */ rip_debug_reset (); rip_route_map_reset (); /* Call library reset functions. */ vty_reset (); access_list_reset (); prefix_list_reset (); distribute_list_reset (); rip_interface_reset (); rip_distance_reset (); rip_zclient_reset (); } static void rip_if_rmap_update (struct if_rmap *if_rmap) { struct interface *ifp; struct rip_interface *ri; struct route_map *rmap; ifp = if_lookup_by_name (if_rmap->ifname); if (ifp == NULL) return; ri = ifp->info; if (if_rmap->routemap[IF_RMAP_IN]) { rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]); if (rmap) ri->routemap[IF_RMAP_IN] = rmap; else ri->routemap[IF_RMAP_IN] = NULL; } else ri->routemap[RIP_FILTER_IN] = NULL; if (if_rmap->routemap[IF_RMAP_OUT]) { rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]); if (rmap) ri->routemap[IF_RMAP_OUT] = rmap; else ri->routemap[IF_RMAP_OUT] = NULL; } else ri->routemap[RIP_FILTER_OUT] = NULL; } void rip_if_rmap_update_interface (struct interface *ifp) { struct if_rmap *if_rmap; if_rmap = if_rmap_lookup (ifp->name); if (if_rmap) rip_if_rmap_update (if_rmap); } static void rip_routemap_update_redistribute (void) { int i; if (rip) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (rip->route_map[i].name) rip->route_map[i].map = route_map_lookup_by_name (rip->route_map[i].name); } } } /* ARGSUSED */ static void rip_routemap_update (const char *notused) { struct interface *ifp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) rip_if_rmap_update_interface (ifp); rip_routemap_update_redistribute (); } /* Allocate new rip structure and set default value. */ void rip_init (void) { /* Randomize for triggered update random(). */ srand (time (NULL)); /* Install top nodes. */ install_node (&rip_node, config_write_rip); /* Install rip commands. */ install_element (VIEW_NODE, &show_ip_rip_cmd); install_element (VIEW_NODE, &show_ip_rip_status_cmd); install_element (ENABLE_NODE, &show_ip_rip_cmd); install_element (ENABLE_NODE, &show_ip_rip_status_cmd); install_element (CONFIG_NODE, &router_rip_cmd); install_element (CONFIG_NODE, &no_router_rip_cmd); install_default (RIP_NODE); install_element (RIP_NODE, &rip_version_cmd); install_element (RIP_NODE, &no_rip_version_cmd); install_element (RIP_NODE, &no_rip_version_val_cmd); install_element (RIP_NODE, &rip_default_metric_cmd); install_element (RIP_NODE, &no_rip_default_metric_cmd); install_element (RIP_NODE, &no_rip_default_metric_val_cmd); install_element (RIP_NODE, &rip_timers_cmd); install_element (RIP_NODE, &no_rip_timers_cmd); install_element (RIP_NODE, &no_rip_timers_val_cmd); install_element (RIP_NODE, &rip_route_cmd); install_element (RIP_NODE, &no_rip_route_cmd); install_element (RIP_NODE, &rip_distance_cmd); install_element (RIP_NODE, &no_rip_distance_cmd); install_element (RIP_NODE, &rip_distance_source_cmd); install_element (RIP_NODE, &no_rip_distance_source_cmd); install_element (RIP_NODE, &rip_distance_source_access_list_cmd); install_element (RIP_NODE, &no_rip_distance_source_access_list_cmd); install_element (RIP_NODE, &rip_allow_ecmp_cmd); install_element (RIP_NODE, &no_rip_allow_ecmp_cmd); /* Debug related init. */ rip_debug_init (); /* SNMP init. */ #ifdef HAVE_SNMP rip_snmp_init (); #endif /* HAVE_SNMP */ /* Access list install. */ access_list_init (); access_list_add_hook (rip_distribute_update_all_wrapper); access_list_delete_hook (rip_distribute_update_all_wrapper); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (rip_distribute_update_all); prefix_list_delete_hook (rip_distribute_update_all); /* Distribute list install. */ distribute_list_init (RIP_NODE); distribute_list_add_hook (rip_distribute_update); distribute_list_delete_hook (rip_distribute_update); /* Route-map */ rip_route_map_init (); rip_offset_init (); route_map_add_hook (rip_routemap_update); route_map_delete_hook (rip_routemap_update); if_rmap_init (RIP_NODE); if_rmap_hook_add (rip_if_rmap_update); if_rmap_hook_delete (rip_if_rmap_update); /* Distance control. */ rip_distance_table = route_table_init (); } quagga-0.99.24.1/ripd/rip_interface.h0000644000175000017500000000244412476520570014161 00000000000000/* RIP interface routines * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_RIP_INTERFACE_H #define _QUAGGA_RIP_INTERFACE_H extern int rip_interface_down (int , struct zclient *, zebra_size_t); extern int rip_interface_up (int , struct zclient *, zebra_size_t); extern int rip_interface_add (int , struct zclient *, zebra_size_t); extern int rip_interface_delete (int , struct zclient *, zebra_size_t); extern int rip_interface_address_add (int , struct zclient *, zebra_size_t); extern int rip_interface_address_delete (int , struct zclient *, zebra_size_t); #endif /* _QUAGGA_RIP_INTERFACE_H */ quagga-0.99.24.1/ripd/rip_debug.h0000644000175000017500000000332712476520570013310 00000000000000/* RIP debug routines * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIP_DEBUG_H #define _ZEBRA_RIP_DEBUG_H /* RIP debug event flags. */ #define RIP_DEBUG_EVENT 0x01 /* RIP debug packet flags. */ #define RIP_DEBUG_PACKET 0x01 #define RIP_DEBUG_SEND 0x20 #define RIP_DEBUG_RECV 0x40 #define RIP_DEBUG_DETAIL 0x80 /* RIP debug zebra flags. */ #define RIP_DEBUG_ZEBRA 0x01 /* Debug related macro. */ #define IS_RIP_DEBUG_EVENT (rip_debug_event & RIP_DEBUG_EVENT) #define IS_RIP_DEBUG_PACKET (rip_debug_packet & RIP_DEBUG_PACKET) #define IS_RIP_DEBUG_SEND (rip_debug_packet & RIP_DEBUG_SEND) #define IS_RIP_DEBUG_RECV (rip_debug_packet & RIP_DEBUG_RECV) #define IS_RIP_DEBUG_ZEBRA (rip_debug_zebra & RIP_DEBUG_ZEBRA) extern unsigned long rip_debug_event; extern unsigned long rip_debug_packet; extern unsigned long rip_debug_zebra; extern void rip_debug_init (void); extern void rip_debug_reset (void); #endif /* _ZEBRA_RIP_DEBUG_H */ quagga-0.99.24.1/ripd/ripd.h0000644000175000017500000002732612476520570012313 00000000000000/* RIP related values and structures. * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _ZEBRA_RIP_H #define _ZEBRA_RIP_H /* RIP version number. */ #define RIPv1 1 #define RIPv2 2 /* N.B. stuff will break if (RIPv1 != RI_RIP_VERSION_1) || (RIPv2 != RI_RIP_VERSION_2) */ /* RIP command list. */ #define RIP_REQUEST 1 #define RIP_RESPONSE 2 #define RIP_TRACEON 3 /* Obsolete */ #define RIP_TRACEOFF 4 /* Obsolete */ #define RIP_POLL 5 #define RIP_POLL_ENTRY 6 #define RIP_COMMAND_MAX 7 /* RIP metric infinity value.*/ #define RIP_METRIC_INFINITY 16 /* Normal RIP packet min and max size. */ #define RIP_PACKET_MINSIZ 4 #define RIP_PACKET_MAXSIZ 512 #define RIP_HEADER_SIZE 4 #define RIP_RTE_SIZE 20 /* Max count of routing table entry in one rip packet. */ #define RIP_MAX_RTE ((RIP_PACKET_MAXSIZ - RIP_HEADER_SIZE) / RIP_RTE_SIZE) /* RIP version 2 multicast address. */ #ifndef INADDR_RIP_GROUP #define INADDR_RIP_GROUP 0xe0000009 /* 224.0.0.9 */ #endif /* RIP timers */ #define RIP_UPDATE_TIMER_DEFAULT 30 #define RIP_TIMEOUT_TIMER_DEFAULT 180 #define RIP_GARBAGE_TIMER_DEFAULT 120 /* RIP peer timeout value. */ #define RIP_PEER_TIMER_DEFAULT 180 /* RIP port number. */ #define RIP_PORT_DEFAULT 520 #define RIP_VTY_PORT 2602 /* Default configuration file name. */ #define RIPD_DEFAULT_CONFIG "ripd.conf" /* RIP route types. */ #define RIP_ROUTE_RTE 0 #define RIP_ROUTE_STATIC 1 #define RIP_ROUTE_DEFAULT 2 #define RIP_ROUTE_REDISTRIBUTE 3 #define RIP_ROUTE_INTERFACE 4 /* RIPv2 special RTE family types */ #define RIP_FAMILY_AUTH 0xffff /* RIPv2 authentication types, for RIP_FAMILY_AUTH RTE's */ #define RIP_NO_AUTH 0 #define RIP_AUTH_DATA 1 #define RIP_AUTH_SIMPLE_PASSWORD 2 #define RIP_AUTH_MD5 3 /* RIPv2 Simple authentication */ #define RIP_AUTH_SIMPLE_SIZE 16 /* RIPv2 MD5 authentication. */ #define RIP_AUTH_MD5_SIZE 16 #define RIP_AUTH_MD5_COMPAT_SIZE RIP_RTE_SIZE /* RIP structure. */ struct rip { /* RIP socket. */ int sock; /* Default version of rip instance. */ int version_send; /* version 1 or 2 (but not both) */ int version_recv; /* version 1 or 2 or both */ /* Output buffer of RIP. */ struct stream *obuf; /* RIP routing information base. */ struct route_table *table; /* RIP only static routing information. */ struct route_table *route; /* RIP neighbor. */ struct route_table *neighbor; /* RIP threads. */ struct thread *t_read; /* Update and garbage timer. */ struct thread *t_update; /* Triggered update hack. */ int trigger; struct thread *t_triggered_update; struct thread *t_triggered_interval; /* RIP timer values. */ unsigned long update_time; unsigned long timeout_time; unsigned long garbage_time; /* RIP default metric. */ int default_metric; /* RIP default-information originate. */ u_char default_information; char *default_information_route_map; /* RIP default distance. */ u_char distance; struct route_table *distance_table; /* RIP ECMP flag */ unsigned int ecmp; /* For redistribute route map. */ struct { char *name; struct route_map *map; int metric_config; u_int32_t metric; } route_map[ZEBRA_ROUTE_MAX]; }; /* RIP routing table entry which belong to rip_packet. */ struct rte { u_int16_t family; /* Address family of this route. */ u_int16_t tag; /* Route Tag which included in RIP2 packet. */ struct in_addr prefix; /* Prefix of rip route. */ struct in_addr mask; /* Netmask of rip route. */ struct in_addr nexthop; /* Next hop of rip route. */ u_int32_t metric; /* Metric value of rip route. */ }; /* RIP packet structure. */ struct rip_packet { unsigned char command; /* Command type of RIP packet. */ unsigned char version; /* RIP version which coming from peer. */ unsigned char pad1; /* Padding of RIP packet header. */ unsigned char pad2; /* Same as above. */ struct rte rte[1]; /* Address structure. */ }; /* Buffer to read RIP packet. */ union rip_buf { struct rip_packet rip_packet; char buf[RIP_PACKET_MAXSIZ]; }; /* RIP route information. */ struct rip_info { /* This route's type. */ int type; /* Sub type. */ int sub_type; /* RIP nexthop. */ struct in_addr nexthop; struct in_addr from; /* Which interface does this route come from. */ unsigned int ifindex; /* Metric of this route. */ u_int32_t metric; /* External metric of this route. if learnt from an externalm proto */ u_int32_t external_metric; /* Tag information of this route. */ u_int16_t tag; /* Flags of RIP route. */ #define RIP_RTF_FIB 1 #define RIP_RTF_CHANGED 2 u_char flags; /* Garbage collect timer. */ struct thread *t_timeout; struct thread *t_garbage_collect; /* Route-map futures - this variables can be changed. */ struct in_addr nexthop_out; u_char metric_set; u_int32_t metric_out; u_short tag_out; unsigned int ifindex_out; struct route_node *rp; u_char distance; #ifdef NEW_RIP_TABLE struct rip_info *next; struct rip_info *prev; #endif /* NEW_RIP_TABLE */ }; typedef enum { RIP_NO_SPLIT_HORIZON = 0, RIP_SPLIT_HORIZON, RIP_SPLIT_HORIZON_POISONED_REVERSE } split_horizon_policy_t; /* RIP specific interface configuration. */ struct rip_interface { /* RIP is enabled on this interface. */ int enable_network; int enable_interface; /* RIP is running on this interface. */ int running; /* RIP version control. */ int ri_send; int ri_receive; /* RIPv2 authentication type. */ int auth_type; /* RIPv2 authentication string. */ char *auth_str; /* RIPv2 authentication key chain. */ char *key_chain; /* value to use for md5->auth_len */ u_int8_t md5_auth_len; /* Split horizon flag. */ split_horizon_policy_t split_horizon; split_horizon_policy_t split_horizon_default; /* For filter type slot. */ #define RIP_FILTER_IN 0 #define RIP_FILTER_OUT 1 #define RIP_FILTER_MAX 2 /* Access-list. */ struct access_list *list[RIP_FILTER_MAX]; /* Prefix-list. */ struct prefix_list *prefix[RIP_FILTER_MAX]; /* Route-map. */ struct route_map *routemap[RIP_FILTER_MAX]; /* Wake up thread. */ struct thread *t_wakeup; /* Interface statistics. */ int recv_badpackets; int recv_badroutes; int sent_updates; /* Passive interface. */ int passive; }; /* RIP peer information. */ struct rip_peer { /* Peer address. */ struct in_addr addr; /* Peer RIP tag value. */ int domain; /* Last update time. */ time_t uptime; /* Peer RIP version. */ u_char version; /* Statistics. */ int recv_badpackets; int recv_badroutes; /* Timeout thread. */ struct thread *t_timeout; }; struct rip_md5_info { u_int16_t family; u_int16_t type; u_int16_t packet_len; u_char keyid; u_char auth_len; u_int32_t sequence; u_int32_t reserv1; u_int32_t reserv2; }; struct rip_md5_data { u_int16_t family; u_int16_t type; u_char digest[16]; }; /* RIP accepet/announce methods. */ #define RI_RIP_UNSPEC 0 #define RI_RIP_VERSION_1 1 #define RI_RIP_VERSION_2 2 #define RI_RIP_VERSION_1_AND_2 3 /* N.B. stuff will break if (RIPv1 != RI_RIP_VERSION_1) || (RIPv2 != RI_RIP_VERSION_2) */ /* Default value for "default-metric" command. */ #define RIP_DEFAULT_METRIC_DEFAULT 1 /* RIP event. */ enum rip_event { RIP_READ, RIP_UPDATE_EVENT, RIP_TRIGGERED_UPDATE, }; /* Macro for timer turn on. */ #define RIP_TIMER_ON(T,F,V) \ do { \ if (!(T)) \ (T) = thread_add_timer (master, (F), rinfo, (V)); \ } while (0) /* Macro for timer turn off. */ #define RIP_TIMER_OFF(X) \ do { \ if (X) \ { \ thread_cancel (X); \ (X) = NULL; \ } \ } while (0) /* Prototypes. */ extern void rip_init (void); extern void rip_reset (void); extern void rip_clean (void); extern void rip_clean_network (void); extern void rip_interface_clean (void); extern void rip_interface_reset (void); extern void rip_passive_nondefault_clean (void); extern void rip_if_init (void); extern void rip_if_down_all (void); extern void rip_route_map_init (void); extern void rip_route_map_reset (void); extern void rip_snmp_init (void); extern void rip_zclient_init (void); extern void rip_zclient_start (void); extern void rip_zclient_reset (void); extern void rip_offset_init (void); extern int if_check_address (struct in_addr addr); extern int rip_request_send (struct sockaddr_in *, struct interface *, u_char, struct connected *); extern int rip_neighbor_lookup (struct sockaddr_in *); extern int rip_redistribute_check (int); extern void rip_redistribute_add (int, int, struct prefix_ipv4 *, unsigned int, struct in_addr *, unsigned int, unsigned char); extern void rip_redistribute_delete (int, int, struct prefix_ipv4 *, unsigned int); extern void rip_redistribute_withdraw (int); extern void rip_zebra_ipv4_add (struct route_node *); extern void rip_zebra_ipv4_delete (struct route_node *); extern void rip_interface_multicast_set (int, struct connected *); extern void rip_distribute_update_interface (struct interface *); extern void rip_if_rmap_update_interface (struct interface *); extern int config_write_rip_network (struct vty *, int); extern int config_write_rip_offset_list (struct vty *); extern int config_write_rip_redistribute (struct vty *, int); extern void rip_peer_init (void); extern void rip_peer_update (struct sockaddr_in *, u_char); extern void rip_peer_bad_route (struct sockaddr_in *); extern void rip_peer_bad_packet (struct sockaddr_in *); extern void rip_peer_display (struct vty *); extern struct rip_peer *rip_peer_lookup (struct in_addr *); extern struct rip_peer *rip_peer_lookup_next (struct in_addr *); extern int rip_offset_list_apply_in (struct prefix_ipv4 *, struct interface *, u_int32_t *); extern int rip_offset_list_apply_out (struct prefix_ipv4 *, struct interface *, u_int32_t *); extern void rip_offset_clean (void); extern void rip_info_free (struct rip_info *); extern u_char rip_distance_apply (struct rip_info *); extern void rip_redistribute_clean (void); extern void rip_ifaddr_add (struct interface *, struct connected *); extern void rip_ifaddr_delete (struct interface *, struct connected *); extern struct rip_info *rip_ecmp_add (struct rip_info *); extern struct rip_info *rip_ecmp_replace (struct rip_info *); extern struct rip_info *rip_ecmp_delete (struct rip_info *); /* There is only one rip strucutre. */ extern struct rip *rip; /* Master thread strucutre. */ extern struct thread_master *master; /* RIP statistics for SNMP. */ extern long rip_global_route_changes; extern long rip_global_queries; #endif /* _ZEBRA_RIP_H */ quagga-0.99.24.1/ripd/ripd.conf.sample0000644000175000017500000000062612476520570014263 00000000000000! -*- rip -*- ! ! RIPd sample configuration file ! ! $Id: ripd.conf.sample,v 1.1 2002/12/13 20:15:30 paul Exp $ ! hostname ripd password zebra ! ! debug rip events ! debug rip packet ! router rip ! network 11.0.0.0/8 ! network eth0 ! route 10.0.0.0/8 ! distribute-list private-only in eth0 ! !access-list private-only permit 10.0.0.0/8 !access-list private-only deny any ! !log file ripd.log ! log stdout quagga-0.99.24.1/ripd/Makefile.am0000644000175000017500000000125212476520570013226 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = librip.a sbin_PROGRAMS = ripd librip_a_SOURCES = \ ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ rip_routemap.c rip_peer.c rip_offset.c noinst_HEADERS = \ ripd.h rip_debug.h rip_interface.h ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) ripd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripd.conf.sample EXTRA_DIST = RIPv2-MIB.txt quagga-0.99.24.1/ripd/Makefile.in0000644000175000017500000006047212476521251013245 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = ripd$(EXEEXT) subdir = ripd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = librip_a_AR = $(AR) $(ARFLAGS) librip_a_LIBADD = am_librip_a_OBJECTS = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) librip_a_OBJECTS = $(am_librip_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = ripd.$(OBJEXT) rip_zebra.$(OBJEXT) \ rip_interface.$(OBJEXT) rip_debug.$(OBJEXT) rip_snmp.$(OBJEXT) \ rip_routemap.$(OBJEXT) rip_peer.$(OBJEXT) rip_offset.$(OBJEXT) am_ripd_OBJECTS = rip_main.$(OBJEXT) $(am__objects_1) ripd_OBJECTS = $(am_ripd_OBJECTS) ripd_DEPENDENCIES = ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) DIST_SOURCES = $(librip_a_SOURCES) $(ripd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = librip.a librip_a_SOURCES = \ ripd.c rip_zebra.c rip_interface.c rip_debug.c rip_snmp.c \ rip_routemap.c rip_peer.c rip_offset.c noinst_HEADERS = \ ripd.h rip_debug.h rip_interface.h ripd_SOURCES = \ rip_main.c $(librip_a_SOURCES) ripd_LDADD = ../lib/libzebra.la @LIBCAP@ examplesdir = $(exampledir) dist_examples_DATA = ripd.conf.sample EXTRA_DIST = RIPv2-MIB.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ripd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu ripd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) librip.a: $(librip_a_OBJECTS) $(librip_a_DEPENDENCIES) $(EXTRA_librip_a_DEPENDENCIES) $(AM_V_at)-rm -f librip.a $(AM_V_AR)$(librip_a_AR) librip.a $(librip_a_OBJECTS) $(librip_a_LIBADD) $(AM_V_at)$(RANLIB) librip.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list ripd$(EXEEXT): $(ripd_OBJECTS) $(ripd_DEPENDENCIES) $(EXTRA_ripd_DEPENDENCIES) @rm -f ripd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(ripd_OBJECTS) $(ripd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_interface.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_offset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_peer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_snmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rip_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ripd.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/bgpd/0000755000175000017500000000000012476521355011232 500000000000000quagga-0.99.24.1/bgpd/BGP4-MIB.txt0000644000175000017500000010734012476520570013017 00000000000000 BGP4-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE, IpAddress, Integer32, Counter32, Gauge32, mib-2 FROM SNMPv2-SMI MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP FROM SNMPv2-CONF; bgp MODULE-IDENTITY LAST-UPDATED "9902100000Z" ORGANIZATION "IETF IDR Working Group" CONTACT-INFO "E-mail: idr@merit.net Susan Hares (Editor) Merit Network 4251 Plymouth Road Suite C Ann Arbor, MI 48105-2785 Tel: +1 734 936 2095 Fax: +1 734 647 3185 E-mail: skh@merit.edu Jeff Johnson (Editor) RedBack Networks, Inc. 1389 Moffett Park Drive Sunnyvale, CA 94089-1134 Tel: +1 408 548 3516 Fax: +1 408 548 3599 E-mail: jeff@redback.com" DESCRIPTION "The MIB module for BGP-4." REVISION "9902100000Z" DESCRIPTION "Corrected duplicate OBJECT IDENTIFIER assignment in the conformance information." REVISION "9601080000Z" DESCRIPTION "1) Fixed the definitions of the traps to make them equivalent to their initial definition in RFC 1269. 2) Added compliance and conformance info." ::= { mib-2 15 } bgpVersion OBJECT-TYPE SYNTAX OCTET STRING (SIZE (1..255)) MAX-ACCESS read-only STATUS current DESCRIPTION "Vector of supported BGP protocol version numbers. Each peer negotiates the version from this vector. Versions are identified via the string of bits contained within this object. The first octet contains bits 0 to 7, the second octet contains bits 8 to 15, and so on, with the most significant bit referring to the lowest bit number in the octet (e.g., the MSB of the first octet refers to bit 0). If a bit, i, is present and set, then the version (i+1) of the BGP is supported." ::= { bgp 1 } bgpLocalAs OBJECT-TYPE SYNTAX INTEGER (0..65535) MAX-ACCESS read-only STATUS current DESCRIPTION "The local autonomous system number." ::= { bgp 2 } -- BGP Peer table. This table contains, one entry per BGP -- peer, information about the BGP peer. bgpPeerTable OBJECT-TYPE SYNTAX SEQUENCE OF BgpPeerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "BGP peer table. This table contains, one entry per BGP peer, information about the connections with BGP peers." ::= { bgp 3 } bgpPeerEntry OBJECT-TYPE SYNTAX BgpPeerEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Entry containing information about the connection with a BGP peer." INDEX { bgpPeerRemoteAddr } ::= { bgpPeerTable 1 } BgpPeerEntry ::= SEQUENCE { bgpPeerIdentifier IpAddress, bgpPeerState INTEGER, bgpPeerAdminStatus INTEGER, bgpPeerNegotiatedVersion Integer32, bgpPeerLocalAddr IpAddress, bgpPeerLocalPort INTEGER, bgpPeerRemoteAddr IpAddress, bgpPeerRemotePort INTEGER, bgpPeerRemoteAs INTEGER, bgpPeerInUpdates Counter32, bgpPeerOutUpdates Counter32, bgpPeerInTotalMessages Counter32, bgpPeerOutTotalMessages Counter32, bgpPeerLastError OCTET STRING, bgpPeerFsmEstablishedTransitions Counter32, bgpPeerFsmEstablishedTime Gauge32, bgpPeerConnectRetryInterval INTEGER, bgpPeerHoldTime INTEGER, bgpPeerKeepAlive INTEGER, bgpPeerHoldTimeConfigured INTEGER, bgpPeerKeepAliveConfigured INTEGER, bgpPeerMinASOriginationInterval INTEGER, bgpPeerMinRouteAdvertisementInterval INTEGER, bgpPeerInUpdateElapsedTime Gauge32 } bgpPeerIdentifier OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The BGP Identifier of this entry's BGP peer." ::= { bgpPeerEntry 1 } bgpPeerState OBJECT-TYPE SYNTAX INTEGER { idle(1), connect(2), active(3), opensent(4), openconfirm(5), established(6) } MAX-ACCESS read-only STATUS current DESCRIPTION "The BGP peer connection state." ::= { bgpPeerEntry 2 } bgpPeerAdminStatus OBJECT-TYPE SYNTAX INTEGER { stop(1), start(2) } MAX-ACCESS read-write STATUS current DESCRIPTION "The desired state of the BGP connection. A transition from 'stop' to 'start' will cause the BGP Start Event to be generated. A transition from 'start' to 'stop' will cause the BGP Stop Event to be generated. This parameter can be used to restart BGP peer connections. Care should be used in providing write access to this object without adequate authentication." ::= { bgpPeerEntry 3 } bgpPeerNegotiatedVersion OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS current DESCRIPTION "The negotiated version of BGP running between the two peers." ::= { bgpPeerEntry 4 } bgpPeerLocalAddr OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The local IP address of this entry's BGP connection." ::= { bgpPeerEntry 5 } bgpPeerLocalPort OBJECT-TYPE SYNTAX INTEGER (0..65535) MAX-ACCESS read-only STATUS current DESCRIPTION "The local port for the TCP connection between the BGP peers." ::= { bgpPeerEntry 6 } bgpPeerRemoteAddr OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The remote IP address of this entry's BGP peer." ::= { bgpPeerEntry 7 } bgpPeerRemotePort OBJECT-TYPE SYNTAX INTEGER (0..65535) MAX-ACCESS read-only STATUS current DESCRIPTION "The remote port for the TCP connection between the BGP peers. Note that the objects bgpPeerLocalAddr, bgpPeerLocalPort, bgpPeerRemoteAddr and bgpPeerRemotePort provide the appropriate reference to the standard MIB TCP connection table." ::= { bgpPeerEntry 8 } bgpPeerRemoteAs OBJECT-TYPE SYNTAX INTEGER (0..65535) MAX-ACCESS read-only STATUS current DESCRIPTION "The remote autonomous system number." ::= { bgpPeerEntry 9 } bgpPeerInUpdates OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of BGP UPDATE messages received on this connection. This object should be initialized to zero (0) when the connection is established." ::= { bgpPeerEntry 10 } bgpPeerOutUpdates OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The number of BGP UPDATE messages transmitted on this connection. This object should be initialized to zero (0) when the connection is established." ::= { bgpPeerEntry 11 } bgpPeerInTotalMessages OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of messages received from the remote peer on this connection. This object should be initialized to zero when the connection is established." ::= { bgpPeerEntry 12 } bgpPeerOutTotalMessages OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of messages transmitted to the remote peer on this connection. This object should be initialized to zero when the connection is established." ::= { bgpPeerEntry 13 } bgpPeerLastError OBJECT-TYPE SYNTAX OCTET STRING (SIZE (2)) MAX-ACCESS read-only STATUS current DESCRIPTION "The last error code and subcode seen by this peer on this connection. If no error has occurred, this field is zero. Otherwise, the first byte of this two byte OCTET STRING contains the error code, and the second byte contains the subcode." ::= { bgpPeerEntry 14 } bgpPeerFsmEstablishedTransitions OBJECT-TYPE SYNTAX Counter32 MAX-ACCESS read-only STATUS current DESCRIPTION "The total number of times the BGP FSM transitioned into the established state." ::= { bgpPeerEntry 15 } bgpPeerFsmEstablishedTime OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "This timer indicates how long (in seconds) this peer has been in the Established state or how long since this peer was last in the Established state. It is set to zero when a new peer is configured or the router is booted." ::= { bgpPeerEntry 16 } bgpPeerConnectRetryInterval OBJECT-TYPE SYNTAX INTEGER (1..65535) MAX-ACCESS read-write STATUS current DESCRIPTION "Time interval in seconds for the ConnectRetry timer. The suggested value for this timer is 120 seconds." ::= { bgpPeerEntry 17 } bgpPeerHoldTime OBJECT-TYPE SYNTAX INTEGER ( 0 | 3..65535 ) MAX-ACCESS read-only STATUS current DESCRIPTION "Time interval in seconds for the Hold Timer established with the peer. The value of this object is calculated by this BGP speaker by using the smaller of the value in bgpPeerHoldTimeConfigured and the Hold Time received in the OPEN message. This value must be at lease three seconds if it is not zero (0) in which case the Hold Timer has not been established with the peer, or, the value of bgpPeerHoldTimeConfigured is zero (0)." ::= { bgpPeerEntry 18 } bgpPeerKeepAlive OBJECT-TYPE SYNTAX INTEGER ( 0 | 1..21845 ) MAX-ACCESS read-only STATUS current DESCRIPTION "Time interval in seconds for the KeepAlive timer established with the peer. The value of this object is calculated by this BGP speaker such that, when compared with bgpPeerHoldTime, it has the same proportion as what bgpPeerKeepAliveConfigured has when compared with bgpPeerHoldTimeConfigured. If the value of this object is zero (0), it indicates that the KeepAlive timer has not been established with the peer, or, the value of bgpPeerKeepAliveConfigured is zero (0)." ::= { bgpPeerEntry 19 } bgpPeerHoldTimeConfigured OBJECT-TYPE SYNTAX INTEGER ( 0 | 3..65535 ) MAX-ACCESS read-write STATUS current DESCRIPTION "Time interval in seconds for the Hold Time configured for this BGP speaker with this peer. This value is placed in an OPEN message sent to this peer by this BGP speaker, and is compared with the Hold Time field in an OPEN message received from the peer when determining the Hold Time (bgpPeerHoldTime) with the peer. This value must not be less than three seconds if it is not zero (0) in which case the Hold Time is NOT to be established with the peer. The suggested value for this timer is 90 seconds." ::= { bgpPeerEntry 20 } bgpPeerKeepAliveConfigured OBJECT-TYPE SYNTAX INTEGER ( 0 | 1..21845 ) MAX-ACCESS read-write STATUS current DESCRIPTION "Time interval in seconds for the KeepAlive timer configured for this BGP speaker with this peer. The value of this object will only determine the KEEPALIVE messages' frequency relative to the value specified in bgpPeerHoldTimeConfigured; the actual time interval for the KEEPALIVE messages is indicated by bgpPeerKeepAlive. A reasonable maximum value for this timer would be configured to be one third of that of bgpPeerHoldTimeConfigured. If the value of this object is zero (0), no periodical KEEPALIVE messages are sent to the peer after the BGP connection has been established. The suggested value for this timer is 30 seconds." ::= { bgpPeerEntry 21 } bgpPeerMinASOriginationInterval OBJECT-TYPE SYNTAX INTEGER (1..65535) MAX-ACCESS read-write STATUS current DESCRIPTION "Time interval in seconds for the MinASOriginationInterval timer. The suggested value for this timer is 15 seconds." ::= { bgpPeerEntry 22 } bgpPeerMinRouteAdvertisementInterval OBJECT-TYPE SYNTAX INTEGER (1..65535) MAX-ACCESS read-write STATUS current DESCRIPTION "Time interval in seconds for the MinRouteAdvertisementInterval timer. The suggested value for this timer is 30 seconds." ::= { bgpPeerEntry 23 } bgpPeerInUpdateElapsedTime OBJECT-TYPE SYNTAX Gauge32 MAX-ACCESS read-only STATUS current DESCRIPTION "Elapsed time in seconds since the last BGP UPDATE message was received from the peer. Each time bgpPeerInUpdates is incremented, the value of this object is set to zero (0)." ::= { bgpPeerEntry 24 } bgpIdentifier OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The BGP Identifier of local system." ::= { bgp 4 } -- Received Path Attribute Table. This table contains, -- one entry per path to a network, path attributes -- received from all peers running BGP version 3 or less. -- This table is obsolete, having been replaced in -- functionality with the bgp4PathAttrTable. bgpRcvdPathAttrTable OBJECT-TYPE SYNTAX SEQUENCE OF BgpPathAttrEntry MAX-ACCESS not-accessible STATUS obsolete DESCRIPTION "The BGP Received Path Attribute Table contains information about paths to destination networks received from all peers running BGP version 3 or less." ::= { bgp 5 } bgpPathAttrEntry OBJECT-TYPE SYNTAX BgpPathAttrEntry MAX-ACCESS not-accessible STATUS obsolete DESCRIPTION "Information about a path to a network." INDEX { bgpPathAttrDestNetwork, bgpPathAttrPeer } ::= { bgpRcvdPathAttrTable 1 } BgpPathAttrEntry ::= SEQUENCE { bgpPathAttrPeer IpAddress, bgpPathAttrDestNetwork IpAddress, bgpPathAttrOrigin INTEGER, bgpPathAttrASPath OCTET STRING, bgpPathAttrNextHop IpAddress, bgpPathAttrInterASMetric Integer32 } bgpPathAttrPeer OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The IP address of the peer where the path information was learned." ::= { bgpPathAttrEntry 1 } bgpPathAttrDestNetwork OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The address of the destination network." ::= { bgpPathAttrEntry 2 } bgpPathAttrOrigin OBJECT-TYPE SYNTAX INTEGER { igp(1),-- networks are interior egp(2),-- networks learned via EGP incomplete(3) -- undetermined } MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The ultimate origin of the path information." ::= { bgpPathAttrEntry 3 } bgpPathAttrASPath OBJECT-TYPE SYNTAX OCTET STRING (SIZE (2..255)) MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The set of ASs that must be traversed to reach the network. This object is probably best represented as SEQUENCE OF INTEGER. For SMI compatibility, though, it is represented as OCTET STRING. Each AS is represented as a pair of octets according to the following algorithm: first-byte-of-pair = ASNumber / 256; second-byte-of-pair = ASNumber & 255;" ::= { bgpPathAttrEntry 4 } bgpPathAttrNextHop OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The address of the border router that should be used for the destination network." ::= { bgpPathAttrEntry 5 } bgpPathAttrInterASMetric OBJECT-TYPE SYNTAX Integer32 MAX-ACCESS read-only STATUS obsolete DESCRIPTION "The optional inter-AS metric. If this attribute has not been provided for this route, the value for this object is 0." ::= { bgpPathAttrEntry 6 } -- BGP-4 Received Path Attribute Table. This table contains, -- one entry per path to a network, path attributes -- received from all peers running BGP-4. bgp4PathAttrTable OBJECT-TYPE SYNTAX SEQUENCE OF Bgp4PathAttrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The BGP-4 Received Path Attribute Table contains information about paths to destination networks received from all BGP4 peers." ::= { bgp 6 } bgp4PathAttrEntry OBJECT-TYPE SYNTAX Bgp4PathAttrEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "Information about a path to a network." INDEX { bgp4PathAttrIpAddrPrefix, bgp4PathAttrIpAddrPrefixLen, bgp4PathAttrPeer } ::= { bgp4PathAttrTable 1 } Bgp4PathAttrEntry ::= SEQUENCE { bgp4PathAttrPeer IpAddress, bgp4PathAttrIpAddrPrefixLen INTEGER, bgp4PathAttrIpAddrPrefix IpAddress, bgp4PathAttrOrigin INTEGER, bgp4PathAttrASPathSegment OCTET STRING, bgp4PathAttrNextHop IpAddress, bgp4PathAttrMultiExitDisc INTEGER, bgp4PathAttrLocalPref INTEGER, bgp4PathAttrAtomicAggregate INTEGER, bgp4PathAttrAggregatorAS INTEGER, bgp4PathAttrAggregatorAddr IpAddress, bgp4PathAttrCalcLocalPref INTEGER, bgp4PathAttrBest INTEGER, bgp4PathAttrUnknown OCTET STRING } bgp4PathAttrPeer OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address of the peer where the path information was learned." ::= { bgp4PathAttrEntry 1 } bgp4PathAttrIpAddrPrefixLen OBJECT-TYPE SYNTAX INTEGER (0..32) MAX-ACCESS read-only STATUS current DESCRIPTION "Length in bits of the IP address prefix in the Network Layer Reachability Information field." ::= { bgp4PathAttrEntry 2 } bgp4PathAttrIpAddrPrefix OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "An IP address prefix in the Network Layer Reachability Information field. This object is an IP address containing the prefix with length specified by bgp4PathAttrIpAddrPrefixLen. Any bits beyond the length specified by bgp4PathAttrIpAddrPrefixLen are zeroed." ::= { bgp4PathAttrEntry 3 } bgp4PathAttrOrigin OBJECT-TYPE SYNTAX INTEGER { igp(1),-- networks are interior egp(2),-- networks learned via EGP incomplete(3) -- undetermined } MAX-ACCESS read-only STATUS current DESCRIPTION "The ultimate origin of the path information." ::= { bgp4PathAttrEntry 4 } bgp4PathAttrASPathSegment OBJECT-TYPE SYNTAX OCTET STRING (SIZE (2..255)) MAX-ACCESS read-only STATUS current DESCRIPTION "The sequence of AS path segments. Each AS path segment is represented by a triple . The type is a 1-octet field which has two possible values: 1 AS_SET: unordered set of ASs a route in the UPDATE message has traversed 2 AS_SEQUENCE: ordered set of ASs a route in the UPDATE message has traversed. The length is a 1-octet field containing the number of ASs in the value field. The value field contains one or more AS numbers, each AS is represented in the octet string as a pair of octets according to the following algorithm: first-byte-of-pair = ASNumber / 256; second-byte-of-pair = ASNumber & 255;" ::= { bgp4PathAttrEntry 5 } bgp4PathAttrNextHop OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The address of the border router that should be used for the destination network." ::= { bgp4PathAttrEntry 6 } bgp4PathAttrMultiExitDisc OBJECT-TYPE SYNTAX INTEGER (-1..2147483647) MAX-ACCESS read-only STATUS current DESCRIPTION "This metric is used to discriminate between multiple exit points to an adjacent autonomous system. A value of -1 indicates the absence of this attribute." ::= { bgp4PathAttrEntry 7 } bgp4PathAttrLocalPref OBJECT-TYPE SYNTAX INTEGER (-1..2147483647) MAX-ACCESS read-only STATUS current DESCRIPTION "The originating BGP4 speaker's degree of preference for an advertised route. A value of -1 indicates the absence of this attribute." ::= { bgp4PathAttrEntry 8 } bgp4PathAttrAtomicAggregate OBJECT-TYPE SYNTAX INTEGER { lessSpecificRrouteNotSelected(1), lessSpecificRouteSelected(2) } MAX-ACCESS read-only STATUS current DESCRIPTION "Whether or not a system has selected a less specific route without selecting a more specific route." ::= { bgp4PathAttrEntry 9 } bgp4PathAttrAggregatorAS OBJECT-TYPE SYNTAX INTEGER (0..65535) MAX-ACCESS read-only STATUS current DESCRIPTION "The AS number of the last BGP4 speaker that performed route aggregation. A value of zero (0) indicates the absence of this attribute." ::= { bgp4PathAttrEntry 10 } bgp4PathAttrAggregatorAddr OBJECT-TYPE SYNTAX IpAddress MAX-ACCESS read-only STATUS current DESCRIPTION "The IP address of the last BGP4 speaker that performed route aggregation. A value of 0.0.0.0 indicates the absence of this attribute." ::= { bgp4PathAttrEntry 11 } bgp4PathAttrCalcLocalPref OBJECT-TYPE SYNTAX INTEGER (-1..2147483647) MAX-ACCESS read-only STATUS current DESCRIPTION "The degree of preference calculated by the receiving BGP4 speaker for an advertised route. A value of -1 indicates the absence of this attribute." ::= { bgp4PathAttrEntry 12 } bgp4PathAttrBest OBJECT-TYPE SYNTAX INTEGER { false(1),-- not chosen as best route true(2) -- chosen as best route } MAX-ACCESS read-only STATUS current DESCRIPTION "An indication of whether or not this route was chosen as the best BGP4 route." ::= { bgp4PathAttrEntry 13 } bgp4PathAttrUnknown OBJECT-TYPE SYNTAX OCTET STRING (SIZE(0..255)) MAX-ACCESS read-only STATUS current DESCRIPTION "One or more path attributes not understood by this BGP4 speaker. Size zero (0) indicates the absence of such attribute(s). Octets beyond the maximum size, if any, are not recorded by this object." ::= { bgp4PathAttrEntry 14 } -- Traps. -- note that in RFC 1657, bgpTraps was incorrectly -- assigned a value of { bgp 7 }, and each of the -- traps had the bgpPeerRemoteAddr object inappropriately -- removed from their OBJECTS clause. The following -- definitions restore the semantics of the traps as -- they were initially defined in RFC 1269. -- { bgp 7 } is unused bgpTraps OBJECT IDENTIFIER ::= { bgp 0 } bgpEstablished NOTIFICATION-TYPE OBJECTS { bgpPeerRemoteAddr, bgpPeerLastError, bgpPeerState } STATUS current DESCRIPTION "The BGP Established event is generated when the BGP FSM enters the ESTABLISHED state." ::= { bgpTraps 1 } bgpBackwardTransition NOTIFICATION-TYPE OBJECTS { bgpPeerRemoteAddr, bgpPeerLastError, bgpPeerState } STATUS current DESCRIPTION "The BGPBackwardTransition Event is generated when the BGP FSM moves from a higher numbered state to a lower numbered state." ::= { bgpTraps 2 } -- conformance information bgpMIBConformance OBJECT IDENTIFIER ::= { bgp 8 } bgpMIBCompliances OBJECT IDENTIFIER ::= { bgpMIBConformance 1 } bgpMIBGroups OBJECT IDENTIFIER ::= { bgpMIBConformance 2 } -- compliance statements bgpMIBCompliance MODULE-COMPLIANCE STATUS current DESCRIPTION "The compliance statement for entities which implement the BGP4 mib." MODULE -- this module MANDATORY-GROUPS { bgp4MIBGlobalsGroup, bgp4MIBPeerGroup, bgp4MIBPathAttrGroup, bgp4MIBNotificationGroup } ::= { bgpMIBCompliances 1 } -- units of conformance bgp4MIBGlobalsGroup OBJECT-GROUP OBJECTS { bgpVersion, bgpLocalAs, bgpIdentifier } STATUS current DESCRIPTION "A collection of objects providing information on global BGP state." ::= { bgpMIBGroups 1 } bgp4MIBPeerGroup OBJECT-GROUP OBJECTS { bgpPeerIdentifier, bgpPeerState, bgpPeerAdminStatus, bgpPeerNegotiatedVersion, bgpPeerLocalAddr, bgpPeerLocalPort, bgpPeerRemoteAddr, bgpPeerRemotePort, bgpPeerRemoteAs, bgpPeerInUpdates, bgpPeerOutUpdates, bgpPeerInTotalMessages, bgpPeerOutTotalMessages, bgpPeerLastError, bgpPeerFsmEstablishedTransitions, bgpPeerFsmEstablishedTime, bgpPeerConnectRetryInterval, bgpPeerHoldTime, bgpPeerKeepAlive, bgpPeerHoldTimeConfigured, bgpPeerKeepAliveConfigured, bgpPeerMinASOriginationInterval, bgpPeerMinRouteAdvertisementInterval, bgpPeerInUpdateElapsedTime } STATUS current DESCRIPTION "A collection of objects for managing BGP peers." ::= { bgpMIBGroups 2 } bgp4MIBRcvdPathAttrGroup OBJECT-GROUP OBJECTS { bgpPathAttrPeer, bgpPathAttrDestNetwork, bgpPathAttrOrigin, bgpPathAttrASPath, bgpPathAttrNextHop, bgpPathAttrInterASMetric } STATUS obsolete DESCRIPTION "A collection of objects for managing BGP path entries. This conformance group is obsolete, replaced by bgp4MIBPathAttrGroup." ::= { bgpMIBGroups 3 } bgp4MIBPathAttrGroup OBJECT-GROUP OBJECTS { bgp4PathAttrPeer, bgp4PathAttrIpAddrPrefixLen, bgp4PathAttrIpAddrPrefix, bgp4PathAttrOrigin, bgp4PathAttrASPathSegment, bgp4PathAttrNextHop, bgp4PathAttrMultiExitDisc, bgp4PathAttrLocalPref, bgp4PathAttrAtomicAggregate, bgp4PathAttrAggregatorAS, bgp4PathAttrAggregatorAddr, bgp4PathAttrCalcLocalPref, bgp4PathAttrBest, bgp4PathAttrUnknown } STATUS current DESCRIPTION "A collection of objects for managing BGP path entries." ::= { bgpMIBGroups 4 } bgp4MIBNotificationGroup NOTIFICATION-GROUP NOTIFICATIONS { bgpEstablished, bgpBackwardTransition } STATUS current DESCRIPTION "A collection of notifications for signaling changes in BGP peer relationships." ::= { bgpMIBGroups 5 } END quagga-0.99.24.1/bgpd/bgp_main.c0000644000175000017500000002537012476520570013077 00000000000000/* Main routine of bgpd. Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "vector.h" #include "vty.h" #include "command.h" #include "getopt.h" #include "thread.h" #include #include "memory.h" #include "prefix.h" #include "log.h" #include "privs.h" #include "sigevent.h" #include "zclient.h" #include "routemap.h" #include "filter.h" #include "plist.h" #include "stream.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_zebra.h" /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "bgp_port", required_argument, NULL, 'p'}, { "listenon", required_argument, NULL, 'l'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "no_kernel", no_argument, NULL, 'n'}, { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { "dryrun", no_argument, NULL, 'C'}, { "help", no_argument, NULL, 'h'}, { 0 } }; /* signal definitions */ void sighup (void); void sigint (void); void sigusr1 (void); static void bgp_exit (int); static struct quagga_signal_t bgp_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Configuration file and directory. */ char config_default[] = SYSCONFDIR BGP_DEFAULT_CONFIG; /* Route retain mode flag. */ static int retain_mode = 0; /* Master of threads. */ struct thread_master *master; /* Manually specified configuration file name. */ char *config_file = NULL; /* Process ID saved for use by init system */ static const char *pid_file = PATH_BGPD_PID; /* VTY port number and address. */ int vty_port = BGP_VTY_PORT; char *vty_addr = NULL; /* privileges */ static zebra_capabilities_t _caps_p [] = { ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, }; struct zebra_privs_t bgpd_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0, }; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\n\ Daemon which manages kernel routing table management and \ redistribution between different routing protocols.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ -z, --socket Set path of zebra socket\n\ -p, --bgp_port Set bgp protocol's port number\n\ -l, --listenon Listen on specified address (implies -n)\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -r, --retain When program terminates, retain added route by bgpd.\n\ -n, --no_kernel Do not install route to kernel.\n\ -u, --user User to run as\n\ -g, --group Group to run as\n\ -v, --version Print program version\n\ -C, --dryrun Check configuration for validity and exit\n\ -h, --help Display this help and exit\n\ \n\ Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ void sighup (void) { zlog (NULL, LOG_INFO, "SIGHUP received"); /* Terminate all thread. */ bgp_terminate (); bgp_reset (); zlog_info ("bgpd restarting!"); /* Reload config file. */ vty_read_config (config_file, config_default); /* Create VTY's socket */ vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); /* Try to return to normal operation. */ } /* SIGINT handler. */ void sigint (void) { zlog_notice ("Terminating on signal"); if (! retain_mode) bgp_terminate (); zprivs_terminate (&bgpd_privs); bgp_exit (0); } /* SIGUSR1 handler. */ void sigusr1 (void) { zlog_rotate (NULL); } /* Try to free up allocations we know about so that diagnostic tools such as valgrind are able to better illuminate leaks. Zebra route removal and protocol teardown are not meant to be done here. For example, "retain_mode" may be set. */ static void bgp_exit (int status) { struct bgp *bgp; struct listnode *node, *nnode; int *socket; struct interface *ifp; extern struct zclient *zclient; extern struct zclient *zlookup; /* it only makes sense for this to be called on a clean exit */ assert (status == 0); /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) bgp_delete (bgp); list_free (bm->bgp); /* reverse bgp_master_init */ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, socket)) { if (close ((int)(long)socket) == -1) zlog_err ("close (%d): %s", (int)(long)socket, safe_strerror (errno)); } list_delete (bm->listen_sockets); /* reverse bgp_zebra_init/if_init */ if (retain_mode) if_add_hook (IF_DELETE_HOOK, NULL); for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { struct listnode *c_node, *c_nnode; struct connected *c; for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c)) bgp_connected_delete (c); if_delete (ifp); } list_free (iflist); /* reverse bgp_attr_init */ bgp_attr_finish (); /* reverse bgp_dump_init */ bgp_dump_finish (); /* reverse bgp_route_init */ bgp_route_finish (); /* reverse bgp_route_map_init/route_map_init */ route_map_finish (); /* reverse bgp_scan_init */ bgp_scan_finish (); /* reverse access_list_init */ access_list_add_hook (NULL); access_list_delete_hook (NULL); access_list_reset (); /* reverse bgp_filter_init */ as_list_add_hook (NULL); as_list_delete_hook (NULL); bgp_filter_reset (); /* reverse prefix_list_init */ prefix_list_add_hook (NULL); prefix_list_delete_hook (NULL); prefix_list_reset (); /* reverse community_list_init */ community_list_terminate (bgp_clist); cmd_terminate (); vty_terminate (); if (zclient) zclient_free (zclient); if (zlookup) zclient_free (zlookup); if (bgp_nexthop_buf) stream_free (bgp_nexthop_buf); /* reverse bgp_master_init */ if (master) thread_master_free (master); if (zlog_default) closezlog (zlog_default); if (CONF_BGP_DEBUG (normal, NORMAL)) log_memstats_stderr ("bgpd"); exit (status); } /* Main routine of bgpd. Treatment of argument and start bgp finite state machine is handled at here. */ int main (int argc, char **argv) { char *p; int opt; int daemon_mode = 0; int dryrun = 0; char *progname; struct thread thread; int tmp_port; /* Set umask before anything for security */ umask (0027); /* Preserve name of myself. */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_BGP, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); /* BGP master init. */ bgp_master_init (); /* Command line argument treatment. */ while (1) { opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0); if (opt == EOF) break; switch (opt) { case 0: break; case 'd': daemon_mode = 1; break; case 'f': config_file = optarg; break; case 'i': pid_file = optarg; break; case 'z': zclient_serv_path_set (optarg); break; case 'p': tmp_port = atoi (optarg); if (tmp_port <= 0 || tmp_port > 0xffff) bm->port = BGP_PORT_DEFAULT; else bm->port = tmp_port; break; case 'A': vty_addr = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and bgpd not listening on bgp port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = BGP_VTY_PORT; break; case 'r': retain_mode = 1; break; case 'l': bm->address = optarg; /* listenon implies -n */ case 'n': bgp_option_set (BGP_OPT_NO_FIB); break; case 'u': bgpd_privs.user = optarg; break; case 'g': bgpd_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'C': dryrun = 1; break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Make thread master. */ master = bm->master; /* Initializations. */ srand (time (NULL)); signal_init (master, array_size(bgp_signals), bgp_signals); zprivs_init (&bgpd_privs); cmd_init (1); vty_init (master); memory_init (); /* BGP related initialization. */ bgp_init (); /* Parse config file. */ vty_read_config (config_file, config_default); /* Start execution only if not in dry-run mode */ if(dryrun) return(0); /* Turn into daemon if daemon_mode is set. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("BGPd daemon failed: %s", strerror(errno)); return (1); } /* Process ID file creation. */ pid_output (pid_file); /* Make bgp vty socket. */ vty_serv_sock (vty_addr, vty_port, BGP_VTYSH_PATH); /* Print banner. */ zlog_notice ("BGPd %s starting: vty@%d, bgp@%s:%d", QUAGGA_VERSION, vty_port, (bm->address ? bm->address : ""), bm->port); /* Start finite state machine, here we go! */ while (thread_fetch (master, &thread)) thread_call (&thread); /* Not reached. */ return (0); } quagga-0.99.24.1/bgpd/bgp_mpath.c0000644000175000017500000004731412476520570013266 00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "linklist.h" #include "sockunion.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_mpath.h" /* * bgp_maximum_paths_set * * Record maximum-paths configuration for BGP instance */ int bgp_maximum_paths_set (struct bgp *bgp, afi_t afi, safi_t safi, int peertype, u_int16_t maxpaths) { if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) return -1; switch (peertype) { case BGP_PEER_IBGP: bgp->maxpaths[afi][safi].maxpaths_ibgp = maxpaths; break; case BGP_PEER_EBGP: bgp->maxpaths[afi][safi].maxpaths_ebgp = maxpaths; break; default: return -1; } return 0; } /* * bgp_maximum_paths_unset * * Remove maximum-paths configuration from BGP instance */ int bgp_maximum_paths_unset (struct bgp *bgp, afi_t afi, safi_t safi, int peertype) { if (!bgp || (afi >= AFI_MAX) || (safi >= SAFI_MAX)) return -1; switch (peertype) { case BGP_PEER_IBGP: bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; break; case BGP_PEER_EBGP: bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; break; default: return -1; } return 0; } /* * bgp_info_nexthop_cmp * * Compare the nexthops of two paths. Return value is less than, equal to, * or greater than zero if bi1 is respectively less than, equal to, * or greater than bi2. */ static int bgp_info_nexthop_cmp (struct bgp_info *bi1, struct bgp_info *bi2) { struct attr_extra *ae1, *ae2; int compare; ae1 = bi1->attr->extra; ae2 = bi2->attr->extra; compare = IPV4_ADDR_CMP (&bi1->attr->nexthop, &bi2->attr->nexthop); if (!compare && ae1 && ae2 && (ae1->mp_nexthop_len == ae2->mp_nexthop_len)) { switch (ae1->mp_nexthop_len) { case 4: case 12: compare = IPV4_ADDR_CMP (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in); break; #ifdef HAVE_IPV6 case 16: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); break; case 32: compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global); if (!compare) compare = IPV6_ADDR_CMP (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local); break; #endif /* HAVE_IPV6 */ } } return compare; } /* * bgp_info_mpath_cmp * * This function determines our multipath list ordering. By ordering * the list we can deterministically select which paths are included * in the multipath set. The ordering also helps in detecting changes * in the multipath selection so we can detect whether to send an * update to zebra. * * The order of paths is determined first by received nexthop, and then * by peer address if the nexthops are the same. */ static int bgp_info_mpath_cmp (void *val1, void *val2) { struct bgp_info *bi1, *bi2; int compare; bi1 = val1; bi2 = val2; compare = bgp_info_nexthop_cmp (bi1, bi2); if (!compare) compare = sockunion_cmp (bi1->peer->su_remote, bi2->peer->su_remote); return compare; } /* * bgp_mp_list_init * * Initialize the mp_list, which holds the list of multipaths * selected by bgp_best_selection */ void bgp_mp_list_init (struct list *mp_list) { assert (mp_list); memset (mp_list, 0, sizeof (struct list)); mp_list->cmp = bgp_info_mpath_cmp; } /* * bgp_mp_list_clear * * Clears all entries out of the mp_list */ void bgp_mp_list_clear (struct list *mp_list) { assert (mp_list); list_delete_all_node (mp_list); } /* * bgp_mp_list_add * * Adds a multipath entry to the mp_list */ void bgp_mp_list_add (struct list *mp_list, struct bgp_info *mpinfo) { assert (mp_list && mpinfo); listnode_add_sort (mp_list, mpinfo); } /* * bgp_info_mpath_new * * Allocate and zero memory for a new bgp_info_mpath element */ static struct bgp_info_mpath * bgp_info_mpath_new (void) { struct bgp_info_mpath *new_mpath; new_mpath = XCALLOC (MTYPE_BGP_MPATH_INFO, sizeof (struct bgp_info_mpath)); return new_mpath; } /* * bgp_info_mpath_free * * Release resources for a bgp_info_mpath element and zero out pointer */ void bgp_info_mpath_free (struct bgp_info_mpath **mpath) { if (mpath && *mpath) { if ((*mpath)->mp_attr) bgp_attr_unintern (&(*mpath)->mp_attr); XFREE (MTYPE_BGP_MPATH_INFO, *mpath); *mpath = NULL; } } /* * bgp_info_mpath_get * * Fetch the mpath element for the given bgp_info. Used for * doing lazy allocation. */ static struct bgp_info_mpath * bgp_info_mpath_get (struct bgp_info *binfo) { struct bgp_info_mpath *mpath; if (!binfo->mpath) { mpath = bgp_info_mpath_new(); if (!mpath) return NULL; binfo->mpath = mpath; mpath->mp_info = binfo; } return binfo->mpath; } /* * bgp_info_mpath_enqueue * * Enqueue a path onto the multipath list given the previous multipath * list entry */ static void bgp_info_mpath_enqueue (struct bgp_info *prev_info, struct bgp_info *binfo) { struct bgp_info_mpath *prev, *mpath; prev = bgp_info_mpath_get (prev_info); mpath = bgp_info_mpath_get (binfo); if (!prev || !mpath) return; mpath->mp_next = prev->mp_next; mpath->mp_prev = prev; if (prev->mp_next) prev->mp_next->mp_prev = mpath; prev->mp_next = mpath; SET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); } /* * bgp_info_mpath_dequeue * * Remove a path from the multipath list */ void bgp_info_mpath_dequeue (struct bgp_info *binfo) { struct bgp_info_mpath *mpath = binfo->mpath; if (!mpath) return; if (mpath->mp_prev) mpath->mp_prev->mp_next = mpath->mp_next; if (mpath->mp_next) mpath->mp_next->mp_prev = mpath->mp_prev; mpath->mp_next = mpath->mp_prev = NULL; UNSET_FLAG (binfo->flags, BGP_INFO_MULTIPATH); } /* * bgp_info_mpath_next * * Given a bgp_info, return the next multipath entry */ struct bgp_info * bgp_info_mpath_next (struct bgp_info *binfo) { if (!binfo->mpath || !binfo->mpath->mp_next) return NULL; return binfo->mpath->mp_next->mp_info; } /* * bgp_info_mpath_first * * Given bestpath bgp_info, return the first multipath entry. */ struct bgp_info * bgp_info_mpath_first (struct bgp_info *binfo) { return bgp_info_mpath_next (binfo); } /* * bgp_info_mpath_count * * Given the bestpath bgp_info, return the number of multipath entries */ u_int32_t bgp_info_mpath_count (struct bgp_info *binfo) { if (!binfo->mpath) return 0; return binfo->mpath->mp_count; } /* * bgp_info_mpath_count_set * * Sets the count of multipaths into bestpath's mpath element */ static void bgp_info_mpath_count_set (struct bgp_info *binfo, u_int32_t count) { struct bgp_info_mpath *mpath; if (!count && !binfo->mpath) return; mpath = bgp_info_mpath_get (binfo); if (!mpath) return; mpath->mp_count = count; } /* * bgp_info_mpath_attr * * Given bestpath bgp_info, return aggregated attribute set used * for advertising the multipath route */ struct attr * bgp_info_mpath_attr (struct bgp_info *binfo) { if (!binfo->mpath) return NULL; return binfo->mpath->mp_attr; } /* * bgp_info_mpath_attr_set * * Sets the aggregated attribute into bestpath's mpath element */ static void bgp_info_mpath_attr_set (struct bgp_info *binfo, struct attr *attr) { struct bgp_info_mpath *mpath; if (!attr && !binfo->mpath) return; mpath = bgp_info_mpath_get (binfo); if (!mpath) return; mpath->mp_attr = attr; } /* * bgp_info_mpath_update * * Compare and sync up the multipath list with the mp_list generated by * bgp_best_selection */ void bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, struct bgp_info *old_best, struct list *mp_list, struct bgp_maxpaths_cfg *mpath_cfg) { u_int16_t maxpaths, mpath_count, old_mpath_count; struct listnode *mp_node, *mp_next_node; struct bgp_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; int mpath_changed, debug; char pfx_buf[INET_ADDRSTRLEN], nh_buf[2][INET_ADDRSTRLEN]; mpath_changed = 0; maxpaths = BGP_DEFAULT_MAXPATHS; mpath_count = 0; cur_mpath = NULL; old_mpath_count = 0; prev_mpath = new_best; mp_node = listhead (mp_list); debug = BGP_DEBUG (events, EVENTS); if (debug) prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf)); if (new_best) { mpath_count++; if (new_best != old_best) bgp_info_mpath_dequeue (new_best); maxpaths = (new_best->peer->sort == BGP_PEER_IBGP) ? mpath_cfg->maxpaths_ibgp : mpath_cfg->maxpaths_ebgp; } if (old_best) { cur_mpath = bgp_info_mpath_first (old_best); old_mpath_count = bgp_info_mpath_count (old_best); bgp_info_mpath_count_set (old_best, 0); bgp_info_mpath_dequeue (old_best); } /* * We perform an ordered walk through both lists in parallel. * The reason for the ordered walk is that if there are paths * that were previously multipaths and are still multipaths, the walk * should encounter them in both lists at the same time. Otherwise * there will be paths that are in one list or another, and we * will deal with these separately. * * Note that new_best might be somewhere in the mp_list, so we need * to skip over it */ while (mp_node || cur_mpath) { /* * We can bail out of this loop if all existing paths on the * multipath list have been visited (for cleanup purposes) and * the maxpath requirement is fulfulled */ if (!cur_mpath && (mpath_count >= maxpaths)) break; mp_next_node = mp_node ? listnextnode (mp_node) : NULL; next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; /* * If equal, the path was a multipath and is still a multipath. * Insert onto new multipath list if maxpaths allows. */ if (mp_node && (listgetdata (mp_node) == cur_mpath)) { list_delete_node (mp_list, mp_node); bgp_info_mpath_dequeue (cur_mpath); if ((mpath_count < maxpaths) && bgp_info_nexthop_cmp (prev_mpath, cur_mpath)) { bgp_info_mpath_enqueue (prev_mpath, cur_mpath); prev_mpath = cur_mpath; mpath_count++; } else { mpath_changed = 1; if (debug) zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (cur_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); } mp_node = mp_next_node; cur_mpath = next_mpath; continue; } if (cur_mpath && (!mp_node || (bgp_info_mpath_cmp (cur_mpath, listgetdata (mp_node)) < 0))) { /* * If here, we have an old multipath and either the mp_list * is finished or the next mp_node points to a later * multipath, so we need to purge this path from the * multipath list */ bgp_info_mpath_dequeue (cur_mpath); mpath_changed = 1; if (debug) zlog_debug ("%s remove mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (cur_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); cur_mpath = next_mpath; } else { /* * If here, we have a path on the mp_list that was not previously * a multipath (due to non-equivalance or maxpaths exceeded), * or the matching multipath is sorted later in the multipath * list. Before we enqueue the path on the new multipath list, * make sure its not on the old_best multipath list or referenced * via next_mpath: * - If next_mpath points to this new path, update next_mpath to * point to the multipath after this one * - Dequeue the path from the multipath list just to make sure */ new_mpath = listgetdata (mp_node); list_delete_node (mp_list, mp_node); if ((mpath_count < maxpaths) && (new_mpath != new_best) && bgp_info_nexthop_cmp (prev_mpath, new_mpath)) { if (new_mpath == next_mpath) next_mpath = bgp_info_mpath_next (new_mpath); bgp_info_mpath_dequeue (new_mpath); bgp_info_mpath_enqueue (prev_mpath, new_mpath); prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; if (debug) zlog_debug ("%s add mpath nexthop %s peer %s", pfx_buf, inet_ntop (AF_INET, &new_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), sockunion2str (new_mpath->peer->su_remote, nh_buf[1], sizeof (nh_buf[1]))); } mp_node = mp_next_node; } } if (new_best) { bgp_info_mpath_count_set (new_best, mpath_count-1); if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); } } /* * bgp_mp_dmed_deselect * * Clean up multipath information for BGP_INFO_DMED_SELECTED path that * is not selected as best path */ void bgp_mp_dmed_deselect (struct bgp_info *dmed_best) { struct bgp_info *mpinfo, *mpnext; if (!dmed_best) return; for (mpinfo = bgp_info_mpath_first (dmed_best); mpinfo; mpinfo = mpnext) { mpnext = bgp_info_mpath_next (mpinfo); bgp_info_mpath_dequeue (mpinfo); } bgp_info_mpath_count_set (dmed_best, 0); UNSET_FLAG (dmed_best->flags, BGP_INFO_MULTIPATH_CHG); assert (bgp_info_mpath_first (dmed_best) == 0); } /* * bgp_info_mpath_aggregate_update * * Set the multipath aggregate attribute. We need to see if the * aggregate has changed and then set the ATTR_CHANGED flag on the * bestpath info so that a peer update will be generated. The * change is detected by generating the current attribute, * interning it, and then comparing the interned pointer with the * current value. We can skip this generate/compare step if there * is no change in multipath selection and no attribute change in * any multipath. */ void bgp_info_mpath_aggregate_update (struct bgp_info *new_best, struct bgp_info *old_best) { struct bgp_info *mpinfo; struct aspath *aspath; struct aspath *asmerge; struct attr *new_attr, *old_attr; u_char origin, attr_chg; struct community *community, *commerge; struct ecommunity *ecomm, *ecommerge; struct attr_extra *ae; struct attr attr = { 0 }; if (old_best && (old_best != new_best) && (old_attr = bgp_info_mpath_attr (old_best))) { bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (old_best, NULL); } if (!new_best) return; if (!bgp_info_mpath_count (new_best)) { if ((new_attr = bgp_info_mpath_attr (new_best))) { bgp_attr_unintern (&new_attr); bgp_info_mpath_attr_set (new_best, NULL); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } return; } /* * Bail out here if the following is true: * - MULTIPATH_CHG bit is not set on new_best, and * - No change in bestpath, and * - ATTR_CHANGED bit is not set on new_best or any of the multipaths */ if (!CHECK_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG) && (old_best == new_best)) { attr_chg = 0; if (CHECK_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED)) attr_chg = 1; else for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { if (CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) { attr_chg = 1; break; } } if (!attr_chg) { assert (bgp_info_mpath_attr (new_best)); return; } } bgp_attr_dup (&attr, new_best->attr); /* aggregate attribute from multipath constituents */ aspath = aspath_dup (attr.aspath); origin = attr.origin; community = attr.community ? community_dup (attr.community) : NULL; ae = attr.extra; ecomm = (ae && ae->ecommunity) ? ecommunity_dup (ae->ecommunity) : NULL; for (mpinfo = bgp_info_mpath_first (new_best); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { asmerge = aspath_aggregate (aspath, mpinfo->attr->aspath); aspath_free (aspath); aspath = asmerge; if (origin < mpinfo->attr->origin) origin = mpinfo->attr->origin; if (mpinfo->attr->community) { if (community) { commerge = community_merge (community, mpinfo->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (mpinfo->attr->community); } ae = mpinfo->attr->extra; if (ae && ae->ecommunity) { if (ecomm) { ecommerge = ecommunity_merge (ecomm, ae->ecommunity); ecomm = ecommunity_uniq_sort (ecommerge); ecommunity_free (&ecommerge); } else ecomm = ecommunity_dup (ae->ecommunity); } } attr.aspath = aspath; attr.origin = origin; if (community) { attr.community = community; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } if (ecomm) { ae = bgp_attr_extra_get (&attr); ae->ecommunity = ecomm; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } /* Zap multipath attr nexthop so we set nexthop to self */ attr.nexthop.s_addr = 0; #ifdef HAVE_IPV6 if (attr.extra) memset (&attr.extra->mp_nexthop_global, 0, sizeof (struct in6_addr)); #endif /* HAVE_IPV6 */ /* TODO: should we set ATOMIC_AGGREGATE and AGGREGATOR? */ new_attr = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); if (new_attr != bgp_info_mpath_attr (new_best)) { if ((old_attr = bgp_info_mpath_attr (new_best))) bgp_attr_unintern (&old_attr); bgp_info_mpath_attr_set (new_best, new_attr); SET_FLAG (new_best->flags, BGP_INFO_ATTR_CHANGED); } else bgp_attr_unintern (&new_attr); } quagga-0.99.24.1/bgpd/bgp_vty.c0000644000175000017500000126135212476520570013000 00000000000000/* BGP VTY interface. Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "plist.h" #include "buffer.h" #include "linklist.h" #include "stream.h" #include "thread.h" #include "log.h" #include "memory.h" #include "hash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" extern struct in_addr router_id_zebra; /* Utility function to get address family from current node. */ afi_t bgp_node_afi (struct vty *vty) { if (vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) return AFI_IP6; return AFI_IP; } /* Utility function to get subsequent address family from current node. */ safi_t bgp_node_safi (struct vty *vty) { if (vty->node == BGP_VPNV4_NODE) return SAFI_MPLS_VPN; if (vty->node == BGP_IPV4M_NODE || vty->node == BGP_IPV6M_NODE) return SAFI_MULTICAST; return SAFI_UNICAST; } static int peer_address_self_check (union sockunion *su) { struct interface *ifp = NULL; if (su->sa.sa_family == AF_INET) ifp = if_lookup_by_ipv4_exact (&su->sin.sin_addr); #ifdef HAVE_IPV6 else if (su->sa.sa_family == AF_INET6) ifp = if_lookup_by_ipv6_exact (&su->sin6.sin6_addr); #endif /* HAVE IPV6 */ if (ifp) return 1; return 0; } /* Utility function for looking up peer from VTY. */ static struct peer * peer_lookup_vty (struct vty *vty, const char *ip_str) { int ret; struct bgp *bgp; union sockunion su; struct peer *peer; bgp = vty->index; ret = str2sockunion (ip_str, &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); return NULL; } peer = peer_lookup (bgp, &su); if (! peer) { vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE); return NULL; } return peer; } /* Utility function for looking up peer or peer group. */ static struct peer * peer_and_group_lookup_vty (struct vty *vty, const char *peer_str) { int ret; struct bgp *bgp; union sockunion su; struct peer *peer; struct peer_group *group; bgp = vty->index; ret = str2sockunion (peer_str, &su); if (ret == 0) { peer = peer_lookup (bgp, &su); if (peer) return peer; } else { group = peer_group_lookup (bgp, peer_str); if (group) return group->conf; } vty_out (vty, "%% Specify remote-as or peer-group commands first%s", VTY_NEWLINE); return NULL; } static int bgp_vty_return (struct vty *vty, int ret) { const char *str = NULL; switch (ret) { case BGP_ERR_INVALID_VALUE: str = "Invalid value"; break; case BGP_ERR_INVALID_FLAG: str = "Invalid flag"; break; case BGP_ERR_PEER_INACTIVE: str = "Activate the neighbor for the address family first"; break; case BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER: str = "Invalid command for a peer-group member"; break; case BGP_ERR_PEER_GROUP_SHUTDOWN: str = "Peer-group has been shutdown. Activate the peer-group first"; break; case BGP_ERR_PEER_GROUP_HAS_THE_FLAG: str = "This peer is a peer-group member. Please change peer-group configuration"; break; case BGP_ERR_PEER_FLAG_CONFLICT: str = "Can't set override-capability and strict-capability-match at the same time"; break; case BGP_ERR_PEER_GROUP_MEMBER_EXISTS: str = "No activate for peergroup can be given only if peer-group has no members"; break; case BGP_ERR_PEER_BELONGS_TO_GROUP: str = "No activate for an individual peer-group member is invalid"; break; case BGP_ERR_PEER_GROUP_AF_UNCONFIGURED: str = "Activate the peer-group for the address family first"; break; case BGP_ERR_PEER_GROUP_NO_REMOTE_AS: str = "Specify remote-as or peer-group remote AS first"; break; case BGP_ERR_PEER_GROUP_CANT_CHANGE: str = "Cannot change the peer-group. Deconfigure first"; break; case BGP_ERR_PEER_GROUP_MISMATCH: str = "Cannot have different peer-group for the neighbor"; break; case BGP_ERR_PEER_FILTER_CONFLICT: str = "Prefix/distribute list can not co-exist"; break; case BGP_ERR_NOT_INTERNAL_PEER: str = "Invalid command. Not an internal neighbor"; break; case BGP_ERR_REMOVE_PRIVATE_AS: str = "Private AS cannot be removed for IBGP peers"; break; case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP: str = "Local-AS allowed only for EBGP peers"; break; case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS: str = "Cannot have local-as same as BGP AS number"; break; case BGP_ERR_TCPSIG_FAILED: str = "Error while applying TCP-Sig to session(s)"; break; case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK: str = "ebgp-multihop and ttl-security cannot be configured together"; break; case BGP_ERR_NO_IBGP_WITH_TTLHACK: str = "ttl-security only allowed for EBGP peers"; break; } if (str) { vty_out (vty, "%% %s%s", str, VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* BGP global configuration. */ DEFUN (bgp_multiple_instance_func, bgp_multiple_instance_cmd, "bgp multiple-instance", BGP_STR "Enable bgp multiple instance\n") { bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE); return CMD_SUCCESS; } DEFUN (no_bgp_multiple_instance, no_bgp_multiple_instance_cmd, "no bgp multiple-instance", NO_STR BGP_STR "BGP multiple instance\n") { int ret; ret = bgp_option_unset (BGP_OPT_MULTIPLE_INSTANCE); if (ret < 0) { vty_out (vty, "%% There are more than two BGP instances%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (bgp_config_type, bgp_config_type_cmd, "bgp config-type (cisco|zebra)", BGP_STR "Configuration type\n" "cisco\n" "zebra\n") { if (strncmp (argv[0], "c", 1) == 0) bgp_option_set (BGP_OPT_CONFIG_CISCO); else bgp_option_unset (BGP_OPT_CONFIG_CISCO); return CMD_SUCCESS; } DEFUN (no_bgp_config_type, no_bgp_config_type_cmd, "no bgp config-type", NO_STR BGP_STR "Display configuration type\n") { bgp_option_unset (BGP_OPT_CONFIG_CISCO); return CMD_SUCCESS; } DEFUN (no_synchronization, no_synchronization_cmd, "no synchronization", NO_STR "Perform IGP synchronization\n") { return CMD_SUCCESS; } DEFUN (no_auto_summary, no_auto_summary_cmd, "no auto-summary", NO_STR "Enable automatic network number summarization\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (neighbor_version, neighbor_version_cmd, NEIGHBOR_CMD "version (4|4-)", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Set the BGP version to match a neighbor\n" "Neighbor's BGP version\n") { return CMD_SUCCESS; } /* "router bgp" commands. */ DEFUN (router_bgp, router_bgp_cmd, "router bgp " CMD_AS_RANGE, ROUTER_STR BGP_STR AS_STR) { int ret; as_t as; struct bgp *bgp; const char *name = NULL; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); if (argc == 2) name = argv[1]; ret = bgp_get (&bgp, &as, name); switch (ret) { case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET: vty_out (vty, "Please specify 'bgp multiple-instance' first%s", VTY_NEWLINE); return CMD_WARNING; case BGP_ERR_AS_MISMATCH: vty_out (vty, "BGP is already running; AS is %u%s", as, VTY_NEWLINE); return CMD_WARNING; case BGP_ERR_INSTANCE_MISMATCH: vty_out (vty, "BGP view name and AS number mismatch%s", VTY_NEWLINE); vty_out (vty, "BGP instance is already running; AS is %u%s", as, VTY_NEWLINE); return CMD_WARNING; } vty->node = BGP_NODE; vty->index = bgp; return CMD_SUCCESS; } ALIAS (router_bgp, router_bgp_view_cmd, "router bgp " CMD_AS_RANGE " view WORD", ROUTER_STR BGP_STR AS_STR "BGP view\n" "view name\n") /* "no router bgp" commands. */ DEFUN (no_router_bgp, no_router_bgp_cmd, "no router bgp " CMD_AS_RANGE, NO_STR ROUTER_STR BGP_STR AS_STR) { as_t as; struct bgp *bgp; const char *name = NULL; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); if (argc == 2) name = argv[1]; /* Lookup bgp structure. */ bgp = bgp_lookup (as, name); if (! bgp) { vty_out (vty, "%% Can't find BGP instance%s", VTY_NEWLINE); return CMD_WARNING; } bgp_delete (bgp); return CMD_SUCCESS; } ALIAS (no_router_bgp, no_router_bgp_view_cmd, "no router bgp " CMD_AS_RANGE " view WORD", NO_STR ROUTER_STR BGP_STR AS_STR "BGP view\n" "view name\n") /* BGP router-id. */ DEFUN (bgp_router_id, bgp_router_id_cmd, "bgp router-id A.B.C.D", BGP_STR "Override configured router identifier\n" "Manually configured router identifier\n") { int ret; struct in_addr id; struct bgp *bgp; bgp = vty->index; ret = inet_aton (argv[0], &id); if (! ret) { vty_out (vty, "%% Malformed bgp router identifier%s", VTY_NEWLINE); return CMD_WARNING; } bgp->router_id_static = id; bgp_router_id_set (bgp, &id); return CMD_SUCCESS; } DEFUN (no_bgp_router_id, no_bgp_router_id_cmd, "no bgp router-id", NO_STR BGP_STR "Override configured router identifier\n") { int ret; struct in_addr id; struct bgp *bgp; bgp = vty->index; if (argc == 1) { ret = inet_aton (argv[0], &id); if (! ret) { vty_out (vty, "%% Malformed BGP router identifier%s", VTY_NEWLINE); return CMD_WARNING; } if (! IPV4_ADDR_SAME (&bgp->router_id_static, &id)) { vty_out (vty, "%% BGP router-id doesn't match%s", VTY_NEWLINE); return CMD_WARNING; } } bgp->router_id_static.s_addr = 0; bgp_router_id_set (bgp, &router_id_zebra); return CMD_SUCCESS; } ALIAS (no_bgp_router_id, no_bgp_router_id_val_cmd, "no bgp router-id A.B.C.D", NO_STR BGP_STR "Override configured router identifier\n" "Manually configured router identifier\n") /* BGP Cluster ID. */ DEFUN (bgp_cluster_id, bgp_cluster_id_cmd, "bgp cluster-id A.B.C.D", BGP_STR "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id in IP address format\n") { int ret; struct bgp *bgp; struct in_addr cluster; bgp = vty->index; ret = inet_aton (argv[0], &cluster); if (! ret) { vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); return CMD_WARNING; } bgp_cluster_id_set (bgp, &cluster); return CMD_SUCCESS; } ALIAS (bgp_cluster_id, bgp_cluster_id32_cmd, "bgp cluster-id <1-4294967295>", BGP_STR "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id as 32 bit quantity\n") DEFUN (no_bgp_cluster_id, no_bgp_cluster_id_cmd, "no bgp cluster-id", NO_STR BGP_STR "Configure Route-Reflector Cluster-id\n") { int ret; struct bgp *bgp; struct in_addr cluster; bgp = vty->index; if (argc == 1) { ret = inet_aton (argv[0], &cluster); if (! ret) { vty_out (vty, "%% Malformed bgp cluster identifier%s", VTY_NEWLINE); return CMD_WARNING; } } bgp_cluster_id_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_cluster_id, no_bgp_cluster_id_arg_cmd, "no bgp cluster-id A.B.C.D", NO_STR BGP_STR "Configure Route-Reflector Cluster-id\n" "Route-Reflector Cluster-id in IP address format\n") DEFUN (bgp_confederation_identifier, bgp_confederation_identifier_cmd, "bgp confederation identifier " CMD_AS_RANGE, "BGP specific commands\n" "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") { struct bgp *bgp; as_t as; bgp = vty->index; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); bgp_confederation_id_set (bgp, as); return CMD_SUCCESS; } DEFUN (no_bgp_confederation_identifier, no_bgp_confederation_identifier_cmd, "no bgp confederation identifier", NO_STR "BGP specific commands\n" "AS confederation parameters\n" "AS number\n") { struct bgp *bgp; as_t as __attribute__((unused)); /* Dummy for VTY_GET_INTEGER_RANGE */ bgp = vty->index; if (argc == 1) VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); bgp_confederation_id_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_confederation_identifier, no_bgp_confederation_identifier_arg_cmd, "no bgp confederation identifier " CMD_AS_RANGE, NO_STR "BGP specific commands\n" "AS confederation parameters\n" "AS number\n" "Set routing domain confederation AS\n") DEFUN (bgp_confederation_peers, bgp_confederation_peers_cmd, "bgp confederation peers ." CMD_AS_RANGE, "BGP specific commands\n" "AS confederation parameters\n" "Peer ASs in BGP confederation\n" AS_STR) { struct bgp *bgp; as_t as; int i; bgp = vty->index; for (i = 0; i < argc; i++) { VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, BGP_AS4_MAX); if (bgp->as == as) { vty_out (vty, "%% Local member-AS not allowed in confed peer list%s", VTY_NEWLINE); continue; } bgp_confederation_peers_add (bgp, as); } return CMD_SUCCESS; } DEFUN (no_bgp_confederation_peers, no_bgp_confederation_peers_cmd, "no bgp confederation peers ." CMD_AS_RANGE, NO_STR "BGP specific commands\n" "AS confederation parameters\n" "Peer ASs in BGP confederation\n" AS_STR) { struct bgp *bgp; as_t as; int i; bgp = vty->index; for (i = 0; i < argc; i++) { VTY_GET_INTEGER_RANGE ("AS", as, argv[i], 1, BGP_AS4_MAX); bgp_confederation_peers_remove (bgp, as); } return CMD_SUCCESS; } /* Maximum-paths configuration */ DEFUN (bgp_maxpaths, bgp_maxpaths_cmd, "maximum-paths <1-255>", "Forward packets over multiple paths\n" "Number of paths\n") { struct bgp *bgp; u_int16_t maxpaths; int ret; bgp = vty->index; VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_EBGP, maxpaths); if (ret < 0) { vty_out (vty, "%% Failed to set maximum-paths %u for afi %u, safi %u%s", maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (bgp_maxpaths_ibgp, bgp_maxpaths_ibgp_cmd, "maximum-paths ibgp <1-255>", "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") { struct bgp *bgp; u_int16_t maxpaths; int ret; bgp = vty->index; VTY_GET_INTEGER_RANGE ("maximum-paths", maxpaths, argv[0], 1, 255); ret = bgp_maximum_paths_set (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_IBGP, maxpaths); if (ret < 0) { vty_out (vty, "%% Failed to set maximum-paths ibgp %u for afi %u, safi %u%s", maxpaths, bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_bgp_maxpaths, no_bgp_maxpaths_cmd, "no maximum-paths", NO_STR "Forward packets over multiple paths\n" "Number of paths\n") { struct bgp *bgp; int ret; bgp = vty->index; ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_EBGP); if (ret < 0) { vty_out (vty, "%% Failed to unset maximum-paths for afi %u, safi %u%s", bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_bgp_maxpaths, no_bgp_maxpaths_arg_cmd, "no maximum-paths <1-255>", NO_STR "Forward packets over multiple paths\n" "Number of paths\n") DEFUN (no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_cmd, "no maximum-paths ibgp", NO_STR "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") { struct bgp *bgp; int ret; bgp = vty->index; ret = bgp_maximum_paths_unset (bgp, bgp_node_afi (vty), bgp_node_safi(vty), BGP_PEER_IBGP); if (ret < 0) { vty_out (vty, "%% Failed to unset maximum-paths ibgp for afi %u, safi %u%s", bgp_node_afi (vty), bgp_node_safi(vty), VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } ALIAS (no_bgp_maxpaths_ibgp, no_bgp_maxpaths_ibgp_arg_cmd, "no maximum-paths ibgp <1-255>", NO_STR "Forward packets over multiple paths\n" "iBGP-multipath\n" "Number of paths\n") int bgp_config_write_maxpaths (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { if (bgp->maxpaths[afi][safi].maxpaths_ebgp != BGP_DEFAULT_MAXPATHS) { bgp_config_write_family_header (vty, afi, safi, write); vty_out (vty, " maximum-paths %d%s", bgp->maxpaths[afi][safi].maxpaths_ebgp, VTY_NEWLINE); } if (bgp->maxpaths[afi][safi].maxpaths_ibgp != BGP_DEFAULT_MAXPATHS) { bgp_config_write_family_header (vty, afi, safi, write); vty_out (vty, " maximum-paths ibgp %d%s", bgp->maxpaths[afi][safi].maxpaths_ibgp, VTY_NEWLINE); } return 0; } /* BGP timers. */ DEFUN (bgp_timers, bgp_timers_cmd, "timers bgp <0-65535> <0-65535>", "Adjust routing timers\n" "BGP timers\n" "Keepalive interval\n" "Holdtime\n") { struct bgp *bgp; unsigned long keepalive = 0; unsigned long holdtime = 0; bgp = vty->index; VTY_GET_INTEGER ("keepalive", keepalive, argv[0]); VTY_GET_INTEGER ("holdtime", holdtime, argv[1]); /* Holdtime value check. */ if (holdtime < 3 && holdtime != 0) { vty_out (vty, "%% hold time value must be either 0 or greater than 3%s", VTY_NEWLINE); return CMD_WARNING; } bgp_timers_set (bgp, keepalive, holdtime); return CMD_SUCCESS; } DEFUN (no_bgp_timers, no_bgp_timers_cmd, "no timers bgp", NO_STR "Adjust routing timers\n" "BGP timers\n") { struct bgp *bgp; bgp = vty->index; bgp_timers_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_timers, no_bgp_timers_arg_cmd, "no timers bgp <0-65535> <0-65535>", NO_STR "Adjust routing timers\n" "BGP timers\n" "Keepalive interval\n" "Holdtime\n") DEFUN (bgp_client_to_client_reflection, bgp_client_to_client_reflection_cmd, "bgp client-to-client reflection", "BGP specific commands\n" "Configure client to client route reflection\n" "reflection of routes allowed\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); return CMD_SUCCESS; } DEFUN (no_bgp_client_to_client_reflection, no_bgp_client_to_client_reflection_cmd, "no bgp client-to-client reflection", NO_STR "BGP specific commands\n" "Configure client to client route reflection\n" "reflection of routes allowed\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT); return CMD_SUCCESS; } /* "bgp always-compare-med" configuration. */ DEFUN (bgp_always_compare_med, bgp_always_compare_med_cmd, "bgp always-compare-med", "BGP specific commands\n" "Allow comparing MED from different neighbors\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); return CMD_SUCCESS; } DEFUN (no_bgp_always_compare_med, no_bgp_always_compare_med_cmd, "no bgp always-compare-med", NO_STR "BGP specific commands\n" "Allow comparing MED from different neighbors\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ALWAYS_COMPARE_MED); return CMD_SUCCESS; } /* "bgp deterministic-med" configuration. */ DEFUN (bgp_deterministic_med, bgp_deterministic_med_cmd, "bgp deterministic-med", "BGP specific commands\n" "Pick the best-MED path among paths advertised from the neighboring AS\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED); return CMD_SUCCESS; } DEFUN (no_bgp_deterministic_med, no_bgp_deterministic_med_cmd, "no bgp deterministic-med", NO_STR "BGP specific commands\n" "Pick the best-MED path among paths advertised from the neighboring AS\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_DETERMINISTIC_MED); return CMD_SUCCESS; } /* "bgp graceful-restart" configuration. */ DEFUN (bgp_graceful_restart, bgp_graceful_restart_cmd, "bgp graceful-restart", "BGP specific commands\n" "Graceful restart capability parameters\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_GRACEFUL_RESTART); return CMD_SUCCESS; } DEFUN (no_bgp_graceful_restart, no_bgp_graceful_restart_cmd, "no bgp graceful-restart", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_GRACEFUL_RESTART); return CMD_SUCCESS; } DEFUN (bgp_graceful_restart_stalepath_time, bgp_graceful_restart_stalepath_time_cmd, "bgp graceful-restart stalepath-time <1-3600>", "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") { struct bgp *bgp; u_int32_t stalepath; bgp = vty->index; if (! bgp) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("stalepath-time", stalepath, argv[0], 1, 3600); bgp->stalepath_time = stalepath; return CMD_SUCCESS; } DEFUN (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_cmd, "no bgp graceful-restart stalepath-time", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n") { struct bgp *bgp; bgp = vty->index; if (! bgp) return CMD_WARNING; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; return CMD_SUCCESS; } ALIAS (no_bgp_graceful_restart_stalepath_time, no_bgp_graceful_restart_stalepath_time_val_cmd, "no bgp graceful-restart stalepath-time <1-3600>", NO_STR "BGP specific commands\n" "Graceful restart capability parameters\n" "Set the max time to hold onto restarting peer's stale paths\n" "Delay value (seconds)\n") /* "bgp fast-external-failover" configuration. */ DEFUN (bgp_fast_external_failover, bgp_fast_external_failover_cmd, "bgp fast-external-failover", BGP_STR "Immediately reset session if a link to a directly connected external peer goes down\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); return CMD_SUCCESS; } DEFUN (no_bgp_fast_external_failover, no_bgp_fast_external_failover_cmd, "no bgp fast-external-failover", NO_STR BGP_STR "Immediately reset session if a link to a directly connected external peer goes down\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_FAST_EXT_FAILOVER); return CMD_SUCCESS; } /* "bgp enforce-first-as" configuration. */ DEFUN (bgp_enforce_first_as, bgp_enforce_first_as_cmd, "bgp enforce-first-as", BGP_STR "Enforce the first AS for EBGP routes\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ENFORCE_FIRST_AS); return CMD_SUCCESS; } DEFUN (no_bgp_enforce_first_as, no_bgp_enforce_first_as_cmd, "no bgp enforce-first-as", NO_STR BGP_STR "Enforce the first AS for EBGP routes\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ENFORCE_FIRST_AS); return CMD_SUCCESS; } /* "bgp bestpath compare-routerid" configuration. */ DEFUN (bgp_bestpath_compare_router_id, bgp_bestpath_compare_router_id_cmd, "bgp bestpath compare-routerid", "BGP specific commands\n" "Change the default bestpath selection\n" "Compare router-id for identical EBGP paths\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_COMPARE_ROUTER_ID); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_compare_router_id, no_bgp_bestpath_compare_router_id_cmd, "no bgp bestpath compare-routerid", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "Compare router-id for identical EBGP paths\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_COMPARE_ROUTER_ID); return CMD_SUCCESS; } /* "bgp bestpath as-path ignore" configuration. */ DEFUN (bgp_bestpath_aspath_ignore, bgp_bestpath_aspath_ignore_cmd, "bgp bestpath as-path ignore", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Ignore as-path length in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ASPATH_IGNORE); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_aspath_ignore, no_bgp_bestpath_aspath_ignore_cmd, "no bgp bestpath as-path ignore", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Ignore as-path length in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ASPATH_IGNORE); return CMD_SUCCESS; } /* "bgp bestpath as-path confed" configuration. */ DEFUN (bgp_bestpath_aspath_confed, bgp_bestpath_aspath_confed_cmd, "bgp bestpath as-path confed", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ASPATH_CONFED); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_aspath_confed, no_bgp_bestpath_aspath_confed_cmd, "no bgp bestpath as-path confed", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Compare path lengths including confederation sets & sequences in selecting a route\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ASPATH_CONFED); return CMD_SUCCESS; } /* "bgp bestpath as-path multipath-relax" configuration. */ DEFUN (bgp_bestpath_aspath_multipath_relax, bgp_bestpath_aspath_multipath_relax_cmd, "bgp bestpath as-path multipath-relax", "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_aspath_multipath_relax, no_bgp_bestpath_aspath_multipath_relax_cmd, "no bgp bestpath as-path multipath-relax", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "AS-path attribute\n" "Allow load sharing across routes that have different AS paths (but same length)\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX); return CMD_SUCCESS; } /* "bgp log-neighbor-changes" configuration. */ DEFUN (bgp_log_neighbor_changes, bgp_log_neighbor_changes_cmd, "bgp log-neighbor-changes", "BGP specific commands\n" "Log neighbor up/down and reset reason\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); return CMD_SUCCESS; } DEFUN (no_bgp_log_neighbor_changes, no_bgp_log_neighbor_changes_cmd, "no bgp log-neighbor-changes", NO_STR "BGP specific commands\n" "Log neighbor up/down and reset reason\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES); return CMD_SUCCESS; } /* "bgp bestpath med" configuration. */ DEFUN (bgp_bestpath_med, bgp_bestpath_med_cmd, "bgp bestpath med (confed|missing-as-worst)", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; if (strncmp (argv[0], "confed", 1) == 0) bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); else bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } DEFUN (bgp_bestpath_med2, bgp_bestpath_med2_cmd, "bgp bestpath med confed missing-as-worst", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_MED_CONFED); bgp_flag_set (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } ALIAS (bgp_bestpath_med2, bgp_bestpath_med3_cmd, "bgp bestpath med missing-as-worst confed", "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") DEFUN (no_bgp_bestpath_med, no_bgp_bestpath_med_cmd, "no bgp bestpath med (confed|missing-as-worst)", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; if (strncmp (argv[0], "confed", 1) == 0) bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); else bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } DEFUN (no_bgp_bestpath_med2, no_bgp_bestpath_med2_cmd, "no bgp bestpath med confed missing-as-worst", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Compare MED among confederation paths\n" "Treat missing MED as the least preferred one\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_MED_CONFED); bgp_flag_unset (bgp, BGP_FLAG_MED_MISSING_AS_WORST); return CMD_SUCCESS; } ALIAS (no_bgp_bestpath_med2, no_bgp_bestpath_med3_cmd, "no bgp bestpath med missing-as-worst confed", NO_STR "BGP specific commands\n" "Change the default bestpath selection\n" "MED attribute\n" "Treat missing MED as the least preferred one\n" "Compare MED among confederation paths\n") /* "no bgp default ipv4-unicast". */ DEFUN (no_bgp_default_ipv4_unicast, no_bgp_default_ipv4_unicast_cmd, "no bgp default ipv4-unicast", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_NO_DEFAULT_IPV4); return CMD_SUCCESS; } DEFUN (bgp_default_ipv4_unicast, bgp_default_ipv4_unicast_cmd, "bgp default ipv4-unicast", "BGP specific commands\n" "Configure BGP defaults\n" "Activate ipv4-unicast for a peer by default\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_NO_DEFAULT_IPV4); return CMD_SUCCESS; } /* "bgp import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, "bgp network import-check", "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK); return CMD_SUCCESS; } DEFUN (no_bgp_network_import_check, no_bgp_network_import_check_cmd, "no bgp network import-check", NO_STR "BGP specific commands\n" "BGP network command\n" "Check BGP network route exists in IGP\n") { struct bgp *bgp; bgp = vty->index; bgp_flag_unset (bgp, BGP_FLAG_IMPORT_CHECK); return CMD_SUCCESS; } DEFUN (bgp_default_local_preference, bgp_default_local_preference_cmd, "bgp default local-preference <0-4294967295>", "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") { struct bgp *bgp; u_int32_t local_pref; bgp = vty->index; VTY_GET_INTEGER ("local preference", local_pref, argv[0]); bgp_default_local_preference_set (bgp, local_pref); return CMD_SUCCESS; } DEFUN (no_bgp_default_local_preference, no_bgp_default_local_preference_cmd, "no bgp default local-preference", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n") { struct bgp *bgp; bgp = vty->index; bgp_default_local_preference_unset (bgp); return CMD_SUCCESS; } ALIAS (no_bgp_default_local_preference, no_bgp_default_local_preference_val_cmd, "no bgp default local-preference <0-4294967295>", NO_STR "BGP specific commands\n" "Configure BGP defaults\n" "local preference (higher=more preferred)\n" "Configure default local preference value\n") static int peer_remote_as_vty (struct vty *vty, const char *peer_str, const char *as_str, afi_t afi, safi_t safi) { int ret; struct bgp *bgp; as_t as; union sockunion su; bgp = vty->index; /* Get AS number. */ VTY_GET_INTEGER_RANGE ("AS", as, as_str, 1, BGP_AS4_MAX); /* If peer is peer group, call proper function. */ ret = str2sockunion (peer_str, &su); if (ret < 0) { ret = peer_group_remote_as (bgp, peer_str, &as); if (ret < 0) { vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } if (peer_address_self_check (&su)) { vty_out (vty, "%% Can not configure the local system as neighbor%s", VTY_NEWLINE); return CMD_WARNING; } ret = peer_remote_as (bgp, &su, &as, afi, safi); /* This peer belongs to peer group. */ switch (ret) { case BGP_ERR_PEER_GROUP_MEMBER: vty_out (vty, "%% Peer-group AS %u. Cannot configure remote-as for member%s", as, VTY_NEWLINE); return CMD_WARNING; case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT: vty_out (vty, "%% The AS# can not be changed from %u to %s, peer-group members must be all internal or all external%s", as, as_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_vty_return (vty, ret); } DEFUN (neighbor_remote_as, neighbor_remote_as_cmd, NEIGHBOR_CMD2 "remote-as " CMD_AS_RANGE, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a BGP neighbor\n" AS_STR) { return peer_remote_as_vty (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST); } DEFUN (neighbor_peer_group, neighbor_peer_group_cmd, "neighbor WORD peer-group", NEIGHBOR_STR "Neighbor tag\n" "Configure peer-group\n") { struct bgp *bgp; struct peer_group *group; bgp = vty->index; group = peer_group_get (bgp, argv[0]); if (! group) return CMD_WARNING; return CMD_SUCCESS; } DEFUN (no_neighbor, no_neighbor_cmd, NO_NEIGHBOR_CMD2, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2) { int ret; union sockunion su; struct peer_group *group; struct peer *peer; ret = str2sockunion (argv[0], &su); if (ret < 0) { group = peer_group_lookup (vty->index, argv[0]); if (group) peer_group_delete (group); else { vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } } else { peer = peer_lookup (vty->index, &su); if (peer) peer_delete (peer); } return CMD_SUCCESS; } ALIAS (no_neighbor, no_neighbor_remote_as_cmd, NO_NEIGHBOR_CMD "remote-as " CMD_AS_RANGE, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Specify a BGP neighbor\n" AS_STR) DEFUN (no_neighbor_peer_group, no_neighbor_peer_group_cmd, "no neighbor WORD peer-group", NO_STR NEIGHBOR_STR "Neighbor tag\n" "Configure peer-group\n") { struct peer_group *group; group = peer_group_lookup (vty->index, argv[0]); if (group) peer_group_delete (group); else { vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (no_neighbor_peer_group_remote_as, no_neighbor_peer_group_remote_as_cmd, "no neighbor WORD remote-as " CMD_AS_RANGE, NO_STR NEIGHBOR_STR "Neighbor tag\n" "Specify a BGP neighbor\n" AS_STR) { struct peer_group *group; group = peer_group_lookup (vty->index, argv[0]); if (group) peer_group_remote_as_delete (group); else { vty_out (vty, "%% Create the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (neighbor_local_as, neighbor_local_as_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_local_as_set (peer, atoi (argv[1]), 0, 0); return bgp_vty_return (vty, ret); } DEFUN (neighbor_local_as_no_prepend, neighbor_local_as_no_prepend_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_local_as_set (peer, atoi (argv[1]), 1, 0); return bgp_vty_return (vty, ret); } DEFUN (neighbor_local_as_no_prepend_replace_as, neighbor_local_as_no_prepend_replace_as_cmd, NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_local_as_set (peer, atoi (argv[1]), 1, 1); return bgp_vty_return (vty, ret); } DEFUN (no_neighbor_local_as, no_neighbor_local_as_cmd, NO_NEIGHBOR_CMD2 "local-as", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_local_as_unset (peer); return bgp_vty_return (vty, ret); } ALIAS (no_neighbor_local_as, no_neighbor_local_as_val_cmd, NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE, NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n") ALIAS (no_neighbor_local_as, no_neighbor_local_as_val2_cmd, NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n") ALIAS (no_neighbor_local_as, no_neighbor_local_as_val3_cmd, NO_NEIGHBOR_CMD2 "local-as " CMD_AS_RANGE " no-prepend replace-as", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify a local-as number\n" "AS number used as local AS\n" "Do not prepend local-as to updates from ebgp peers\n" "Do not prepend local-as to updates from ibgp peers\n") DEFUN (neighbor_password, neighbor_password_cmd, NEIGHBOR_CMD2 "password LINE", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set a password\n" "The password\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_password_set (peer, argv[1]); return bgp_vty_return (vty, ret); } DEFUN (no_neighbor_password, no_neighbor_password_cmd, NO_NEIGHBOR_CMD2 "password", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set a password\n") { struct peer *peer; int ret; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_password_unset (peer); return bgp_vty_return (vty, ret); } DEFUN (neighbor_activate, neighbor_activate_cmd, NEIGHBOR_CMD2 "activate", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enable the Address Family for this Neighbor\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; peer_activate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); return CMD_SUCCESS; } DEFUN (no_neighbor_activate, no_neighbor_activate_cmd, NO_NEIGHBOR_CMD2 "activate", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enable the Address Family for this Neighbor\n") { int ret; struct peer *peer; /* Lookup peer. */ peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_deactivate (peer, bgp_node_afi (vty), bgp_node_safi (vty)); return bgp_vty_return (vty, ret); } DEFUN (neighbor_set_peer_group, neighbor_set_peer_group_cmd, NEIGHBOR_CMD "peer-group WORD", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Member of the peer-group\n" "peer-group name\n") { int ret; as_t as; union sockunion su; struct bgp *bgp; struct peer_group *group; bgp = vty->index; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } group = peer_group_lookup (bgp, argv[1]); if (! group) { vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } if (peer_address_self_check (&su)) { vty_out (vty, "%% Can not configure the local system as neighbor%s", VTY_NEWLINE); return CMD_WARNING; } ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty), bgp_node_safi (vty), &as); if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) { vty_out (vty, "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external%s", as, VTY_NEWLINE); return CMD_WARNING; } return bgp_vty_return (vty, ret); } DEFUN (no_neighbor_set_peer_group, no_neighbor_set_peer_group_cmd, NO_NEIGHBOR_CMD "peer-group WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Member of the peer-group\n" "peer-group name\n") { int ret; struct bgp *bgp; struct peer *peer; struct peer_group *group; bgp = vty->index; peer = peer_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; group = peer_group_lookup (bgp, argv[1]); if (! group) { vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); return CMD_WARNING; } ret = peer_group_unbind (bgp, peer, group, bgp_node_afi (vty), bgp_node_safi (vty)); return bgp_vty_return (vty, ret); } static int peer_flag_modify_vty (struct vty *vty, const char *ip_str, u_int16_t flag, int set) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (set) ret = peer_flag_set (peer, flag); else ret = peer_flag_unset (peer, flag); return bgp_vty_return (vty, ret); } static int peer_flag_set_vty (struct vty *vty, const char *ip_str, u_int16_t flag) { return peer_flag_modify_vty (vty, ip_str, flag, 1); } static int peer_flag_unset_vty (struct vty *vty, const char *ip_str, u_int16_t flag) { return peer_flag_modify_vty (vty, ip_str, flag, 0); } /* neighbor passive. */ DEFUN (neighbor_passive, neighbor_passive_cmd, NEIGHBOR_CMD2 "passive", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Don't send open messages to this neighbor\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_PASSIVE); } DEFUN (no_neighbor_passive, no_neighbor_passive_cmd, NO_NEIGHBOR_CMD2 "passive", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Don't send open messages to this neighbor\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_PASSIVE); } /* neighbor shutdown. */ DEFUN (neighbor_shutdown, neighbor_shutdown_cmd, NEIGHBOR_CMD2 "shutdown", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Administratively shut down this neighbor\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); } DEFUN (no_neighbor_shutdown, no_neighbor_shutdown_cmd, NO_NEIGHBOR_CMD2 "shutdown", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Administratively shut down this neighbor\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_SHUTDOWN); } /* Deprecated neighbor capability route-refresh. */ DEFUN_DEPRECATED (neighbor_capability_route_refresh, neighbor_capability_route_refresh_cmd, NEIGHBOR_CMD2 "capability route-refresh", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise route-refresh capability to this neighbor\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_neighbor_capability_route_refresh, no_neighbor_capability_route_refresh_cmd, NO_NEIGHBOR_CMD2 "capability route-refresh", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise route-refresh capability to this neighbor\n") { return CMD_SUCCESS; } /* neighbor capability dynamic. */ DEFUN (neighbor_capability_dynamic, neighbor_capability_dynamic_cmd, NEIGHBOR_CMD2 "capability dynamic", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise dynamic capability to this neighbor\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); } DEFUN (no_neighbor_capability_dynamic, no_neighbor_capability_dynamic_cmd, NO_NEIGHBOR_CMD2 "capability dynamic", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise dynamic capability to this neighbor\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DYNAMIC_CAPABILITY); } /* neighbor dont-capability-negotiate */ DEFUN (neighbor_dont_capability_negotiate, neighbor_dont_capability_negotiate_cmd, NEIGHBOR_CMD2 "dont-capability-negotiate", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Do not perform capability negotiation\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); } DEFUN (no_neighbor_dont_capability_negotiate, no_neighbor_dont_capability_negotiate_cmd, NO_NEIGHBOR_CMD2 "dont-capability-negotiate", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Do not perform capability negotiation\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DONT_CAPABILITY); } static int peer_af_flag_modify_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_t flag, int set) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, peer_str); if (! peer) return CMD_WARNING; if (set) ret = peer_af_flag_set (peer, afi, safi, flag); else ret = peer_af_flag_unset (peer, afi, safi, flag); return bgp_vty_return (vty, ret); } static int peer_af_flag_set_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 1); } static int peer_af_flag_unset_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify_vty (vty, peer_str, afi, safi, flag, 0); } /* neighbor capability orf prefix-list. */ DEFUN (neighbor_capability_orf_prefix, neighbor_capability_orf_prefix_cmd, NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise ORF capability to the peer\n" "Advertise prefixlist ORF capability to this neighbor\n" "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") { u_int16_t flag = 0; if (strncmp (argv[1], "s", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_SM; else if (strncmp (argv[1], "r", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_RM; else if (strncmp (argv[1], "b", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; else return CMD_WARNING; return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flag); } DEFUN (no_neighbor_capability_orf_prefix, no_neighbor_capability_orf_prefix_cmd, NO_NEIGHBOR_CMD2 "capability orf prefix-list (both|send|receive)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Advertise capability to the peer\n" "Advertise ORF capability to the peer\n" "Advertise prefixlist ORF capability to this neighbor\n" "Capability to SEND and RECEIVE the ORF to/from this neighbor\n" "Capability to RECEIVE the ORF from this neighbor\n" "Capability to SEND the ORF to this neighbor\n") { u_int16_t flag = 0; if (strncmp (argv[1], "s", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_SM; else if (strncmp (argv[1], "r", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_RM; else if (strncmp (argv[1], "b", 1) == 0) flag = PEER_FLAG_ORF_PREFIX_SM|PEER_FLAG_ORF_PREFIX_RM; else return CMD_WARNING; return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flag); } /* neighbor next-hop-self. */ DEFUN (neighbor_nexthop_self, neighbor_nexthop_self_cmd, NEIGHBOR_CMD2 "next-hop-self {all}", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") { u_int32_t flags = PEER_FLAG_NEXTHOP_SELF, unset = 0; int rc; /* Check if "all" is specified */ if (argv[1] != NULL) flags |= PEER_FLAG_NEXTHOP_SELF_ALL; else unset |= PEER_FLAG_NEXTHOP_SELF_ALL; rc = peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); if ( rc == CMD_SUCCESS && unset ) rc = peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), unset); return rc; } DEFUN (no_neighbor_nexthop_self, no_neighbor_nexthop_self_cmd, NO_NEIGHBOR_CMD2 "next-hop-self {all}", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Disable the next hop calculation for this neighbor\n" "Apply also to ibgp-learned routes when acting as a route reflector\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_SELF|PEER_FLAG_NEXTHOP_SELF_ALL); } /* neighbor remove-private-AS. */ DEFUN (neighbor_remove_private_as, neighbor_remove_private_as_cmd, NEIGHBOR_CMD2 "remove-private-AS", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Remove private AS number from outbound updates\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REMOVE_PRIVATE_AS); } DEFUN (no_neighbor_remove_private_as, no_neighbor_remove_private_as_cmd, NO_NEIGHBOR_CMD2 "remove-private-AS", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Remove private AS number from outbound updates\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REMOVE_PRIVATE_AS); } /* neighbor send-community. */ DEFUN (neighbor_send_community, neighbor_send_community_cmd, NEIGHBOR_CMD2 "send-community", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); } DEFUN (no_neighbor_send_community, no_neighbor_send_community_cmd, NO_NEIGHBOR_CMD2 "send-community", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); } /* neighbor send-community extended. */ DEFUN (neighbor_send_community_type, neighbor_send_community_type_cmd, NEIGHBOR_CMD2 "send-community (both|extended|standard)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); if (strncmp (argv[1], "e", 1) == 0) return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY| PEER_FLAG_SEND_EXT_COMMUNITY)); } DEFUN (no_neighbor_send_community_type, no_neighbor_send_community_type_cmd, NO_NEIGHBOR_CMD2 "send-community (both|extended|standard)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Send Community attribute to this neighbor\n" "Send Standard and Extended Community attributes\n" "Send Extended Community attributes\n" "Send Standard Community attributes\n") { if (strncmp (argv[1], "s", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_COMMUNITY); if (strncmp (argv[1], "e", 1) == 0) return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SEND_EXT_COMMUNITY); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY)); } /* neighbor soft-reconfig. */ DEFUN (neighbor_soft_reconfiguration, neighbor_soft_reconfiguration_cmd, NEIGHBOR_CMD2 "soft-reconfiguration inbound", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SOFT_RECONFIG); } DEFUN (no_neighbor_soft_reconfiguration, no_neighbor_soft_reconfiguration_cmd, NO_NEIGHBOR_CMD2 "soft-reconfiguration inbound", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Per neighbor soft reconfiguration\n" "Allow inbound soft reconfiguration for this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_SOFT_RECONFIG); } DEFUN (neighbor_route_reflector_client, neighbor_route_reflector_client_cmd, NEIGHBOR_CMD2 "route-reflector-client", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Reflector client\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REFLECTOR_CLIENT); } DEFUN (no_neighbor_route_reflector_client, no_neighbor_route_reflector_client_cmd, NO_NEIGHBOR_CMD2 "route-reflector-client", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Reflector client\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_REFLECTOR_CLIENT); } static int peer_rsclient_set_vty (struct vty *vty, const char *peer_str, int afi, int safi) { int ret; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct listnode *node, *nnode; struct bgp_filter *pfilter; struct bgp_filter *gfilter; int locked_and_added = 0; bgp = vty->index; peer = peer_and_group_lookup_vty (vty, peer_str); if ( ! peer ) return CMD_WARNING; /* If it is already a RS-Client, don't do anything. */ if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) return CMD_SUCCESS; if ( ! peer_rsclient_active (peer) ) { peer = peer_lock (peer); /* rsclient peer list reference */ listnode_add_sort (bgp->rsclient, peer); locked_and_added = 1; } ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) { if (locked_and_added) { listnode_delete (bgp->rsclient, peer); peer_unlock (peer); /* rsclient peer list reference */ } return bgp_vty_return (vty, ret); } peer->rib[afi][safi] = bgp_table_init (afi, safi); peer->rib[afi][safi]->type = BGP_TABLE_RSCLIENT; /* RIB peer reference. Released when table is free'd in bgp_table_free. */ peer->rib[afi][safi]->owner = peer_lock (peer); /* Check for existing 'network' and 'redistribute' routes. */ bgp_check_local_routes_rsclient (peer, afi, safi); /* Check for routes for peers configured with 'soft-reconfiguration'. */ bgp_soft_reconfig_rsclient (peer, afi, safi); if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; gfilter = &peer->filter[afi][safi]; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { pfilter = &peer->filter[afi][safi]; /* Members of a non-RS-Client group should not be RS-Clients, as that is checked when the become part of the peer-group */ ret = peer_af_flag_set (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); /* Make peer's RIB point to group's RIB. */ peer->rib[afi][safi] = group->conf->rib[afi][safi]; /* Import policy. */ if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); if (gfilter->map[RMAP_IMPORT].name) { pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map =NULL; } /* Export policy. */ if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } } } return CMD_SUCCESS; } static int peer_rsclient_unset_vty (struct vty *vty, const char *peer_str, int afi, int safi) { int ret; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct listnode *node, *nnode; bgp = vty->index; peer = peer_and_group_lookup_vty (vty, peer_str); if ( ! peer ) return CMD_WARNING; /* If it is not a RS-Client, don't do anything. */ if ( ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) ) return CMD_SUCCESS; if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); peer->rib[afi][safi] = NULL; } peer = group->conf; } ret = peer_af_flag_unset (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT); if (ret < 0) return bgp_vty_return (vty, ret); if ( ! peer_rsclient_active (peer) ) { bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); listnode_delete (bgp->rsclient, peer); peer_unlock (peer); /* peer bgp rsclient reference */ } bgp_table_finish (&peer->rib[bgp_node_afi(vty)][bgp_node_safi(vty)]); return CMD_SUCCESS; } /* neighbor route-server-client. */ DEFUN (neighbor_route_server_client, neighbor_route_server_client_cmd, NEIGHBOR_CMD2 "route-server-client", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Server client\n") { return peer_rsclient_set_vty (vty, argv[0], bgp_node_afi(vty), bgp_node_safi(vty)); } DEFUN (no_neighbor_route_server_client, no_neighbor_route_server_client_cmd, NO_NEIGHBOR_CMD2 "route-server-client", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure a neighbor as Route Server client\n") { return peer_rsclient_unset_vty (vty, argv[0], bgp_node_afi(vty), bgp_node_safi(vty)); } DEFUN (neighbor_nexthop_local_unchanged, neighbor_nexthop_local_unchanged_cmd, NEIGHBOR_CMD2 "nexthop-local unchanged", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure treatment of outgoing link-local nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } DEFUN (no_neighbor_nexthop_local_unchanged, no_neighbor_nexthop_local_unchanged_cmd, NO_NEIGHBOR_CMD2 "nexthop-local unchanged", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Configure treatment of outgoing link-local-nexthop attribute\n" "Leave link-local nexthop unchanged for this peer\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED ); } DEFUN (neighbor_attr_unchanged, neighbor_attr_unchanged_cmd, NEIGHBOR_CMD2 "attribute-unchanged", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_MED_UNCHANGED)); } DEFUN (neighbor_attr_unchanged1, neighbor_attr_unchanged1_cmd, NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") { u_int16_t flags = 0; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (neighbor_attr_unchanged2, neighbor_attr_unchanged2_cmd, NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") { u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (neighbor_attr_unchanged3, neighbor_attr_unchanged3_cmd, NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") { u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (neighbor_attr_unchanged4, neighbor_attr_unchanged4_cmd, NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") { u_int16_t flags = PEER_FLAG_MED_UNCHANGED; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged5_cmd, NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged6_cmd, NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Med attribute\n" "Nexthop attribute\n") ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged7_cmd, NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "Med attribute\n" "As-path attribute\n") ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged8_cmd, NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged9_cmd, NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "Nexthop attribute\n" "As-path attribute\n") ALIAS (neighbor_attr_unchanged, neighbor_attr_unchanged10_cmd, NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") DEFUN (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n") { return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), (PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_MED_UNCHANGED)); } DEFUN (no_neighbor_attr_unchanged1, no_neighbor_attr_unchanged1_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged (as-path|next-hop|med)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") { u_int16_t flags = 0; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (no_neighbor_attr_unchanged2, no_neighbor_attr_unchanged2_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged as-path (next-hop|med)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") { u_int16_t flags = PEER_FLAG_AS_PATH_UNCHANGED; if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (no_neighbor_attr_unchanged3, no_neighbor_attr_unchanged3_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop (as-path|med)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") { u_int16_t flags = PEER_FLAG_NEXTHOP_UNCHANGED; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "med", 1) == 0) SET_FLAG (flags, PEER_FLAG_MED_UNCHANGED); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } DEFUN (no_neighbor_attr_unchanged4, no_neighbor_attr_unchanged4_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged med (as-path|next-hop)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") { u_int16_t flags = PEER_FLAG_MED_UNCHANGED; if (strncmp (argv[1], "as-path", 1) == 0) SET_FLAG (flags, PEER_FLAG_AS_PATH_UNCHANGED); else if (strncmp (argv[1], "next-hop", 1) == 0) SET_FLAG (flags, PEER_FLAG_NEXTHOP_UNCHANGED); return peer_af_flag_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), flags); } ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged5_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged as-path next-hop med", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Nexthop attribute\n" "Med attribute\n") ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged6_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged as-path med next-hop", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "As-path attribute\n" "Med attribute\n" "Nexthop attribute\n") ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged7_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop med as-path", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "Med attribute\n" "As-path attribute\n") ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged8_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged next-hop as-path med", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Nexthop attribute\n" "As-path attribute\n" "Med attribute\n") ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged9_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged med next-hop as-path", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "Nexthop attribute\n" "As-path attribute\n") ALIAS (no_neighbor_attr_unchanged, no_neighbor_attr_unchanged10_cmd, NO_NEIGHBOR_CMD2 "attribute-unchanged med as-path next-hop", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP attribute is propagated unchanged to this neighbor\n" "Med attribute\n" "As-path attribute\n" "Nexthop attribute\n") /* For old version Zebra compatibility. */ DEFUN_DEPRECATED (neighbor_transparent_as, neighbor_transparent_as_cmd, NEIGHBOR_CMD "transparent-as", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Do not append my AS number even peer is EBGP peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_AS_PATH_UNCHANGED); } DEFUN_DEPRECATED (neighbor_transparent_nexthop, neighbor_transparent_nexthop_cmd, NEIGHBOR_CMD "transparent-nexthop", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Do not change nexthop even peer is EBGP peer\n") { return peer_af_flag_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), PEER_FLAG_NEXTHOP_UNCHANGED); } /* EBGP multihop configuration. */ static int peer_ebgp_multihop_set_vty (struct vty *vty, const char *ip_str, const char *ttl_str) { struct peer *peer; unsigned int ttl; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (! ttl_str) ttl = TTL_MAX; else VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255); return bgp_vty_return (vty, peer_ebgp_multihop_set (peer, ttl)); } static int peer_ebgp_multihop_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_ebgp_multihop_unset (peer)); } /* neighbor ebgp-multihop. */ DEFUN (neighbor_ebgp_multihop, neighbor_ebgp_multihop_cmd, NEIGHBOR_CMD2 "ebgp-multihop", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Allow EBGP neighbors not on directly connected networks\n") { return peer_ebgp_multihop_set_vty (vty, argv[0], NULL); } DEFUN (neighbor_ebgp_multihop_ttl, neighbor_ebgp_multihop_ttl_cmd, NEIGHBOR_CMD2 "ebgp-multihop <1-255>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Allow EBGP neighbors not on directly connected networks\n" "maximum hop count\n") { return peer_ebgp_multihop_set_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_ebgp_multihop, no_neighbor_ebgp_multihop_cmd, NO_NEIGHBOR_CMD2 "ebgp-multihop", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Allow EBGP neighbors not on directly connected networks\n") { return peer_ebgp_multihop_unset_vty (vty, argv[0]); } ALIAS (no_neighbor_ebgp_multihop, no_neighbor_ebgp_multihop_ttl_cmd, NO_NEIGHBOR_CMD2 "ebgp-multihop <1-255>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Allow EBGP neighbors not on directly connected networks\n" "maximum hop count\n") /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, NEIGHBOR_CMD2 "disable-connected-check", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "one-hop away EBGP peer using loopback address\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_DISABLE_CONNECTED_CHECK); } DEFUN (no_neighbor_disable_connected_check, no_neighbor_disable_connected_check_cmd, NO_NEIGHBOR_CMD2 "disable-connected-check", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "one-hop away EBGP peer using loopback address\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_DISABLE_CONNECTED_CHECK); } /* Enforce multihop. */ ALIAS (neighbor_disable_connected_check, neighbor_enforce_multihop_cmd, NEIGHBOR_CMD2 "enforce-multihop", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enforce EBGP neighbors perform multihop\n") /* Enforce multihop. */ ALIAS (no_neighbor_disable_connected_check, no_neighbor_enforce_multihop_cmd, NO_NEIGHBOR_CMD2 "enforce-multihop", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Enforce EBGP neighbors perform multihop\n") DEFUN (neighbor_description, neighbor_description_cmd, NEIGHBOR_CMD2 "description .LINE", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Neighbor specific description\n" "Up to 80 characters describing this neighbor\n") { struct peer *peer; char *str; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; if (argc == 1) return CMD_SUCCESS; str = argv_concat(argv, argc, 1); peer_description_set (peer, str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } DEFUN (no_neighbor_description, no_neighbor_description_cmd, NO_NEIGHBOR_CMD2 "description", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Neighbor specific description\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; peer_description_unset (peer); return CMD_SUCCESS; } ALIAS (no_neighbor_description, no_neighbor_description_val_cmd, NO_NEIGHBOR_CMD2 "description .LINE", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Neighbor specific description\n" "Up to 80 characters describing this neighbor\n") /* Neighbor update-source. */ static int peer_update_source_vty (struct vty *vty, const char *peer_str, const char *source_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, peer_str); if (! peer) return CMD_WARNING; if (source_str) { union sockunion su; int ret = str2sockunion (source_str, &su); if (ret == 0) peer_update_source_addr_set (peer, &su); else peer_update_source_if_set (peer, source_str); } else peer_update_source_unset (peer); return CMD_SUCCESS; } #define BGP_UPDATE_SOURCE_STR "(A.B.C.D|X:X::X:X|WORD)" #define BGP_UPDATE_SOURCE_HELP_STR \ "IPv4 address\n" \ "IPv6 address\n" \ "Interface name (requires zebra to be running)\n" DEFUN (neighbor_update_source, neighbor_update_source_cmd, NEIGHBOR_CMD2 "update-source " BGP_UPDATE_SOURCE_STR, NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Source of routing updates\n" BGP_UPDATE_SOURCE_HELP_STR) { return peer_update_source_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_update_source, no_neighbor_update_source_cmd, NO_NEIGHBOR_CMD2 "update-source", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Source of routing updates\n") { return peer_update_source_vty (vty, argv[0], NULL); } static int peer_default_originate_set_vty (struct vty *vty, const char *peer_str, afi_t afi, safi_t safi, const char *rmap, int set) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, peer_str); if (! peer) return CMD_WARNING; if (set) ret = peer_default_originate_set (peer, afi, safi, rmap); else ret = peer_default_originate_unset (peer, afi, safi); return bgp_vty_return (vty, ret); } /* neighbor default-originate. */ DEFUN (neighbor_default_originate, neighbor_default_originate_cmd, NEIGHBOR_CMD2 "default-originate", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Originate default route to this neighbor\n") { return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), NULL, 1); } DEFUN (neighbor_default_originate_rmap, neighbor_default_originate_rmap_cmd, NEIGHBOR_CMD2 "default-originate route-map WORD", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Originate default route to this neighbor\n" "Route-map to specify criteria to originate default\n" "route-map name\n") { return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], 1); } DEFUN (no_neighbor_default_originate, no_neighbor_default_originate_cmd, NO_NEIGHBOR_CMD2 "default-originate", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Originate default route to this neighbor\n") { return peer_default_originate_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), NULL, 0); } ALIAS (no_neighbor_default_originate, no_neighbor_default_originate_rmap_cmd, NO_NEIGHBOR_CMD2 "default-originate route-map WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Originate default route to this neighbor\n" "Route-map to specify criteria to originate default\n" "route-map name\n") /* Set neighbor's BGP port. */ static int peer_port_vty (struct vty *vty, const char *ip_str, int afi, const char *port_str) { struct peer *peer; u_int16_t port; struct servent *sp; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (! port_str) { sp = getservbyname ("bgp", "tcp"); port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); } else { VTY_GET_INTEGER("port", port, port_str); } peer_port_set (peer, port); return CMD_SUCCESS; } /* Set specified peer's BGP port. */ DEFUN (neighbor_port, neighbor_port_cmd, NEIGHBOR_CMD "port <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Neighbor's BGP port\n" "TCP port number\n") { return peer_port_vty (vty, argv[0], AFI_IP, argv[1]); } DEFUN (no_neighbor_port, no_neighbor_port_cmd, NO_NEIGHBOR_CMD "port", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Neighbor's BGP port\n") { return peer_port_vty (vty, argv[0], AFI_IP, NULL); } ALIAS (no_neighbor_port, no_neighbor_port_val_cmd, NO_NEIGHBOR_CMD "port <0-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Neighbor's BGP port\n" "TCP port number\n") /* neighbor weight. */ static int peer_weight_set_vty (struct vty *vty, const char *ip_str, const char *weight_str) { struct peer *peer; unsigned long weight; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE("weight", weight, weight_str, 0, 65535); return bgp_vty_return (vty, peer_weight_set (peer, weight)); } static int peer_weight_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_weight_unset (peer)); } DEFUN (neighbor_weight, neighbor_weight_cmd, NEIGHBOR_CMD2 "weight <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set default weight for routes from this neighbor\n" "default weight\n") { return peer_weight_set_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_weight, no_neighbor_weight_cmd, NO_NEIGHBOR_CMD2 "weight", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set default weight for routes from this neighbor\n") { return peer_weight_unset_vty (vty, argv[0]); } ALIAS (no_neighbor_weight, no_neighbor_weight_val_cmd, NO_NEIGHBOR_CMD2 "weight <0-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Set default weight for routes from this neighbor\n" "default weight\n") /* Override capability negotiation. */ DEFUN (neighbor_override_capability, neighbor_override_capability_cmd, NEIGHBOR_CMD2 "override-capability", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Override capability negotiation result\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); } DEFUN (no_neighbor_override_capability, no_neighbor_override_capability_cmd, NO_NEIGHBOR_CMD2 "override-capability", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Override capability negotiation result\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_OVERRIDE_CAPABILITY); } DEFUN (neighbor_strict_capability, neighbor_strict_capability_cmd, NEIGHBOR_CMD "strict-capability-match", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Strict capability negotiation match\n") { return peer_flag_set_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); } DEFUN (no_neighbor_strict_capability, no_neighbor_strict_capability_cmd, NO_NEIGHBOR_CMD "strict-capability-match", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Strict capability negotiation match\n") { return peer_flag_unset_vty (vty, argv[0], PEER_FLAG_STRICT_CAP_MATCH); } static int peer_timers_set_vty (struct vty *vty, const char *ip_str, const char *keep_str, const char *hold_str) { int ret; struct peer *peer; u_int32_t keepalive; u_int32_t holdtime; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("Keepalive", keepalive, keep_str, 0, 65535); VTY_GET_INTEGER_RANGE ("Holdtime", holdtime, hold_str, 0, 65535); ret = peer_timers_set (peer, keepalive, holdtime); return bgp_vty_return (vty, ret); } static int peer_timers_unset_vty (struct vty *vty, const char *ip_str) { int ret; struct peer *peer; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; ret = peer_timers_unset (peer); return bgp_vty_return (vty, ret); } DEFUN (neighbor_timers, neighbor_timers_cmd, NEIGHBOR_CMD2 "timers <0-65535> <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n" "Keepalive interval\n" "Holdtime\n") { return peer_timers_set_vty (vty, argv[0], argv[1], argv[2]); } DEFUN (no_neighbor_timers, no_neighbor_timers_cmd, NO_NEIGHBOR_CMD2 "timers", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "BGP per neighbor timers\n") { return peer_timers_unset_vty (vty, argv[0]); } static int peer_timers_connect_set_vty (struct vty *vty, const char *ip_str, const char *time_str) { struct peer *peer; u_int32_t connect; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("Connect time", connect, time_str, 0, 65535); return bgp_vty_return (vty, peer_timers_connect_set (peer, connect)); } static int peer_timers_connect_unset_vty (struct vty *vty, const char *ip_str) { struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_timers_connect_unset (peer)); } DEFUN (neighbor_timers_connect, neighbor_timers_connect_cmd, NEIGHBOR_CMD "timers connect <0-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") { return peer_timers_connect_set_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_timers_connect, no_neighbor_timers_connect_cmd, NO_NEIGHBOR_CMD "timers connect", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "BGP per neighbor timers\n" "BGP connect timer\n") { return peer_timers_connect_unset_vty (vty, argv[0]); } ALIAS (no_neighbor_timers_connect, no_neighbor_timers_connect_val_cmd, NO_NEIGHBOR_CMD "timers connect <0-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "BGP per neighbor timers\n" "BGP connect timer\n" "Connect timer\n") static int peer_advertise_interval_vty (struct vty *vty, const char *ip_str, const char *time_str, int set) { int ret; struct peer *peer; u_int32_t routeadv = 0; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (time_str) VTY_GET_INTEGER_RANGE ("advertise interval", routeadv, time_str, 0, 600); if (set) ret = peer_advertise_interval_set (peer, routeadv); else ret = peer_advertise_interval_unset (peer); return bgp_vty_return (vty, ret); } DEFUN (neighbor_advertise_interval, neighbor_advertise_interval_cmd, NEIGHBOR_CMD "advertisement-interval <0-600>", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n" "time in seconds\n") { return peer_advertise_interval_vty (vty, argv[0], argv[1], 1); } DEFUN (no_neighbor_advertise_interval, no_neighbor_advertise_interval_cmd, NO_NEIGHBOR_CMD "advertisement-interval", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n") { return peer_advertise_interval_vty (vty, argv[0], NULL, 0); } ALIAS (no_neighbor_advertise_interval, no_neighbor_advertise_interval_val_cmd, NO_NEIGHBOR_CMD "advertisement-interval <0-600>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Minimum interval between sending BGP routing updates\n" "time in seconds\n") /* neighbor interface */ static int peer_interface_vty (struct vty *vty, const char *ip_str, const char *str) { int ret; struct peer *peer; peer = peer_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; if (str) ret = peer_interface_set (peer, str); else ret = peer_interface_unset (peer); return bgp_vty_return (vty, ret); } DEFUN (neighbor_interface, neighbor_interface_cmd, NEIGHBOR_CMD "interface WORD", NEIGHBOR_STR NEIGHBOR_ADDR_STR "Interface\n" "Interface name\n") { return peer_interface_vty (vty, argv[0], argv[1]); } DEFUN (no_neighbor_interface, no_neighbor_interface_cmd, NO_NEIGHBOR_CMD "interface WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR "Interface\n" "Interface name\n") { return peer_interface_vty (vty, argv[0], NULL); } /* Set distribute list to the peer. */ static int peer_distribute_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_distribute_set (peer, afi, safi, direct, name_str); return bgp_vty_return (vty, ret); } static int peer_distribute_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_distribute_unset (peer, afi, safi, direct); return bgp_vty_return (vty, ret); } DEFUN (neighbor_distribute_list, neighbor_distribute_list_cmd, NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") { return peer_distribute_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2]); } DEFUN (no_neighbor_distribute_list, no_neighbor_distribute_list_cmd, NO_NEIGHBOR_CMD2 "distribute-list (<1-199>|<1300-2699>|WORD) (in|out)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") { return peer_distribute_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } /* Set prefix list to the peer. */ static int peer_prefix_list_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_prefix_list_set (peer, afi, safi, direct, name_str); return bgp_vty_return (vty, ret); } static int peer_prefix_list_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_prefix_list_unset (peer, afi, safi, direct); return bgp_vty_return (vty, ret); } DEFUN (neighbor_prefix_list, neighbor_prefix_list_cmd, NEIGHBOR_CMD2 "prefix-list WORD (in|out)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "Name of a prefix list\n" "Filter incoming updates\n" "Filter outgoing updates\n") { return peer_prefix_list_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2]); } DEFUN (no_neighbor_prefix_list, no_neighbor_prefix_list_cmd, NO_NEIGHBOR_CMD2 "prefix-list WORD (in|out)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" "Name of a prefix list\n" "Filter incoming updates\n" "Filter outgoing updates\n") { return peer_prefix_list_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } static int peer_aslist_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_aslist_set (peer, afi, safi, direct, name_str); return bgp_vty_return (vty, ret); } static int peer_aslist_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *direct_str) { int ret; struct peer *peer; int direct = FILTER_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "i", 1) == 0) direct = FILTER_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = FILTER_OUT; ret = peer_aslist_unset (peer, afi, safi, direct); return bgp_vty_return (vty, ret); } DEFUN (neighbor_filter_list, neighbor_filter_list_cmd, NEIGHBOR_CMD2 "filter-list WORD (in|out)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Establish BGP filters\n" "AS path access-list name\n" "Filter incoming routes\n" "Filter outgoing routes\n") { return peer_aslist_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2]); } DEFUN (no_neighbor_filter_list, no_neighbor_filter_list_cmd, NO_NEIGHBOR_CMD2 "filter-list WORD (in|out)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Establish BGP filters\n" "AS path access-list name\n" "Filter incoming routes\n" "Filter outgoing routes\n") { return peer_aslist_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } /* Set route-map to the peer. */ static int peer_route_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str, const char *direct_str) { int ret; struct peer *peer; int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "in", 2) == 0) direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RMAP_OUT; else if (strncmp (direct_str, "im", 2) == 0) direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; ret = peer_route_map_set (peer, afi, safi, direct, name_str); return bgp_vty_return (vty, ret); } static int peer_route_map_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *direct_str) { int ret; struct peer *peer; int direct = RMAP_IN; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; /* Check filter direction. */ if (strncmp (direct_str, "in", 2) == 0) direct = RMAP_IN; else if (strncmp (direct_str, "o", 1) == 0) direct = RMAP_OUT; else if (strncmp (direct_str, "im", 2) == 0) direct = RMAP_IMPORT; else if (strncmp (direct_str, "e", 1) == 0) direct = RMAP_EXPORT; ret = peer_route_map_unset (peer, afi, safi, direct); return bgp_vty_return (vty, ret); } DEFUN (neighbor_route_map, neighbor_route_map_cmd, NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") { return peer_route_map_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2]); } DEFUN (no_neighbor_route_map, no_neighbor_route_map_cmd, NO_NEIGHBOR_CMD2 "route-map WORD (in|out|import|export)", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Apply route map to neighbor\n" "Name of route map\n" "Apply map to incoming routes\n" "Apply map to outbound routes\n" "Apply map to routes going into a Route-Server client's table\n" "Apply map to routes coming from a Route-Server client") { return peer_route_map_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[2]); } /* Set unsuppress-map to the peer. */ static int peer_unsuppress_map_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *name_str) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; ret = peer_unsuppress_map_set (peer, afi, safi, name_str); return bgp_vty_return (vty, ret); } /* Unset route-map from the peer. */ static int peer_unsuppress_map_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; ret = peer_unsuppress_map_unset (peer, afi, safi); return bgp_vty_return (vty, ret); } DEFUN (neighbor_unsuppress_map, neighbor_unsuppress_map_cmd, NEIGHBOR_CMD2 "unsuppress-map WORD", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to selectively unsuppress suppressed routes\n" "Name of route map\n") { return peer_unsuppress_map_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1]); } DEFUN (no_neighbor_unsuppress_map, no_neighbor_unsuppress_map_cmd, NO_NEIGHBOR_CMD2 "unsuppress-map WORD", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Route-map to selectively unsuppress suppressed routes\n" "Name of route map\n") { return peer_unsuppress_map_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty)); } static int peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi, const char *num_str, const char *threshold_str, int warning, const char *restart_str) { int ret; struct peer *peer; u_int32_t max; u_char threshold; u_int16_t restart; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; VTY_GET_INTEGER ("maximum number", max, num_str); if (threshold_str) threshold = atoi (threshold_str); else threshold = MAXIMUM_PREFIX_THRESHOLD_DEFAULT; if (restart_str) restart = atoi (restart_str); else restart = 0; ret = peer_maximum_prefix_set (peer, afi, safi, max, threshold, warning, restart); return bgp_vty_return (vty, ret); } static int peer_maximum_prefix_unset_vty (struct vty *vty, const char *ip_str, afi_t afi, safi_t safi) { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, ip_str); if (! peer) return CMD_WARNING; ret = peer_maximum_prefix_unset (peer, afi, safi); return bgp_vty_return (vty, ret); } /* Maximum number of prefix configuration. prefix count is different for each peer configuration. So this configuration can be set for each peer configuration. */ DEFUN (neighbor_maximum_prefix, neighbor_maximum_prefix_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], NULL, 0, NULL); } DEFUN (neighbor_maximum_prefix_threshold, neighbor_maximum_prefix_threshold_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2], 0, NULL); } DEFUN (neighbor_maximum_prefix_warning, neighbor_maximum_prefix_warning_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Only give warning message when limit is exceeded\n") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], NULL, 1, NULL); } DEFUN (neighbor_maximum_prefix_threshold_warning, neighbor_maximum_prefix_threshold_warning_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> warning-only", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Only give warning message when limit is exceeded\n") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2], 1, NULL); } DEFUN (neighbor_maximum_prefix_restart, neighbor_maximum_prefix_restart_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> restart <1-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], NULL, 0, argv[2]); } DEFUN (neighbor_maximum_prefix_threshold_restart, neighbor_maximum_prefix_threshold_restart_cmd, NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") { return peer_maximum_prefix_set_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty), argv[1], argv[2], 0, argv[3]); } DEFUN (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n") { return peer_maximum_prefix_unset_vty (vty, argv[0], bgp_node_afi (vty), bgp_node_safi (vty)); } ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_val_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n") ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_threshold_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n") ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_warning_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> warning-only", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Only give warning message when limit is exceeded\n") ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_threshold_warning_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> warning-only", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Only give warning message when limit is exceeded\n") ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_restart_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> restart <1-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") ALIAS (no_neighbor_maximum_prefix, no_neighbor_maximum_prefix_threshold_restart_cmd, NO_NEIGHBOR_CMD2 "maximum-prefix <1-4294967295> <1-100> restart <1-65535>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Maximum number of prefix accept from this peer\n" "maximum no. of prefix limit\n" "Threshold value (%) at which to generate a warning msg\n" "Restart bgp connection after limit is exceeded\n" "Restart interval in minutes") /* "neighbor allowas-in" */ DEFUN (neighbor_allowas_in, neighbor_allowas_in_cmd, NEIGHBOR_CMD2 "allowas-in", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Accept as-path with my AS present in it\n") { int ret; struct peer *peer; unsigned int allow_num; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; if (argc == 1) allow_num = 3; else VTY_GET_INTEGER_RANGE ("AS number", allow_num, argv[1], 1, 10); ret = peer_allowas_in_set (peer, bgp_node_afi (vty), bgp_node_safi (vty), allow_num); return bgp_vty_return (vty, ret); } ALIAS (neighbor_allowas_in, neighbor_allowas_in_arg_cmd, NEIGHBOR_CMD2 "allowas-in <1-10>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Accept as-path with my AS present in it\n" "Number of occurances of AS number\n") DEFUN (no_neighbor_allowas_in, no_neighbor_allowas_in_cmd, NO_NEIGHBOR_CMD2 "allowas-in", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "allow local ASN appears in aspath attribute\n") { int ret; struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; ret = peer_allowas_in_unset (peer, bgp_node_afi (vty), bgp_node_safi (vty)); return bgp_vty_return (vty, ret); } DEFUN (neighbor_ttl_security, neighbor_ttl_security_cmd, NEIGHBOR_CMD2 "ttl-security hops <1-254>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify the maximum number of hops to the BGP peer\n") { struct peer *peer; int gtsm_hops; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254); return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, gtsm_hops)); } DEFUN (no_neighbor_ttl_security, no_neighbor_ttl_security_cmd, NO_NEIGHBOR_CMD2 "ttl-security hops <1-254>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Specify the maximum number of hops to the BGP peer\n") { struct peer *peer; peer = peer_and_group_lookup_vty (vty, argv[0]); if (! peer) return CMD_WARNING; return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer)); } /* Address family configuration. */ DEFUN (address_family_ipv4, address_family_ipv4_cmd, "address-family ipv4", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_IPV4_NODE; return CMD_SUCCESS; } DEFUN (address_family_ipv4_safi, address_family_ipv4_safi_cmd, "address-family ipv4 (unicast|multicast)", "Enter Address Family command mode\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") { if (strncmp (argv[0], "m", 1) == 0) vty->node = BGP_IPV4M_NODE; else vty->node = BGP_IPV4_NODE; return CMD_SUCCESS; } DEFUN (address_family_ipv6, address_family_ipv6_cmd, "address-family ipv6", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_IPV6_NODE; return CMD_SUCCESS; } DEFUN (address_family_ipv6_safi, address_family_ipv6_safi_cmd, "address-family ipv6 (unicast|multicast)", "Enter Address Family command mode\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n") { if (strncmp (argv[0], "m", 1) == 0) vty->node = BGP_IPV6M_NODE; else vty->node = BGP_IPV6_NODE; return CMD_SUCCESS; } DEFUN (address_family_vpnv4, address_family_vpnv4_cmd, "address-family vpnv4", "Enter Address Family command mode\n" "Address family\n") { vty->node = BGP_VPNV4_NODE; return CMD_SUCCESS; } ALIAS (address_family_vpnv4, address_family_vpnv4_unicast_cmd, "address-family vpnv4 unicast", "Enter Address Family command mode\n" "Address family\n" "Address Family Modifier\n") DEFUN (exit_address_family, exit_address_family_cmd, "exit-address-family", "Exit from Address Family configuration mode\n") { if (vty->node == BGP_IPV4_NODE || vty->node == BGP_IPV4M_NODE || vty->node == BGP_VPNV4_NODE || vty->node == BGP_IPV6_NODE || vty->node == BGP_IPV6M_NODE) vty->node = BGP_NODE; return CMD_SUCCESS; } /* BGP clear sort. */ enum clear_sort { clear_all, clear_peer, clear_group, clear_external, clear_as }; static void bgp_clear_vty_error (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int error) { switch (error) { case BGP_ERR_AF_UNCONFIGURED: vty_out (vty, "%%BGP: Enable %s %s address family for the neighbor %s%s", afi == AFI_IP6 ? "IPv6" : safi == SAFI_MPLS_VPN ? "VPNv4" : "IPv4", safi == SAFI_MULTICAST ? "Multicast" : "Unicast", peer->host, VTY_NEWLINE); break; case BGP_ERR_SOFT_RECONFIG_UNCONFIGURED: vty_out (vty, "%%BGP: Inbound soft reconfig for %s not possible as it%s has neither refresh capability, nor inbound soft reconfig%s", peer->host, VTY_NEWLINE, VTY_NEWLINE); break; default: break; } } /* `clear ip bgp' functions. */ static int bgp_clear (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum clear_sort sort,enum bgp_clear_type stype, const char *arg) { int ret; struct peer *peer; struct listnode *node, *nnode; /* Clear all neighbors. */ if (sort == clear_all) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear (peer); else ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); } return CMD_SUCCESS; } /* Clear specified neighbors. */ if (sort == clear_peer) { union sockunion su; int ret; /* Make sockunion for lookup. */ ret = str2sockunion (arg, &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", arg, VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (bgp, &su); if (! peer) { vty_out (vty, "%%BGP: Unknown neighbor - \"%s\"%s", arg, VTY_NEWLINE); return CMD_WARNING; } if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear (peer); else ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); return CMD_SUCCESS; } /* Clear all peer-group members. */ if (sort == clear_group) { struct peer_group *group; group = peer_group_lookup (bgp, arg); if (! group) { vty_out (vty, "%%BGP: No such peer-group %s%s", arg, VTY_NEWLINE); return CMD_WARNING; } for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (stype == BGP_CLEAR_SOFT_NONE) { ret = peer_clear (peer); continue; } if (! peer->af_group[afi][safi]) continue; ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); } return CMD_SUCCESS; } if (sort == clear_external) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear (peer); else ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); } return CMD_SUCCESS; } if (sort == clear_as) { as_t as; int find = 0; VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as != as) continue; find = 1; if (stype == BGP_CLEAR_SOFT_NONE) ret = peer_clear (peer); else ret = peer_clear_soft (peer, afi, safi, stype); if (ret < 0) bgp_clear_vty_error (vty, peer, afi, safi, ret); } if (! find) vty_out (vty, "%%BGP: No peer is configured with AS %s%s", arg, VTY_NEWLINE); return CMD_SUCCESS; } return CMD_SUCCESS; } static int bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, enum clear_sort sort, enum bgp_clear_type stype, const char *arg) { struct bgp *bgp; /* BGP structure lookup. */ if (name) { bgp = bgp_lookup_by_name (name); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", name, VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } return bgp_clear (vty, bgp, afi, safi, sort, stype, arg); } DEFUN (clear_ip_bgp_all, clear_ip_bgp_all_cmd, "clear ip bgp *", CLEAR_STR IP_STR BGP_STR "Clear all peers\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL); return bgp_clear_vty (vty, NULL, 0, 0, clear_all, BGP_CLEAR_SOFT_NONE, NULL); } ALIAS (clear_ip_bgp_all, clear_bgp_all_cmd, "clear bgp *", CLEAR_STR BGP_STR "Clear all peers\n") ALIAS (clear_ip_bgp_all, clear_bgp_ipv6_all_cmd, "clear bgp ipv6 *", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n") ALIAS (clear_ip_bgp_all, clear_ip_bgp_instance_all_cmd, "clear ip bgp view WORD *", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n") ALIAS (clear_ip_bgp_all, clear_bgp_instance_all_cmd, "clear bgp view WORD *", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n") DEFUN (clear_ip_bgp_peer, clear_ip_bgp_peer_cmd, "clear ip bgp (A.B.C.D|X:X::X:X)", CLEAR_STR IP_STR BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n") { return bgp_clear_vty (vty, NULL, 0, 0, clear_peer, BGP_CLEAR_SOFT_NONE, argv[0]); } ALIAS (clear_ip_bgp_peer, clear_bgp_peer_cmd, "clear bgp (A.B.C.D|X:X::X:X)", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n") ALIAS (clear_ip_bgp_peer, clear_bgp_ipv6_peer_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X)", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n") DEFUN (clear_ip_bgp_peer_group, clear_ip_bgp_peer_group_cmd, "clear ip bgp peer-group WORD", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n") { return bgp_clear_vty (vty, NULL, 0, 0, clear_group, BGP_CLEAR_SOFT_NONE, argv[0]); } ALIAS (clear_ip_bgp_peer_group, clear_bgp_peer_group_cmd, "clear bgp peer-group WORD", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n") ALIAS (clear_ip_bgp_peer_group, clear_bgp_ipv6_peer_group_cmd, "clear bgp ipv6 peer-group WORD", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n") DEFUN (clear_ip_bgp_external, clear_ip_bgp_external_cmd, "clear ip bgp external", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n") { return bgp_clear_vty (vty, NULL, 0, 0, clear_external, BGP_CLEAR_SOFT_NONE, NULL); } ALIAS (clear_ip_bgp_external, clear_bgp_external_cmd, "clear bgp external", CLEAR_STR BGP_STR "Clear all external peers\n") ALIAS (clear_ip_bgp_external, clear_bgp_ipv6_external_cmd, "clear bgp ipv6 external", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n") DEFUN (clear_ip_bgp_as, clear_ip_bgp_as_cmd, "clear ip bgp " CMD_AS_RANGE, CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n") { return bgp_clear_vty (vty, NULL, 0, 0, clear_as, BGP_CLEAR_SOFT_NONE, argv[0]); } ALIAS (clear_ip_bgp_as, clear_bgp_as_cmd, "clear bgp " CMD_AS_RANGE, CLEAR_STR BGP_STR "Clear peers with the AS number\n") ALIAS (clear_ip_bgp_as, clear_bgp_ipv6_as_cmd, "clear bgp ipv6 " CMD_AS_RANGE, CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n") /* Outbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_out, clear_ip_bgp_all_soft_out_cmd, "clear ip bgp * soft out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_soft_out, clear_ip_bgp_all_out_cmd, "clear ip bgp * out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig outbound update\n") ALIAS (clear_ip_bgp_all_soft_out, clear_ip_bgp_instance_all_soft_out_cmd, "clear ip bgp view WORD * soft out", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_all_ipv4_soft_out, clear_ip_bgp_all_ipv4_soft_out_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_ipv4_soft_out, clear_ip_bgp_all_ipv4_out_cmd, "clear ip bgp * ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_instance_all_ipv4_soft_out, clear_ip_bgp_instance_all_ipv4_soft_out_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft_out, clear_ip_bgp_all_vpnv4_soft_out_cmd, "clear ip bgp * vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_all_vpnv4_soft_out, clear_ip_bgp_all_vpnv4_out_cmd, "clear ip bgp * vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_all_soft_out, clear_bgp_all_soft_out_cmd, "clear bgp * soft out", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_bgp_all_soft_out, clear_bgp_instance_all_soft_out_cmd, "clear bgp view WORD * soft out", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_all_out_cmd, "clear bgp * out", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_soft_out_cmd, "clear bgp ipv6 * soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_all_soft_out, clear_bgp_ipv6_all_out_cmd, "clear bgp ipv6 * out", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_soft_out, clear_ip_bgp_peer_soft_out_cmd, "clear ip bgp A.B.C.D soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_soft_out, clear_ip_bgp_peer_out_cmd, "clear ip bgp A.B.C.D out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_ipv4_soft_out, clear_ip_bgp_peer_ipv4_soft_out_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_ipv4_soft_out, clear_ip_bgp_peer_ipv4_out_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_vpnv4_soft_out, clear_ip_bgp_peer_vpnv4_soft_out_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_vpnv4_soft_out, clear_ip_bgp_peer_vpnv4_out_cmd, "clear ip bgp A.B.C.D vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_peer_soft_out, clear_bgp_peer_soft_out_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft out", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_peer_soft_out, clear_bgp_ipv6_peer_soft_out_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft out", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_soft_out, clear_bgp_peer_out_cmd, "clear bgp (A.B.C.D|X:X::X:X) out", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_soft_out, clear_bgp_ipv6_peer_out_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) out", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_group_soft_out, clear_ip_bgp_peer_group_soft_out_cmd, "clear ip bgp peer-group WORD soft out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_group_soft_out, clear_ip_bgp_peer_group_out_cmd, "clear ip bgp peer-group WORD out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_peer_group_ipv4_soft_out, clear_ip_bgp_peer_group_ipv4_soft_out_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_peer_group_ipv4_soft_out, clear_ip_bgp_peer_group_ipv4_out_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_soft_out_cmd, "clear bgp peer-group WORD soft out", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_ipv6_peer_group_soft_out_cmd, "clear bgp ipv6 peer-group WORD soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_peer_group_out_cmd, "clear bgp peer-group WORD out", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_peer_group_soft_out, clear_bgp_ipv6_peer_group_out_cmd, "clear bgp ipv6 peer-group WORD out", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_external_soft_out, clear_ip_bgp_external_soft_out_cmd, "clear ip bgp external soft out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_external_soft_out, clear_ip_bgp_external_out_cmd, "clear ip bgp external out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_external_ipv4_soft_out, clear_ip_bgp_external_ipv4_soft_out_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_ip_bgp_external_ipv4_soft_out, clear_ip_bgp_external_ipv4_out_cmd, "clear ip bgp external ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_external_soft_out, clear_bgp_external_soft_out_cmd, "clear bgp external soft out", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_OUT, NULL); } ALIAS (clear_bgp_external_soft_out, clear_bgp_ipv6_external_soft_out_cmd, "clear bgp ipv6 external soft out", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_external_soft_out, clear_bgp_external_out_cmd, "clear bgp external out", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_external_soft_out, clear_bgp_ipv6_external_out_cmd, "clear bgp ipv6 external WORD out", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_soft_out, clear_ip_bgp_as_out_cmd, "clear ip bgp " CMD_AS_RANGE " out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_ipv4_soft_out, clear_ip_bgp_as_ipv4_out_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_ip_bgp_as_vpnv4_soft_out, clear_ip_bgp_as_vpnv4_soft_out_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast soft out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_ip_bgp_as_vpnv4_soft_out, clear_ip_bgp_as_vpnv4_out_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast out", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig outbound update\n") DEFUN (clear_bgp_as_soft_out, clear_bgp_as_soft_out_cmd, "clear bgp " CMD_AS_RANGE " soft out", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_OUT, argv[0]); } ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_soft_out_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_as_soft_out, clear_bgp_as_out_cmd, "clear bgp " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig outbound update\n") ALIAS (clear_bgp_as_soft_out, clear_bgp_ipv6_as_out_cmd, "clear bgp ipv6 " CMD_AS_RANGE " out", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig outbound update\n") /* Inbound soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_soft_in_cmd, "clear ip bgp * soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_soft_in, clear_ip_bgp_instance_all_soft_in_cmd, "clear ip bgp view WORD * soft in", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_ip_bgp_all_soft_in, clear_ip_bgp_all_in_cmd, "clear ip bgp * in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_all_in_prefix_filter, clear_ip_bgp_all_in_prefix_filter_cmd, "clear ip bgp * in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (argc== 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_ip_bgp_all_in_prefix_filter, clear_ip_bgp_instance_all_in_prefix_filter_cmd, "clear ip bgp view WORD * in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_all_ipv4_soft_in, clear_ip_bgp_all_ipv4_soft_in_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_ipv4_soft_in, clear_ip_bgp_all_ipv4_in_cmd, "clear ip bgp * ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_instance_all_ipv4_soft_in, clear_ip_bgp_instance_all_ipv4_soft_in_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } DEFUN (clear_ip_bgp_all_ipv4_in_prefix_filter, clear_ip_bgp_all_ipv4_in_prefix_filter_cmd, "clear ip bgp * ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_instance_all_ipv4_in_prefix_filter, clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft_in, clear_ip_bgp_all_vpnv4_soft_in_cmd, "clear ip bgp * vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_all_vpnv4_soft_in, clear_ip_bgp_all_vpnv4_in_cmd, "clear ip bgp * vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_all_soft_in, clear_bgp_all_soft_in_cmd, "clear bgp * soft in", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_bgp_all_soft_in, clear_bgp_instance_all_soft_in_cmd, "clear bgp view WORD * soft in", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_soft_in_cmd, "clear bgp ipv6 * soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_all_in_cmd, "clear bgp * in", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_all_soft_in, clear_bgp_ipv6_all_in_cmd, "clear bgp ipv6 * in", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_all_in_prefix_filter, clear_bgp_all_in_prefix_filter_cmd, "clear bgp * in prefix-filter", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_bgp_all_in_prefix_filter, clear_bgp_ipv6_all_in_prefix_filter_cmd, "clear bgp ipv6 * in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_peer_soft_in, clear_ip_bgp_peer_soft_in_cmd, "clear ip bgp A.B.C.D soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_soft_in, clear_ip_bgp_peer_in_cmd, "clear ip bgp A.B.C.D in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_in_prefix_filter, clear_ip_bgp_peer_in_prefix_filter_cmd, "clear ip bgp A.B.C.D in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_ipv4_soft_in, clear_ip_bgp_peer_ipv4_soft_in_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_ipv4_soft_in, clear_ip_bgp_peer_ipv4_in_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_ipv4_in_prefix_filter, clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_vpnv4_soft_in, clear_ip_bgp_peer_vpnv4_soft_in_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_vpnv4_soft_in, clear_ip_bgp_peer_vpnv4_in_cmd, "clear ip bgp A.B.C.D vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_soft_in, clear_bgp_peer_soft_in_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft in", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_peer_soft_in, clear_bgp_ipv6_peer_soft_in_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft in", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_soft_in, clear_bgp_peer_in_cmd, "clear bgp (A.B.C.D|X:X::X:X) in", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_soft_in, clear_bgp_ipv6_peer_in_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_in_prefix_filter, clear_bgp_peer_in_prefix_filter_cmd, "clear bgp (A.B.C.D|X:X::X:X) in prefix-filter", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_peer_in_prefix_filter, clear_bgp_ipv6_peer_in_prefix_filter_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig inbound update\n" "Push out the existing ORF prefix-list\n") DEFUN (clear_ip_bgp_peer_group_soft_in, clear_ip_bgp_peer_group_soft_in_cmd, "clear ip bgp peer-group WORD soft in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_group_soft_in, clear_ip_bgp_peer_group_in_cmd, "clear ip bgp peer-group WORD in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_group_in_prefix_filter, clear_ip_bgp_peer_group_in_prefix_filter_cmd, "clear ip bgp peer-group WORD in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_peer_group_ipv4_soft_in, clear_ip_bgp_peer_group_ipv4_soft_in_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_peer_group_ipv4_soft_in, clear_ip_bgp_peer_group_ipv4_in_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_peer_group_ipv4_in_prefix_filter, clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_bgp_peer_group_soft_in, clear_bgp_peer_group_soft_in_cmd, "clear bgp peer-group WORD soft in", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_ipv6_peer_group_soft_in_cmd, "clear bgp ipv6 peer-group WORD soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_peer_group_in_cmd, "clear bgp peer-group WORD in", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_peer_group_soft_in, clear_bgp_ipv6_peer_group_in_cmd, "clear bgp ipv6 peer-group WORD in", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_peer_group_in_prefix_filter, clear_bgp_peer_group_in_prefix_filter_cmd, "clear bgp peer-group WORD in prefix-filter", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_peer_group_in_prefix_filter, clear_bgp_ipv6_peer_group_in_prefix_filter_cmd, "clear bgp ipv6 peer-group WORD in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_external_soft_in, clear_ip_bgp_external_soft_in_cmd, "clear ip bgp external soft in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_external_soft_in, clear_ip_bgp_external_in_cmd, "clear ip bgp external in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_external_in_prefix_filter, clear_ip_bgp_external_in_prefix_filter_cmd, "clear ip bgp external in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_ip_bgp_external_ipv4_soft_in, clear_ip_bgp_external_ipv4_soft_in_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_ip_bgp_external_ipv4_soft_in, clear_ip_bgp_external_ipv4_in_cmd, "clear ip bgp external ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_external_ipv4_in_prefix_filter, clear_ip_bgp_external_ipv4_in_prefix_filter_cmd, "clear ip bgp external ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } DEFUN (clear_bgp_external_soft_in, clear_bgp_external_soft_in_cmd, "clear bgp external soft in", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN, NULL); } ALIAS (clear_bgp_external_soft_in, clear_bgp_ipv6_external_soft_in_cmd, "clear bgp ipv6 external soft in", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_external_soft_in, clear_bgp_external_in_cmd, "clear bgp external in", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_external_soft_in, clear_bgp_ipv6_external_in_cmd, "clear bgp ipv6 external WORD in", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_external_in_prefix_filter, clear_bgp_external_in_prefix_filter_cmd, "clear bgp external in prefix-filter", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_IN_ORF_PREFIX, NULL); } ALIAS (clear_bgp_external_in_prefix_filter, clear_bgp_ipv6_external_in_prefix_filter_cmd, "clear bgp ipv6 external in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") DEFUN (clear_ip_bgp_as_soft_in, clear_ip_bgp_as_soft_in_cmd, "clear ip bgp " CMD_AS_RANGE " soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_soft_in, clear_ip_bgp_as_in_cmd, "clear ip bgp " CMD_AS_RANGE " in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_as_in_prefix_filter, clear_ip_bgp_as_in_prefix_filter_cmd, "clear ip bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_as_ipv4_soft_in, clear_ip_bgp_as_ipv4_soft_in_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_ipv4_soft_in, clear_ip_bgp_as_ipv4_in_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_ip_bgp_as_ipv4_in_prefix_filter, clear_ip_bgp_as_ipv4_in_prefix_filter_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) in prefix-filter", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } DEFUN (clear_ip_bgp_as_vpnv4_soft_in, clear_ip_bgp_as_vpnv4_soft_in_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast soft in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_ip_bgp_as_vpnv4_soft_in, clear_ip_bgp_as_vpnv4_in_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast in", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family modifier\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_as_soft_in, clear_bgp_as_soft_in_cmd, "clear bgp " CMD_AS_RANGE " soft in", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN, argv[0]); } ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_soft_in_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_as_soft_in, clear_bgp_as_in_cmd, "clear bgp " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n") ALIAS (clear_bgp_as_soft_in, clear_bgp_ipv6_as_in_cmd, "clear bgp ipv6 " CMD_AS_RANGE " in", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n") DEFUN (clear_bgp_as_in_prefix_filter, clear_bgp_as_in_prefix_filter_cmd, "clear bgp " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_IN_ORF_PREFIX, argv[0]); } ALIAS (clear_bgp_as_in_prefix_filter, clear_bgp_ipv6_as_in_prefix_filter_cmd, "clear bgp ipv6 " CMD_AS_RANGE " in prefix-filter", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig inbound update\n" "Push out prefix-list ORF and do inbound soft reconfig\n") /* Both soft-reconfiguration */ DEFUN (clear_ip_bgp_all_soft, clear_ip_bgp_all_soft_cmd, "clear ip bgp * soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } ALIAS (clear_ip_bgp_all_soft, clear_ip_bgp_instance_all_soft_cmd, "clear ip bgp view WORD * soft", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_all_ipv4_soft, clear_ip_bgp_all_ipv4_soft_cmd, "clear ip bgp * ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_instance_all_ipv4_soft, clear_ip_bgp_instance_all_ipv4_soft_cmd, "clear ip bgp view WORD * ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_all_vpnv4_soft, clear_ip_bgp_all_vpnv4_soft_cmd, "clear ip bgp * vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_all_soft, clear_bgp_all_soft_cmd, "clear bgp * soft", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_all_soft, clear_bgp_instance_all_soft_cmd, "clear bgp view WORD * soft", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig\n") ALIAS (clear_bgp_all_soft, clear_bgp_ipv6_all_soft_cmd, "clear bgp ipv6 * soft", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_peer_soft, clear_ip_bgp_peer_soft_cmd, "clear ip bgp A.B.C.D soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_ipv4_soft, clear_ip_bgp_peer_ipv4_soft_cmd, "clear ip bgp A.B.C.D ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_vpnv4_soft, clear_ip_bgp_peer_vpnv4_soft_cmd, "clear ip bgp A.B.C.D vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "BGP neighbor address to clear\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_peer_soft, clear_bgp_peer_soft_cmd, "clear bgp (A.B.C.D|X:X::X:X) soft", CLEAR_STR BGP_STR "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_peer_soft, clear_bgp_ipv6_peer_soft_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) soft", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_peer_group_soft, clear_ip_bgp_peer_group_soft_cmd, "clear ip bgp peer-group WORD soft", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_peer_group_ipv4_soft, clear_ip_bgp_peer_group_ipv4_soft_cmd, "clear ip bgp peer-group WORD ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_peer_group_soft, clear_bgp_peer_group_soft_cmd, "clear bgp peer-group WORD soft", CLEAR_STR BGP_STR "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_group, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_peer_group_soft, clear_bgp_ipv6_peer_group_soft_cmd, "clear bgp ipv6 peer-group WORD soft", CLEAR_STR BGP_STR "Address family\n" "Clear all members of peer-group\n" "BGP peer-group name\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_external_soft, clear_ip_bgp_external_soft_cmd, "clear ip bgp external soft", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_ip_bgp_external_ipv4_soft, clear_ip_bgp_external_ipv4_soft_cmd, "clear ip bgp external ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear all external peers\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Soft reconfig\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } DEFUN (clear_bgp_external_soft, clear_bgp_external_soft_cmd, "clear bgp external soft", CLEAR_STR BGP_STR "Clear all external peers\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_external, BGP_CLEAR_SOFT_BOTH, NULL); } ALIAS (clear_bgp_external_soft, clear_bgp_ipv6_external_soft_cmd, "clear bgp ipv6 external soft", CLEAR_STR BGP_STR "Address family\n" "Clear all external peers\n" "Soft reconfig\n") DEFUN (clear_ip_bgp_as_soft, clear_ip_bgp_as_soft_cmd, "clear ip bgp " CMD_AS_RANGE " soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_as_ipv4_soft, clear_ip_bgp_as_ipv4_soft_cmd, "clear ip bgp " CMD_AS_RANGE " ipv4 (unicast|multicast) soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" "Address Family Modifier\n" "Soft reconfig\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MULTICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); return bgp_clear_vty (vty, NULL,AFI_IP, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_ip_bgp_as_vpnv4_soft, clear_ip_bgp_as_vpnv4_soft_cmd, "clear ip bgp " CMD_AS_RANGE " vpnv4 unicast soft", CLEAR_STR IP_STR BGP_STR "Clear peers with the AS number\n" "Address family\n" "Address Family Modifier\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } DEFUN (clear_bgp_as_soft, clear_bgp_as_soft_cmd, "clear bgp " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Clear peers with the AS number\n" "Soft reconfig\n") { return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_as, BGP_CLEAR_SOFT_BOTH, argv[0]); } ALIAS (clear_bgp_as_soft, clear_bgp_ipv6_as_soft_cmd, "clear bgp ipv6 " CMD_AS_RANGE " soft", CLEAR_STR BGP_STR "Address family\n" "Clear peers with the AS number\n" "Soft reconfig\n") /* RS-client soft reconfiguration. */ #ifdef HAVE_IPV6 DEFUN (clear_bgp_all_rsclient, clear_bgp_all_rsclient_cmd, "clear bgp * rsclient", CLEAR_STR BGP_STR "Clear all peers\n" "Soft reconfig for rsclient RIB\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); } ALIAS (clear_bgp_all_rsclient, clear_bgp_ipv6_all_rsclient_cmd, "clear bgp ipv6 * rsclient", CLEAR_STR BGP_STR "Address family\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") ALIAS (clear_bgp_all_rsclient, clear_bgp_instance_all_rsclient_cmd, "clear bgp view WORD * rsclient", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") ALIAS (clear_bgp_all_rsclient, clear_bgp_ipv6_instance_all_rsclient_cmd, "clear bgp ipv6 view WORD * rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") #endif /* HAVE_IPV6 */ DEFUN (clear_ip_bgp_all_rsclient, clear_ip_bgp_all_rsclient_cmd, "clear ip bgp * rsclient", CLEAR_STR IP_STR BGP_STR "Clear all peers\n" "Soft reconfig for rsclient RIB\n") { if (argc == 1) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_all, BGP_CLEAR_SOFT_RSCLIENT, NULL); } ALIAS (clear_ip_bgp_all_rsclient, clear_ip_bgp_instance_all_rsclient_cmd, "clear ip bgp view WORD * rsclient", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "Clear all peers\n" "Soft reconfig for rsclient RIB\n") #ifdef HAVE_IPV6 DEFUN (clear_bgp_peer_rsclient, clear_bgp_peer_rsclient_cmd, "clear bgp (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[1]); return bgp_clear_vty (vty, NULL, AFI_IP6, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[0]); } ALIAS (clear_bgp_peer_rsclient, clear_bgp_ipv6_peer_rsclient_cmd, "clear bgp ipv6 (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") ALIAS (clear_bgp_peer_rsclient, clear_bgp_instance_peer_rsclient_cmd, "clear bgp view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") ALIAS (clear_bgp_peer_rsclient, clear_bgp_ipv6_instance_peer_rsclient_cmd, "clear bgp ipv6 view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR BGP_STR "Address family\n" "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") #endif /* HAVE_IPV6 */ DEFUN (clear_ip_bgp_peer_rsclient, clear_ip_bgp_peer_rsclient_cmd, "clear ip bgp (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR IP_STR BGP_STR "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") { if (argc == 2) return bgp_clear_vty (vty, argv[0], AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[1]); return bgp_clear_vty (vty, NULL, AFI_IP, SAFI_UNICAST, clear_peer, BGP_CLEAR_SOFT_RSCLIENT, argv[0]); } ALIAS (clear_ip_bgp_peer_rsclient, clear_ip_bgp_instance_peer_rsclient_cmd, "clear ip bgp view WORD (A.B.C.D|X:X::X:X) rsclient", CLEAR_STR IP_STR BGP_STR "BGP view\n" "view name\n" "BGP neighbor IP address to clear\n" "BGP IPv6 neighbor to clear\n" "Soft reconfig for rsclient RIB\n") DEFUN (show_bgp_views, show_bgp_views_cmd, "show bgp views", SHOW_STR BGP_STR "Show the defined BGP views\n") { struct list *inst = bm->bgp; struct listnode *node; struct bgp *bgp; if (!bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) { vty_out (vty, "Multiple BGP views are not defined%s", VTY_NEWLINE); return CMD_WARNING; } vty_out (vty, "Defined BGP views:%s", VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO(inst, node, bgp)) vty_out (vty, "\t%s (AS%u)%s", bgp->name ? bgp->name : "(null)", bgp->as, VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (show_bgp_memory, show_bgp_memory_cmd, "show bgp memory", SHOW_STR BGP_STR "Global BGP memory statistics\n") { char memstrbuf[MTYPE_MEMSTR_LEN]; unsigned long count; /* RIB related usage stats */ count = mtype_stats_alloc (MTYPE_BGP_NODE); vty_out (vty, "%ld RIB nodes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_node)), VTY_NEWLINE); count = mtype_stats_alloc (MTYPE_BGP_ROUTE); vty_out (vty, "%ld BGP routes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_info)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_ROUTE_EXTRA))) vty_out (vty, "%ld BGP route ancillaries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_info_extra)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_STATIC))) vty_out (vty, "%ld Static routes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_static)), VTY_NEWLINE); /* Adj-In/Out */ if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_IN))) vty_out (vty, "%ld Adj-In entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_adj_in)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_OUT))) vty_out (vty, "%ld Adj-Out entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_adj_out)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_NEXTHOP_CACHE))) vty_out (vty, "%ld Nexthop cache entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_nexthop_cache)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_DAMP_INFO))) vty_out (vty, "%ld Dampening entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct bgp_damp_info)), VTY_NEWLINE); /* Attributes */ count = attr_count(); vty_out (vty, "%ld BGP attributes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof(struct attr)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_ATTR_EXTRA))) vty_out (vty, "%ld BGP extra attributes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof(struct attr_extra)), VTY_NEWLINE); if ((count = attr_unknown_count())) vty_out (vty, "%ld unknown attributes%s", count, VTY_NEWLINE); /* AS_PATH attributes */ count = aspath_count (); vty_out (vty, "%ld BGP AS-PATH entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct aspath)), VTY_NEWLINE); count = mtype_stats_alloc (MTYPE_AS_SEG); vty_out (vty, "%ld BGP AS-PATH segments, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct assegment)), VTY_NEWLINE); /* Other attributes */ if ((count = community_count ())) vty_out (vty, "%ld BGP community entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct community)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_ECOMMUNITY))) vty_out (vty, "%ld BGP community entries, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct ecommunity)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_CLUSTER))) vty_out (vty, "%ld Cluster lists, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct cluster_list)), VTY_NEWLINE); /* Peer related usage */ count = mtype_stats_alloc (MTYPE_BGP_PEER); vty_out (vty, "%ld peers, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct peer)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_PEER_GROUP))) vty_out (vty, "%ld peer groups, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct peer_group)), VTY_NEWLINE); /* Other */ if ((count = mtype_stats_alloc (MTYPE_HASH))) vty_out (vty, "%ld hash tables, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct hash)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_HASH_BACKET))) vty_out (vty, "%ld hash buckets, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (struct hash_backet)), VTY_NEWLINE); if ((count = mtype_stats_alloc (MTYPE_BGP_REGEXP))) vty_out (vty, "%ld compiled regexes, using %s of memory%s", count, mtype_memstr (memstrbuf, sizeof (memstrbuf), count * sizeof (regex_t)), VTY_NEWLINE); return CMD_SUCCESS; } /* Show BGP peer's summary information. */ static int bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) { struct peer *peer; struct listnode *node, *nnode; unsigned int count = 0; char timebuf[BGP_UPTIME_LEN]; int len; /* Header string for each address family. */ static char header[] = "Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd"; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->afc[afi][safi]) { if (!count) { unsigned long ents; char memstrbuf[MTYPE_MEMSTR_LEN]; /* Usage summary and header */ vty_out (vty, "BGP router identifier %s, local AS number %u%s", inet_ntoa (bgp->router_id), bgp->as, VTY_NEWLINE); ents = bgp_table_count (bgp->rib[afi][safi]); vty_out (vty, "RIB entries %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct bgp_node)), VTY_NEWLINE); /* Peer related usage */ ents = listcount (bgp->peer); vty_out (vty, "Peers %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer)), VTY_NEWLINE); if ((ents = listcount (bgp->rsclient))) vty_out (vty, "RS-Client peers %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer)), VTY_NEWLINE); if ((ents = listcount (bgp->group))) vty_out (vty, "Peer groups %ld, using %s of memory%s", ents, mtype_memstr (memstrbuf, sizeof (memstrbuf), ents * sizeof (struct peer_group)), VTY_NEWLINE); if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) vty_out (vty, "Dampening enabled.%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%s%s", header, VTY_NEWLINE); } count++; len = vty_out (vty, "%s", peer->host); len = 16 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); else vty_out (vty, "%*s", len, " "); vty_out (vty, "4 "); vty_out (vty, "%5u %7d %7d %8d %4d %4lu ", peer->as, peer->open_in + peer->update_in + peer->keepalive_in + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in, peer->open_out + peer->update_out + peer->keepalive_out + peer->notify_out + peer->refresh_out + peer->dynamic_cap_out, 0, 0, (unsigned long) peer->obuf->count); vty_out (vty, "%8s", peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN)); if (peer->status == Established) { vty_out (vty, " %8ld", peer->pcount[afi][safi]); } else { if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " Idle (Admin)"); else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) vty_out (vty, " Idle (PfxCt)"); else vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, peer->status)); } vty_out (vty, "%s", VTY_NEWLINE); } } if (count) vty_out (vty, "%sTotal number of neighbors %d%s", VTY_NEWLINE, count, VTY_NEWLINE); else vty_out (vty, "No %s neighbor is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show_summary_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi) { struct bgp *bgp; if (name) { bgp = bgp_lookup_by_name (name); if (! bgp) { vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); return CMD_WARNING; } bgp_show_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } bgp = bgp_get_default (); if (bgp) bgp_show_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } /* `show ip bgp summary' commands. */ DEFUN (show_ip_bgp_summary, show_ip_bgp_summary_cmd, "show ip bgp summary", SHOW_STR IP_STR BGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_instance_summary, show_ip_bgp_instance_summary_cmd, "show ip bgp view WORD summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_summary, show_ip_bgp_ipv4_summary_cmd, "show ip bgp ipv4 (unicast|multicast) summary", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_summary, show_bgp_ipv4_safi_summary_cmd, "show bgp ipv4 (unicast|multicast) summary", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFUN (show_ip_bgp_instance_ipv4_summary, show_ip_bgp_instance_ipv4_summary_cmd, "show ip bgp view WORD ipv4 (unicast|multicast) summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); else return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_instance_ipv4_summary, show_bgp_instance_ipv4_safi_summary_cmd, "show bgp view WORD ipv4 (unicast|multicast) summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") DEFUN (show_ip_bgp_vpnv4_all_summary, show_ip_bgp_vpnv4_all_summary_cmd, "show ip bgp vpnv4 all summary", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } DEFUN (show_ip_bgp_vpnv4_rd_summary, show_ip_bgp_vpnv4_rd_summary_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn summary", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Summary of BGP neighbor status\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_MPLS_VPN); } #ifdef HAVE_IPV6 DEFUN (show_bgp_summary, show_bgp_summary_cmd, "show bgp summary", SHOW_STR BGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } DEFUN (show_bgp_instance_summary, show_bgp_instance_summary_cmd, "show bgp view WORD summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_summary, show_bgp_ipv6_summary_cmd, "show bgp ipv6 summary", SHOW_STR BGP_STR "Address family\n" "Summary of BGP neighbor status\n") ALIAS (show_bgp_instance_summary, show_bgp_instance_ipv6_summary_cmd, "show bgp view WORD ipv6 summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Summary of BGP neighbor status\n") DEFUN (show_bgp_ipv6_safi_summary, show_bgp_ipv6_safi_summary_cmd, "show bgp ipv6 (unicast|multicast) summary", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } DEFUN (show_bgp_instance_ipv6_safi_summary, show_bgp_instance_ipv6_safi_summary_cmd, "show bgp view WORD ipv6 (unicast|multicast) summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Summary of BGP neighbor status\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST); return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_bgp_summary, show_ipv6_bgp_summary_cmd, "show ipv6 bgp summary", SHOW_STR IPV6_STR BGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_summary, show_ipv6_mbgp_summary_cmd, "show ipv6 mbgp summary", SHOW_STR IPV6_STR MBGP_STR "Summary of BGP neighbor status\n") { return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ const char * afi_safi_print (afi_t afi, safi_t safi) { if (afi == AFI_IP && safi == SAFI_UNICAST) return "IPv4 Unicast"; else if (afi == AFI_IP && safi == SAFI_MULTICAST) return "IPv4 Multicast"; else if (afi == AFI_IP && safi == SAFI_MPLS_VPN) return "VPNv4 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_UNICAST) return "IPv6 Unicast"; else if (afi == AFI_IP6 && safi == SAFI_MULTICAST) return "IPv6 Multicast"; else return "Unknown"; } /* Show BGP peer's information. */ enum show_type { show_all, show_peer }; static void bgp_show_peer_afi_orf_cap (struct vty *vty, struct peer *p, afi_t afi, safi_t safi, u_int16_t adv_smcap, u_int16_t adv_rmcap, u_int16_t rcv_smcap, u_int16_t rcv_rmcap) { /* Send-Mode */ if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) || CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) { vty_out (vty, " Send-mode: "); if (CHECK_FLAG (p->af_cap[afi][safi], adv_smcap)) vty_out (vty, "advertised"); if (CHECK_FLAG (p->af_cap[afi][safi], rcv_smcap)) vty_out (vty, "%sreceived", CHECK_FLAG (p->af_cap[afi][safi], adv_smcap) ? ", " : ""); vty_out (vty, "%s", VTY_NEWLINE); } /* Receive-Mode */ if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) || CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) { vty_out (vty, " Receive-mode: "); if (CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap)) vty_out (vty, "advertised"); if (CHECK_FLAG (p->af_cap[afi][safi], rcv_rmcap)) vty_out (vty, "%sreceived", CHECK_FLAG (p->af_cap[afi][safi], adv_rmcap) ? ", " : ""); vty_out (vty, "%s", VTY_NEWLINE); } } static void bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi) { struct bgp_filter *filter; char orf_pfx_name[BUFSIZ]; int orf_pfx_count; filter = &p->filter[afi][safi]; vty_out (vty, " For address family: %s%s", afi_safi_print (afi, safi), VTY_NEWLINE); if (p->af_group[afi][safi]) vty_out (vty, " %s peer-group member%s", p->group->name, VTY_NEWLINE); if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) vty_out (vty, " AF-dependant capabilities:%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) { vty_out (vty, " Outbound Route Filter (ORF) type (%d) Prefix-list:%s", ORF_TYPE_PREFIX, VTY_NEWLINE); bgp_show_peer_afi_orf_cap (vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV, PEER_CAP_ORF_PREFIX_RM_ADV, PEER_CAP_ORF_PREFIX_SM_RCV, PEER_CAP_ORF_PREFIX_RM_RCV); } if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) || CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) { vty_out (vty, " Outbound Route Filter (ORF) type (%d) Prefix-list:%s", ORF_TYPE_PREFIX_OLD, VTY_NEWLINE); bgp_show_peer_afi_orf_cap (vty, p, afi, safi, PEER_CAP_ORF_PREFIX_SM_ADV, PEER_CAP_ORF_PREFIX_RM_ADV, PEER_CAP_ORF_PREFIX_SM_OLD_RCV, PEER_CAP_ORF_PREFIX_RM_OLD_RCV); } sprintf (orf_pfx_name, "%s.%d.%d", p->host, afi, safi); orf_pfx_count = prefix_bgp_show_prefix_list (NULL, afi, orf_pfx_name); if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND) || orf_pfx_count) { vty_out (vty, " Outbound Route Filter (ORF):"); if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) vty_out (vty, " sent;"); if (orf_pfx_count) vty_out (vty, " received (%d entries)", orf_pfx_count); vty_out (vty, "%s", VTY_NEWLINE); } if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) vty_out (vty, " First update is deferred until ORF or ROUTE-REFRESH is received%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) vty_out (vty, " Route-Reflector Client%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) vty_out (vty, " Route-Server Client%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) vty_out (vty, " Inbound soft reconfiguration allowed%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_REMOVE_PRIVATE_AS)) vty_out (vty, " Private AS number removed from updates to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)) vty_out (vty, " NEXT_HOP is always this router%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) vty_out (vty, " AS_PATH is propagated unchanged to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) vty_out (vty, " NEXT_HOP is propagated unchanged to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) vty_out (vty, " MED is propagated unchanged to this neighbor%s", VTY_NEWLINE); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) || CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) { vty_out (vty, " Community attribute sent to this neighbor"); if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(both)%s", VTY_NEWLINE); else if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, "(extended)%s", VTY_NEWLINE); else vty_out (vty, "(standard)%s", VTY_NEWLINE); } if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) { vty_out (vty, " Default information originate,"); if (p->default_rmap[afi][safi].name) vty_out (vty, " default route-map %s%s,", p->default_rmap[afi][safi].map ? "*" : "", p->default_rmap[afi][safi].name); if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) vty_out (vty, " default sent%s", VTY_NEWLINE); else vty_out (vty, " default not sent%s", VTY_NEWLINE); } if (filter->plist[FILTER_IN].name || filter->dlist[FILTER_IN].name || filter->aslist[FILTER_IN].name || filter->map[RMAP_IN].name) vty_out (vty, " Inbound path policy configured%s", VTY_NEWLINE); if (filter->plist[FILTER_OUT].name || filter->dlist[FILTER_OUT].name || filter->aslist[FILTER_OUT].name || filter->map[RMAP_OUT].name || filter->usmap.name) vty_out (vty, " Outbound path policy configured%s", VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name) vty_out (vty, " Import policy for this RS-client configured%s", VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) vty_out (vty, " Export policy for this RS-client configured%s", VTY_NEWLINE); /* prefix-list */ if (filter->plist[FILTER_IN].name) vty_out (vty, " Incoming update prefix filter list is %s%s%s", filter->plist[FILTER_IN].plist ? "*" : "", filter->plist[FILTER_IN].name, VTY_NEWLINE); if (filter->plist[FILTER_OUT].name) vty_out (vty, " Outgoing update prefix filter list is %s%s%s", filter->plist[FILTER_OUT].plist ? "*" : "", filter->plist[FILTER_OUT].name, VTY_NEWLINE); /* distribute-list */ if (filter->dlist[FILTER_IN].name) vty_out (vty, " Incoming update network filter list is %s%s%s", filter->dlist[FILTER_IN].alist ? "*" : "", filter->dlist[FILTER_IN].name, VTY_NEWLINE); if (filter->dlist[FILTER_OUT].name) vty_out (vty, " Outgoing update network filter list is %s%s%s", filter->dlist[FILTER_OUT].alist ? "*" : "", filter->dlist[FILTER_OUT].name, VTY_NEWLINE); /* filter-list. */ if (filter->aslist[FILTER_IN].name) vty_out (vty, " Incoming update AS path filter list is %s%s%s", filter->aslist[FILTER_IN].aslist ? "*" : "", filter->aslist[FILTER_IN].name, VTY_NEWLINE); if (filter->aslist[FILTER_OUT].name) vty_out (vty, " Outgoing update AS path filter list is %s%s%s", filter->aslist[FILTER_OUT].aslist ? "*" : "", filter->aslist[FILTER_OUT].name, VTY_NEWLINE); /* route-map. */ if (filter->map[RMAP_IN].name) vty_out (vty, " Route map for incoming advertisements is %s%s%s", filter->map[RMAP_IN].map ? "*" : "", filter->map[RMAP_IN].name, VTY_NEWLINE); if (filter->map[RMAP_OUT].name) vty_out (vty, " Route map for outgoing advertisements is %s%s%s", filter->map[RMAP_OUT].map ? "*" : "", filter->map[RMAP_OUT].name, VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name) vty_out (vty, " Route map for advertisements going into this RS-client's table is %s%s%s", filter->map[RMAP_IMPORT].map ? "*" : "", filter->map[RMAP_IMPORT].name, VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) vty_out (vty, " Route map for advertisements coming from this RS-client is %s%s%s", filter->map[RMAP_EXPORT].map ? "*" : "", filter->map[RMAP_EXPORT].name, VTY_NEWLINE); /* unsuppress-map */ if (filter->usmap.name) vty_out (vty, " Route map for selective unsuppress is %s%s%s", filter->usmap.map ? "*" : "", filter->usmap.name, VTY_NEWLINE); /* Receive prefix count */ vty_out (vty, " %ld accepted prefixes%s", p->pcount[afi][safi], VTY_NEWLINE); /* Maximum prefix */ if (CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) { vty_out (vty, " Maximum prefixes allowed %ld%s%s", p->pmax[afi][safi], CHECK_FLAG (p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) ? " (warning-only)" : "", VTY_NEWLINE); vty_out (vty, " Threshold for warning message %d%%", p->pmax_threshold[afi][safi]); if (p->pmax_restart[afi][safi]) vty_out (vty, ", restart interval %d min", p->pmax_restart[afi][safi]); vty_out (vty, "%s", VTY_NEWLINE); } vty_out (vty, "%s", VTY_NEWLINE); } static void bgp_show_peer (struct vty *vty, struct peer *p) { struct bgp *bgp; char buf1[BUFSIZ]; char timebuf[BGP_UPTIME_LEN]; afi_t afi; safi_t safi; bgp = p->bgp; /* Configured IP address. */ vty_out (vty, "BGP neighbor is %s, ", p->host); vty_out (vty, "remote AS %u, ", p->as); vty_out (vty, "local AS %u%s%s, ", p->change_local_as ? p->change_local_as : p->local_as, CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? " no-prepend" : "", CHECK_FLAG (p->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" : ""); vty_out (vty, "%s link%s", p->as == p->local_as ? "internal" : "external", VTY_NEWLINE); /* Description. */ if (p->desc) vty_out (vty, " Description: %s%s", p->desc, VTY_NEWLINE); /* Peer-group */ if (p->group) vty_out (vty, " Member of peer-group %s for session parameters%s", p->group->name, VTY_NEWLINE); /* Administrative shutdown. */ if (CHECK_FLAG (p->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " Administratively shut down%s", VTY_NEWLINE); /* BGP Version. */ vty_out (vty, " BGP version 4"); vty_out (vty, ", remote router ID %s%s", inet_ntop (AF_INET, &p->remote_id, buf1, BUFSIZ), VTY_NEWLINE); /* Confederation */ if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION) && bgp_confederation_peers_check (bgp, p->as)) vty_out (vty, " Neighbor under common administration%s", VTY_NEWLINE); /* Status. */ vty_out (vty, " BGP state = %s", LOOKUP (bgp_status_msg, p->status)); if (p->status == Established) vty_out (vty, ", up for %8s", peer_uptime (p->uptime, timebuf, BGP_UPTIME_LEN)); else if (p->status == Active) { if (CHECK_FLAG (p->flags, PEER_FLAG_PASSIVE)) vty_out (vty, " (passive)"); else if (CHECK_FLAG (p->sflags, PEER_STATUS_NSF_WAIT)) vty_out (vty, " (NSF passive)"); } vty_out (vty, "%s", VTY_NEWLINE); /* read timer */ vty_out (vty, " Last read %s", peer_uptime (p->readtime, timebuf, BGP_UPTIME_LEN)); /* Configured timer values. */ vty_out (vty, ", hold time is %d, keepalive interval is %d seconds%s", p->v_holdtime, p->v_keepalive, VTY_NEWLINE); if (CHECK_FLAG (p->config, PEER_CONFIG_TIMER)) { vty_out (vty, " Configured hold time is %d", p->holdtime); vty_out (vty, ", keepalive interval is %d seconds%s", p->keepalive, VTY_NEWLINE); } /* Capability. */ if (p->status == Established) { if (p->cap || p->afc_adv[AFI_IP][SAFI_UNICAST] || p->afc_recv[AFI_IP][SAFI_UNICAST] || p->afc_adv[AFI_IP][SAFI_MULTICAST] || p->afc_recv[AFI_IP][SAFI_MULTICAST] #ifdef HAVE_IPV6 || p->afc_adv[AFI_IP6][SAFI_UNICAST] || p->afc_recv[AFI_IP6][SAFI_UNICAST] || p->afc_adv[AFI_IP6][SAFI_MULTICAST] || p->afc_recv[AFI_IP6][SAFI_MULTICAST] #endif /* HAVE_IPV6 */ || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, " Neighbor capabilities:%s", VTY_NEWLINE); /* AS4 */ if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV) || CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) { vty_out (vty, " 4 Byte AS:"); if (CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV)) vty_out (vty, " advertised"); if (CHECK_FLAG (p->cap, PEER_CAP_AS4_RCV)) vty_out (vty, " %sreceived", CHECK_FLAG (p->cap, PEER_CAP_AS4_ADV) ? "and " : ""); vty_out (vty, "%s", VTY_NEWLINE); } /* Dynamic */ if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) { vty_out (vty, " Dynamic:"); if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV)) vty_out (vty, " advertised"); if (CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_RCV)) vty_out (vty, " %sreceived", CHECK_FLAG (p->cap, PEER_CAP_DYNAMIC_ADV) ? "and " : ""); vty_out (vty, "%s", VTY_NEWLINE); } /* Route Refresh */ if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) { vty_out (vty, " Route refresh:"); if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV)) vty_out (vty, " advertised"); if (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV) || CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV)) vty_out (vty, " %sreceived(%s)", CHECK_FLAG (p->cap, PEER_CAP_REFRESH_ADV) ? "and " : "", (CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV) && CHECK_FLAG (p->cap, PEER_CAP_REFRESH_NEW_RCV)) ? "old & new" : CHECK_FLAG (p->cap, PEER_CAP_REFRESH_OLD_RCV) ? "old" : "new"); vty_out (vty, "%s", VTY_NEWLINE); } /* Multiprotocol Extensions */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (p->afc_adv[afi][safi] || p->afc_recv[afi][safi]) { vty_out (vty, " Address family %s:", afi_safi_print (afi, safi)); if (p->afc_adv[afi][safi]) vty_out (vty, " advertised"); if (p->afc_recv[afi][safi]) vty_out (vty, " %sreceived", p->afc_adv[afi][safi] ? "and " : ""); vty_out (vty, "%s", VTY_NEWLINE); } /* Gracefull Restart */ if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV)) { vty_out (vty, " Graceful Restart Capabilty:"); if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV)) vty_out (vty, " advertised"); if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)) vty_out (vty, " %sreceived", CHECK_FLAG (p->cap, PEER_CAP_RESTART_ADV) ? "and " : ""); vty_out (vty, "%s", VTY_NEWLINE); if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV)) { int restart_af_count = 0; vty_out (vty, " Remote Restart timer is %d seconds%s", p->v_gr_restart, VTY_NEWLINE); vty_out (vty, " Address families by peer:%s ", VTY_NEWLINE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) { vty_out (vty, "%s%s(%s)", restart_af_count ? ", " : "", afi_safi_print (afi, safi), CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ? "preserved" : "not preserved"); restart_af_count++; } if (! restart_af_count) vty_out (vty, "none"); vty_out (vty, "%s", VTY_NEWLINE); } } } } /* graceful restart information */ if (CHECK_FLAG (p->cap, PEER_CAP_RESTART_RCV) || p->t_gr_restart || p->t_gr_stale) { int eor_send_af_count = 0; int eor_receive_af_count = 0; vty_out (vty, " Graceful restart informations:%s", VTY_NEWLINE); if (p->status == Established) { vty_out (vty, " End-of-RIB send: "); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)) { vty_out (vty, "%s%s", eor_send_af_count ? ", " : "", afi_safi_print (afi, safi)); eor_send_af_count++; } vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, " End-of-RIB received: "); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) { vty_out (vty, "%s%s", eor_receive_af_count ? ", " : "", afi_safi_print (afi, safi)); eor_receive_af_count++; } vty_out (vty, "%s", VTY_NEWLINE); } if (p->t_gr_restart) vty_out (vty, " The remaining time of restart timer is %ld%s", thread_timer_remain_second (p->t_gr_restart), VTY_NEWLINE); if (p->t_gr_stale) vty_out (vty, " The remaining time of stalepath timer is %ld%s", thread_timer_remain_second (p->t_gr_stale), VTY_NEWLINE); } /* Packet counts. */ vty_out (vty, " Message statistics:%s", VTY_NEWLINE); vty_out (vty, " Inq depth is 0%s", VTY_NEWLINE); vty_out (vty, " Outq depth is %lu%s", (unsigned long) p->obuf->count, VTY_NEWLINE); vty_out (vty, " Sent Rcvd%s", VTY_NEWLINE); vty_out (vty, " Opens: %10d %10d%s", p->open_out, p->open_in, VTY_NEWLINE); vty_out (vty, " Notifications: %10d %10d%s", p->notify_out, p->notify_in, VTY_NEWLINE); vty_out (vty, " Updates: %10d %10d%s", p->update_out, p->update_in, VTY_NEWLINE); vty_out (vty, " Keepalives: %10d %10d%s", p->keepalive_out, p->keepalive_in, VTY_NEWLINE); vty_out (vty, " Route Refresh: %10d %10d%s", p->refresh_out, p->refresh_in, VTY_NEWLINE); vty_out (vty, " Capability: %10d %10d%s", p->dynamic_cap_out, p->dynamic_cap_in, VTY_NEWLINE); vty_out (vty, " Total: %10d %10d%s", p->open_out + p->notify_out + p->update_out + p->keepalive_out + p->refresh_out + p->dynamic_cap_out, p->open_in + p->notify_in + p->update_in + p->keepalive_in + p->refresh_in + p->dynamic_cap_in, VTY_NEWLINE); /* advertisement-interval */ vty_out (vty, " Minimum time between advertisement runs is %d seconds%s", p->v_routeadv, VTY_NEWLINE); /* Update-source. */ if (p->update_if || p->update_source) { vty_out (vty, " Update source is "); if (p->update_if) vty_out (vty, "%s", p->update_if); else if (p->update_source) vty_out (vty, "%s", sockunion2str (p->update_source, buf1, SU_ADDRSTRLEN)); vty_out (vty, "%s", VTY_NEWLINE); } /* Default weight */ if (CHECK_FLAG (p->config, PEER_CONFIG_WEIGHT)) vty_out (vty, " Default weight %d%s", p->weight, VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); /* Address Family Information */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (p->afc[afi][safi]) bgp_show_peer_afi (vty, p, afi, safi); vty_out (vty, " Connections established %d; dropped %d%s", p->established, p->dropped, VTY_NEWLINE); if (! p->dropped) vty_out (vty, " Last reset never%s", VTY_NEWLINE); else vty_out (vty, " Last reset %s, due to %s%s", peer_uptime (p->resettime, timebuf, BGP_UPTIME_LEN), peer_down_str[(int) p->last_reset], VTY_NEWLINE); if (CHECK_FLAG (p->sflags, PEER_STATUS_PREFIX_OVERFLOW)) { vty_out (vty, " Peer had exceeded the max. no. of prefixes configured.%s", VTY_NEWLINE); if (p->t_pmax_restart) vty_out (vty, " Reduce the no. of prefix from %s, will restart in %ld seconds%s", p->host, thread_timer_remain_second (p->t_pmax_restart), VTY_NEWLINE); else vty_out (vty, " Reduce the no. of prefix and clear ip bgp %s to restore peering%s", p->host, VTY_NEWLINE); } /* EBGP Multihop and GTSM */ if (p->sort != BGP_PEER_IBGP) { if (p->gtsm_hops > 0) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", p->gtsm_hops, VTY_NEWLINE); else if (p->ttl > 1) vty_out (vty, " External BGP neighbor may be up to %d hops away.%s", p->ttl, VTY_NEWLINE); } else { if (p->gtsm_hops > 0) vty_out (vty, " Internal BGP neighbor may be up to %d hops away.%s", p->gtsm_hops, VTY_NEWLINE); } /* Local address. */ if (p->su_local) { vty_out (vty, "Local host: %s, Local port: %d%s", sockunion2str (p->su_local, buf1, SU_ADDRSTRLEN), ntohs (p->su_local->sin.sin_port), VTY_NEWLINE); } /* Remote address. */ if (p->su_remote) { vty_out (vty, "Foreign host: %s, Foreign port: %d%s", sockunion2str (p->su_remote, buf1, SU_ADDRSTRLEN), ntohs (p->su_remote->sin.sin_port), VTY_NEWLINE); } /* Nexthop display. */ if (p->su_local) { vty_out (vty, "Nexthop: %s%s", inet_ntop (AF_INET, &p->nexthop.v4, buf1, BUFSIZ), VTY_NEWLINE); #ifdef HAVE_IPV6 vty_out (vty, "Nexthop global: %s%s", inet_ntop (AF_INET6, &p->nexthop.v6_global, buf1, BUFSIZ), VTY_NEWLINE); vty_out (vty, "Nexthop local: %s%s", inet_ntop (AF_INET6, &p->nexthop.v6_local, buf1, BUFSIZ), VTY_NEWLINE); vty_out (vty, "BGP connection: %s%s", p->shared_network ? "shared network" : "non shared network", VTY_NEWLINE); #endif /* HAVE_IPV6 */ } /* Timer information. */ if (p->t_start) vty_out (vty, "Next start timer due in %ld seconds%s", thread_timer_remain_second (p->t_start), VTY_NEWLINE); if (p->t_connect) vty_out (vty, "Next connect timer due in %ld seconds%s", thread_timer_remain_second (p->t_connect), VTY_NEWLINE); vty_out (vty, "Read thread: %s Write thread: %s%s", p->t_read ? "on" : "off", p->t_write ? "on" : "off", VTY_NEWLINE); if (p->notify.code == BGP_NOTIFY_OPEN_ERR && p->notify.subcode == BGP_NOTIFY_OPEN_UNSUP_CAPBL) bgp_capability_vty_out (vty, p); vty_out (vty, "%s", VTY_NEWLINE); } static int bgp_show_neighbor (struct vty *vty, struct bgp *bgp, enum show_type type, union sockunion *su) { struct listnode *node, *nnode; struct peer *peer; int find = 0; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { switch (type) { case show_all: bgp_show_peer (vty, peer); break; case show_peer: if (sockunion_same (&peer->su, su)) { find = 1; bgp_show_peer (vty, peer); } break; } } if (type == show_peer && ! find) vty_out (vty, "%% No such neighbor%s", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show_neighbor_vty (struct vty *vty, const char *name, enum show_type type, const char *ip_str) { int ret; struct bgp *bgp; union sockunion su; if (ip_str) { ret = str2sockunion (ip_str, &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", ip_str, VTY_NEWLINE); return CMD_WARNING; } } if (name) { bgp = bgp_lookup_by_name (name); if (! bgp) { vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); return CMD_WARNING; } bgp_show_neighbor (vty, bgp, type, &su); return CMD_SUCCESS; } bgp = bgp_get_default (); if (bgp) bgp_show_neighbor (vty, bgp, type, &su); return CMD_SUCCESS; } /* "show ip bgp neighbors" commands. */ DEFUN (show_ip_bgp_neighbors, show_ip_bgp_neighbors_cmd, "show ip bgp neighbors", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n") { return bgp_show_neighbor_vty (vty, NULL, show_all, NULL); } ALIAS (show_ip_bgp_neighbors, show_ip_bgp_ipv4_neighbors_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_neighbors, show_ip_bgp_vpnv4_all_neighbors_cmd, "show ip bgp vpnv4 all neighbors", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_neighbors, show_ip_bgp_vpnv4_rd_neighbors_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_neighbors, show_bgp_neighbors_cmd, "show bgp neighbors", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_neighbors, show_bgp_ipv6_neighbors_cmd, "show bgp ipv6 neighbors", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFUN (show_ip_bgp_neighbors_peer, show_ip_bgp_neighbors_peer_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") { return bgp_show_neighbor_vty (vty, NULL, show_peer, argv[argc - 1]); } ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_ipv4_neighbors_peer_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_vpnv4_all_neighbors_peer_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_ip_bgp_vpnv4_rd_neighbors_peer_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_bgp_neighbors_peer_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_neighbors_peer, show_bgp_ipv6_neighbors_peer_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") DEFUN (show_ip_bgp_instance_neighbors, show_ip_bgp_instance_neighbors_cmd, "show ip bgp view WORD neighbors", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") { return bgp_show_neighbor_vty (vty, argv[0], show_all, NULL); } ALIAS (show_ip_bgp_instance_neighbors, show_bgp_instance_neighbors_cmd, "show bgp view WORD neighbors", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n") ALIAS (show_ip_bgp_instance_neighbors, show_bgp_instance_ipv6_neighbors_cmd, "show bgp view WORD ipv6 neighbors", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n") DEFUN (show_ip_bgp_instance_neighbors_peer, show_ip_bgp_instance_neighbors_peer_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") { return bgp_show_neighbor_vty (vty, argv[0], show_peer, argv[1]); } ALIAS (show_ip_bgp_instance_neighbors_peer, show_bgp_instance_neighbors_peer_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") ALIAS (show_ip_bgp_instance_neighbors_peer, show_bgp_instance_ipv6_neighbors_peer_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n") /* Show BGP's AS paths internal data. There are both `show ip bgp paths' and `show ip mbgp paths'. Those functions results are the same.*/ DEFUN (show_ip_bgp_paths, show_ip_bgp_paths_cmd, "show ip bgp paths", SHOW_STR IP_STR BGP_STR "Path information\n") { vty_out (vty, "Address Refcnt Path%s", VTY_NEWLINE); aspath_print_all_vty (vty); return CMD_SUCCESS; } DEFUN (show_ip_bgp_ipv4_paths, show_ip_bgp_ipv4_paths_cmd, "show ip bgp ipv4 (unicast|multicast) paths", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Path information\n") { vty_out (vty, "Address Refcnt Path\r\n"); aspath_print_all_vty (vty); return CMD_SUCCESS; } #include "hash.h" static void community_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct community *com; com = (struct community *) backet->data; vty_out (vty, "[%p] (%ld) %s%s", backet, com->refcnt, community_str (com), VTY_NEWLINE); } /* Show BGP's community internal data. */ DEFUN (show_ip_bgp_community_info, show_ip_bgp_community_info_cmd, "show ip bgp community-info", SHOW_STR IP_STR BGP_STR "List all bgp community information\n") { vty_out (vty, "Address Refcnt Community%s", VTY_NEWLINE); hash_iterate (community_hash (), (void (*) (struct hash_backet *, void *)) community_show_all_iterator, vty); return CMD_SUCCESS; } DEFUN (show_ip_bgp_attr_info, show_ip_bgp_attr_info_cmd, "show ip bgp attribute-info", SHOW_STR IP_STR BGP_STR "List all bgp attribute information\n") { attr_show_all (vty); return CMD_SUCCESS; } static int bgp_write_rsclient_summary (struct vty *vty, struct peer *rsclient, afi_t afi, safi_t safi) { char timebuf[BGP_UPTIME_LEN]; char rmbuf[14]; const char *rmname; struct peer *peer; struct listnode *node, *nnode; int len; int count = 0; if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) { for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, peer)) { count++; bgp_write_rsclient_summary (vty, peer, afi, safi); } return count; } len = vty_out (vty, "%s", rsclient->host); len = 16 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " "); else vty_out (vty, "%*s", len, " "); vty_out (vty, "4 "); vty_out (vty, "%10u ", rsclient->as); rmname = ROUTE_MAP_EXPORT_NAME(&rsclient->filter[afi][safi]); if ( rmname && strlen (rmname) > 13 ) { sprintf (rmbuf, "%13s", "..."); rmname = strncpy (rmbuf, rmname, 10); } else if (! rmname) rmname = ""; vty_out (vty, " %13s ", rmname); rmname = ROUTE_MAP_IMPORT_NAME(&rsclient->filter[afi][safi]); if ( rmname && strlen (rmname) > 13 ) { sprintf (rmbuf, "%13s", "..."); rmname = strncpy (rmbuf, rmname, 10); } else if (! rmname) rmname = ""; vty_out (vty, " %13s ", rmname); vty_out (vty, "%8s", peer_uptime (rsclient->uptime, timebuf, BGP_UPTIME_LEN)); if (CHECK_FLAG (rsclient->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " Idle (Admin)"); else if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_PREFIX_OVERFLOW)) vty_out (vty, " Idle (PfxCt)"); else vty_out (vty, " %-11s", LOOKUP(bgp_status_msg, rsclient->status)); vty_out (vty, "%s", VTY_NEWLINE); return 1; } static int bgp_show_rsclient_summary (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { struct peer *peer; struct listnode *node, *nnode; int count = 0; /* Header string for each address family. */ static char header[] = "Neighbor V AS Export-Policy Import-Policy Up/Down State"; for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, peer)) { if (peer->afc[afi][safi] && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { if (! count) { vty_out (vty, "Route Server's BGP router identifier %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, "Route Server's local AS number %u%s", bgp->as, VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); vty_out (vty, "%s%s", header, VTY_NEWLINE); } count += bgp_write_rsclient_summary (vty, peer, afi, safi); } } if (count) vty_out (vty, "%sTotal number of Route Server Clients %d%s", VTY_NEWLINE, count, VTY_NEWLINE); else vty_out (vty, "No %s Route Server Client is configured%s", afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show_rsclient_summary_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi) { struct bgp *bgp; if (name) { bgp = bgp_lookup_by_name (name); if (! bgp) { vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); return CMD_WARNING; } bgp_show_rsclient_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } bgp = bgp_get_default (); if (bgp) bgp_show_rsclient_summary (vty, bgp, afi, safi); return CMD_SUCCESS; } /* 'show bgp rsclient' commands. */ DEFUN (show_ip_bgp_rsclient_summary, show_ip_bgp_rsclient_summary_cmd, "show ip bgp rsclient summary", SHOW_STR IP_STR BGP_STR "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_instance_rsclient_summary, show_ip_bgp_instance_rsclient_summary_cmd, "show ip bgp view WORD rsclient summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_rsclient_summary, show_ip_bgp_ipv4_rsclient_summary_cmd, "show ip bgp ipv4 (unicast|multicast) rsclient summary", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_MULTICAST); return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_instance_ipv4_rsclient_summary, show_ip_bgp_instance_ipv4_rsclient_summary_cmd, "show ip bgp view WORD ipv4 (unicast|multicast) rsclient summary", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { if (strncmp (argv[1], "m", 1) == 0) return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_MULTICAST); return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_instance_ipv4_safi_rsclient_summary_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { safi_t safi; if (argc == 2) { safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, safi); } else { safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, safi); } } ALIAS (show_bgp_instance_ipv4_safi_rsclient_summary, show_bgp_ipv4_safi_rsclient_summary_cmd, "show bgp ipv4 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") #ifdef HAVE_IPV6 DEFUN (show_bgp_rsclient_summary, show_bgp_rsclient_summary_cmd, "show bgp rsclient summary", SHOW_STR BGP_STR "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST); } DEFUN (show_bgp_instance_rsclient_summary, show_bgp_instance_rsclient_summary_cmd, "show bgp view WORD rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_rsclient_summary, show_bgp_ipv6_rsclient_summary_cmd, "show bgp ipv6 rsclient summary", SHOW_STR BGP_STR "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") ALIAS (show_bgp_instance_rsclient_summary, show_bgp_instance_ipv6_rsclient_summary_cmd, "show bgp view WORD ipv6 rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") DEFUN (show_bgp_instance_ipv6_safi_rsclient_summary, show_bgp_instance_ipv6_safi_rsclient_summary_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") { safi_t safi; if (argc == 2) { safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, safi); } else { safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, safi); } } ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, show_bgp_ipv6_safi_rsclient_summary_cmd, "show bgp ipv6 (unicast|multicast) rsclient summary", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Clients\n" "Summary of all Route Server Clients\n") #endif /* HAVE IPV6 */ /* Redistribute VTY commands. */ DEFUN (bgp_redistribute_ipv4, bgp_redistribute_ipv4_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_set (vty->index, AFI_IP, type); } DEFUN (bgp_redistribute_ipv4_rmap, bgp_redistribute_ipv4_rmap_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); return bgp_redistribute_set (vty->index, AFI_IP, type); } DEFUN (bgp_redistribute_ipv4_metric, bgp_redistribute_ipv4_metric_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); return bgp_redistribute_set (vty->index, AFI_IP, type); } DEFUN (bgp_redistribute_ipv4_rmap_metric, bgp_redistribute_ipv4_rmap_metric_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[2]); bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); return bgp_redistribute_set (vty->index, AFI_IP, type); } DEFUN (bgp_redistribute_ipv4_metric_rmap, bgp_redistribute_ipv4_metric_rmap_cmd, "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP, type, metric); bgp_redistribute_rmap_set (vty->index, AFI_IP, type, argv[2]); return bgp_redistribute_set (vty->index, AFI_IP, type); } DEFUN (no_bgp_redistribute_ipv4, no_bgp_redistribute_ipv4_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_unset (vty->index, AFI_IP, type); } DEFUN (no_bgp_redistribute_ipv4_rmap, no_bgp_redistribute_ipv4_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv4_metric, no_bgp_redistribute_ipv4_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_metric_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_rmap_metric_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") { int type; type = proto_redistnum (AFI_IP, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_metric_unset (vty->index, AFI_IP, type); bgp_redistribute_routemap_unset (vty->index, AFI_IP, type); return CMD_SUCCESS; } ALIAS (no_bgp_redistribute_ipv4_rmap_metric, no_bgp_redistribute_ipv4_metric_rmap_cmd, "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") #ifdef HAVE_IPV6 DEFUN (bgp_redistribute_ipv6, bgp_redistribute_ipv6_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD, "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_set (vty->index, AFI_IP6, type); } DEFUN (bgp_redistribute_ipv6_rmap, bgp_redistribute_ipv6_rmap_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); return bgp_redistribute_set (vty->index, AFI_IP6, type); } DEFUN (bgp_redistribute_ipv6_metric, bgp_redistribute_ipv6_metric_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); return bgp_redistribute_set (vty->index, AFI_IP6, type); } DEFUN (bgp_redistribute_ipv6_rmap_metric, bgp_redistribute_ipv6_rmap_metric_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[2]); bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); return bgp_redistribute_set (vty->index, AFI_IP6, type); } DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") { int type; u_int32_t metric; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } VTY_GET_INTEGER ("metric", metric, argv[1]); bgp_redistribute_metric_set (vty->index, AFI_IP6, type, metric); bgp_redistribute_rmap_set (vty->index, AFI_IP6, type, argv[2]); return bgp_redistribute_set (vty->index, AFI_IP6, type); } DEFUN (no_bgp_redistribute_ipv6, no_bgp_redistribute_ipv6_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD, NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD) { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_redistribute_unset (vty->index, AFI_IP6, type); } DEFUN (no_bgp_redistribute_ipv6_rmap, no_bgp_redistribute_ipv6_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n") { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv6_metric, no_bgp_redistribute_ipv6_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n") { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } DEFUN (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_rmap_metric_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Route map reference\n" "Pointer to route-map entries\n" "Metric for redistributed routes\n" "Default metric\n") { int type; type = proto_redistnum (AFI_IP6, argv[0]); if (type < 0 || type == ZEBRA_ROUTE_BGP) { vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE); return CMD_WARNING; } bgp_redistribute_metric_unset (vty->index, AFI_IP6, type); bgp_redistribute_routemap_unset (vty->index, AFI_IP6, type); return CMD_SUCCESS; } ALIAS (no_bgp_redistribute_ipv6_rmap_metric, no_bgp_redistribute_ipv6_metric_rmap_cmd, "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD", NO_STR "Redistribute information from another routing protocol\n" QUAGGA_IP6_REDIST_HELP_STR_BGPD "Metric for redistributed routes\n" "Default metric\n" "Route map reference\n" "Pointer to route-map entries\n") #endif /* HAVE_IPV6 */ int bgp_config_write_redistribute (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { int i; /* Unicast redistribution only. */ if (safi != SAFI_UNICAST) return 0; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { /* Redistribute BGP does not make sense. */ if (bgp->redist[afi][i] && i != ZEBRA_ROUTE_BGP) { /* Display "address-family" when it is not yet diplayed. */ bgp_config_write_family_header (vty, afi, safi, write); /* "redistribute" configuration. */ vty_out (vty, " redistribute %s", zebra_route_string(i)); if (bgp->redist_metric_flag[afi][i]) vty_out (vty, " metric %u", bgp->redist_metric[afi][i]); if (bgp->rmap[afi][i].name) vty_out (vty, " route-map %s", bgp->rmap[afi][i].name); vty_out (vty, "%s", VTY_NEWLINE); } } return *write; } /* BGP node structure. */ static struct cmd_node bgp_node = { BGP_NODE, "%s(config-router)# ", 1, }; static struct cmd_node bgp_ipv4_unicast_node = { BGP_IPV4_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv4_multicast_node = { BGP_IPV4M_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv6_unicast_node = { BGP_IPV6_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_ipv6_multicast_node = { BGP_IPV6M_NODE, "%s(config-router-af)# ", 1, }; static struct cmd_node bgp_vpnv4_node = { BGP_VPNV4_NODE, "%s(config-router-af)# ", 1 }; static void community_list_vty (void); void bgp_vty_init (void) { /* Install bgp top node. */ install_node (&bgp_node, bgp_config_write); install_node (&bgp_ipv4_unicast_node, NULL); install_node (&bgp_ipv4_multicast_node, NULL); install_node (&bgp_ipv6_unicast_node, NULL); install_node (&bgp_ipv6_multicast_node, NULL); install_node (&bgp_vpnv4_node, NULL); /* Install default VTY commands to new nodes. */ install_default (BGP_NODE); install_default (BGP_IPV4_NODE); install_default (BGP_IPV4M_NODE); install_default (BGP_IPV6_NODE); install_default (BGP_IPV6M_NODE); install_default (BGP_VPNV4_NODE); /* "bgp multiple-instance" commands. */ install_element (CONFIG_NODE, &bgp_multiple_instance_cmd); install_element (CONFIG_NODE, &no_bgp_multiple_instance_cmd); /* "bgp config-type" commands. */ install_element (CONFIG_NODE, &bgp_config_type_cmd); install_element (CONFIG_NODE, &no_bgp_config_type_cmd); /* Dummy commands (Currently not supported) */ install_element (BGP_NODE, &no_synchronization_cmd); install_element (BGP_NODE, &no_auto_summary_cmd); /* "router bgp" commands. */ install_element (CONFIG_NODE, &router_bgp_cmd); install_element (CONFIG_NODE, &router_bgp_view_cmd); /* "no router bgp" commands. */ install_element (CONFIG_NODE, &no_router_bgp_cmd); install_element (CONFIG_NODE, &no_router_bgp_view_cmd); /* "bgp router-id" commands. */ install_element (BGP_NODE, &bgp_router_id_cmd); install_element (BGP_NODE, &no_bgp_router_id_cmd); install_element (BGP_NODE, &no_bgp_router_id_val_cmd); /* "bgp cluster-id" commands. */ install_element (BGP_NODE, &bgp_cluster_id_cmd); install_element (BGP_NODE, &bgp_cluster_id32_cmd); install_element (BGP_NODE, &no_bgp_cluster_id_cmd); install_element (BGP_NODE, &no_bgp_cluster_id_arg_cmd); /* "bgp confederation" commands. */ install_element (BGP_NODE, &bgp_confederation_identifier_cmd); install_element (BGP_NODE, &no_bgp_confederation_identifier_cmd); install_element (BGP_NODE, &no_bgp_confederation_identifier_arg_cmd); /* "bgp confederation peers" commands. */ install_element (BGP_NODE, &bgp_confederation_peers_cmd); install_element (BGP_NODE, &no_bgp_confederation_peers_cmd); /* "maximum-paths" commands. */ install_element (BGP_NODE, &bgp_maxpaths_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_arg_cmd); install_element (BGP_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); install_element (BGP_IPV4_NODE, &bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_cmd); install_element (BGP_IPV4_NODE, &no_bgp_maxpaths_ibgp_arg_cmd); /* "timers bgp" commands. */ install_element (BGP_NODE, &bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_cmd); install_element (BGP_NODE, &no_bgp_timers_arg_cmd); /* "bgp client-to-client reflection" commands */ install_element (BGP_NODE, &no_bgp_client_to_client_reflection_cmd); install_element (BGP_NODE, &bgp_client_to_client_reflection_cmd); /* "bgp always-compare-med" commands */ install_element (BGP_NODE, &bgp_always_compare_med_cmd); install_element (BGP_NODE, &no_bgp_always_compare_med_cmd); /* "bgp deterministic-med" commands */ install_element (BGP_NODE, &bgp_deterministic_med_cmd); install_element (BGP_NODE, &no_bgp_deterministic_med_cmd); /* "bgp graceful-restart" commands */ install_element (BGP_NODE, &bgp_graceful_restart_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_cmd); install_element (BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd); install_element (BGP_NODE, &no_bgp_graceful_restart_stalepath_time_val_cmd); /* "bgp fast-external-failover" commands */ install_element (BGP_NODE, &bgp_fast_external_failover_cmd); install_element (BGP_NODE, &no_bgp_fast_external_failover_cmd); /* "bgp enforce-first-as" commands */ install_element (BGP_NODE, &bgp_enforce_first_as_cmd); install_element (BGP_NODE, &no_bgp_enforce_first_as_cmd); /* "bgp bestpath compare-routerid" commands */ install_element (BGP_NODE, &bgp_bestpath_compare_router_id_cmd); install_element (BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd); /* "bgp bestpath as-path ignore" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_ignore_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_ignore_cmd); /* "bgp bestpath as-path confed" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_confed_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_confed_cmd); /* "bgp bestpath as-path multipath-relax" commands */ install_element (BGP_NODE, &bgp_bestpath_aspath_multipath_relax_cmd); install_element (BGP_NODE, &no_bgp_bestpath_aspath_multipath_relax_cmd); /* "bgp log-neighbor-changes" commands */ install_element (BGP_NODE, &bgp_log_neighbor_changes_cmd); install_element (BGP_NODE, &no_bgp_log_neighbor_changes_cmd); /* "bgp bestpath med" commands */ install_element (BGP_NODE, &bgp_bestpath_med_cmd); install_element (BGP_NODE, &bgp_bestpath_med2_cmd); install_element (BGP_NODE, &bgp_bestpath_med3_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med2_cmd); install_element (BGP_NODE, &no_bgp_bestpath_med3_cmd); /* "no bgp default ipv4-unicast" commands. */ install_element (BGP_NODE, &no_bgp_default_ipv4_unicast_cmd); install_element (BGP_NODE, &bgp_default_ipv4_unicast_cmd); /* "bgp network import-check" commands. */ install_element (BGP_NODE, &bgp_network_import_check_cmd); install_element (BGP_NODE, &no_bgp_network_import_check_cmd); /* "bgp default local-preference" commands. */ install_element (BGP_NODE, &bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd); /* "neighbor remote-as" commands. */ install_element (BGP_NODE, &neighbor_remote_as_cmd); install_element (BGP_NODE, &no_neighbor_cmd); install_element (BGP_NODE, &no_neighbor_remote_as_cmd); /* "neighbor peer-group" commands. */ install_element (BGP_NODE, &neighbor_peer_group_cmd); install_element (BGP_NODE, &no_neighbor_peer_group_cmd); install_element (BGP_NODE, &no_neighbor_peer_group_remote_as_cmd); /* "neighbor local-as" commands. */ install_element (BGP_NODE, &neighbor_local_as_cmd); install_element (BGP_NODE, &neighbor_local_as_no_prepend_cmd); install_element (BGP_NODE, &neighbor_local_as_no_prepend_replace_as_cmd); install_element (BGP_NODE, &no_neighbor_local_as_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd); install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd); /* "neighbor password" commands. */ install_element (BGP_NODE, &neighbor_password_cmd); install_element (BGP_NODE, &no_neighbor_password_cmd); /* "neighbor activate" commands. */ install_element (BGP_NODE, &neighbor_activate_cmd); install_element (BGP_IPV4_NODE, &neighbor_activate_cmd); install_element (BGP_IPV4M_NODE, &neighbor_activate_cmd); install_element (BGP_IPV6_NODE, &neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &neighbor_activate_cmd); /* "no neighbor activate" commands. */ install_element (BGP_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_activate_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_activate_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_activate_cmd); /* "neighbor peer-group set" commands. */ install_element (BGP_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV4_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV4M_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV6_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &neighbor_set_peer_group_cmd); /* "no neighbor peer-group unset" commands. */ install_element (BGP_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_set_peer_group_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_set_peer_group_cmd); /* "neighbor softreconfiguration inbound" commands.*/ install_element (BGP_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4M_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6M_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &neighbor_soft_reconfiguration_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_soft_reconfiguration_cmd); /* "neighbor attribute-unchanged" commands. */ install_element (BGP_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_IPV4_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_IPV4M_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6M_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_attr_unchanged10_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged1_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged2_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged3_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged4_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged5_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged6_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged7_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged8_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV4_NODE, &neighbor_attr_unchanged10_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged1_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged2_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged3_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged4_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged5_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged6_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged7_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged8_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged9_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_attr_unchanged10_cmd); /* "nexthop-local unchanged" commands */ install_element (BGP_IPV6_NODE, &neighbor_nexthop_local_unchanged_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_local_unchanged_cmd); /* "transparent-as" and "transparent-nexthop" for old version compatibility. */ install_element (BGP_NODE, &neighbor_transparent_as_cmd); install_element (BGP_NODE, &neighbor_transparent_nexthop_cmd); /* "neighbor next-hop-self" commands. */ install_element (BGP_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV4_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV4M_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV6_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_IPV6M_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &neighbor_nexthop_self_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_nexthop_self_cmd); /* "neighbor remove-private-AS" commands. */ install_element (BGP_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_IPV4_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_IPV4M_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_IPV6_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_IPV6M_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &neighbor_remove_private_as_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_remove_private_as_cmd); /* "neighbor send-community" commands.*/ install_element (BGP_NODE, &neighbor_send_community_cmd); install_element (BGP_NODE, &neighbor_send_community_type_cmd); install_element (BGP_NODE, &no_neighbor_send_community_cmd); install_element (BGP_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_IPV4_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV4_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_IPV4M_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV4M_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_IPV6_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV6_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_IPV6M_NODE, &neighbor_send_community_cmd); install_element (BGP_IPV6M_NODE, &neighbor_send_community_type_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_send_community_type_cmd); install_element (BGP_VPNV4_NODE, &neighbor_send_community_cmd); install_element (BGP_VPNV4_NODE, &neighbor_send_community_type_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_send_community_type_cmd); /* "neighbor route-reflector" commands.*/ install_element (BGP_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV4_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_reflector_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_reflector_client_cmd); /* "neighbor route-server" commands.*/ install_element (BGP_NODE, &neighbor_route_server_client_cmd); install_element (BGP_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV4_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_server_client_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_server_client_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_server_client_cmd); /* "neighbor passive" commands. */ install_element (BGP_NODE, &neighbor_passive_cmd); install_element (BGP_NODE, &no_neighbor_passive_cmd); /* "neighbor shutdown" commands. */ install_element (BGP_NODE, &neighbor_shutdown_cmd); install_element (BGP_NODE, &no_neighbor_shutdown_cmd); /* Deprecated "neighbor capability route-refresh" commands.*/ install_element (BGP_NODE, &neighbor_capability_route_refresh_cmd); install_element (BGP_NODE, &no_neighbor_capability_route_refresh_cmd); /* "neighbor capability orf prefix-list" commands.*/ install_element (BGP_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4M_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6M_NODE, &neighbor_capability_orf_prefix_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_capability_orf_prefix_cmd); /* "neighbor capability dynamic" commands.*/ install_element (BGP_NODE, &neighbor_capability_dynamic_cmd); install_element (BGP_NODE, &no_neighbor_capability_dynamic_cmd); /* "neighbor dont-capability-negotiate" commands. */ install_element (BGP_NODE, &neighbor_dont_capability_negotiate_cmd); install_element (BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd); /* "neighbor ebgp-multihop" commands. */ install_element (BGP_NODE, &neighbor_ebgp_multihop_cmd); install_element (BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_cmd); install_element (BGP_NODE, &no_neighbor_ebgp_multihop_ttl_cmd); /* "neighbor disable-connected-check" commands. */ install_element (BGP_NODE, &neighbor_disable_connected_check_cmd); install_element (BGP_NODE, &no_neighbor_disable_connected_check_cmd); install_element (BGP_NODE, &neighbor_enforce_multihop_cmd); install_element (BGP_NODE, &no_neighbor_enforce_multihop_cmd); /* "neighbor description" commands. */ install_element (BGP_NODE, &neighbor_description_cmd); install_element (BGP_NODE, &no_neighbor_description_cmd); install_element (BGP_NODE, &no_neighbor_description_val_cmd); /* "neighbor update-source" commands. "*/ install_element (BGP_NODE, &neighbor_update_source_cmd); install_element (BGP_NODE, &no_neighbor_update_source_cmd); /* "neighbor default-originate" commands. */ install_element (BGP_NODE, &neighbor_default_originate_cmd); install_element (BGP_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_NODE, &no_neighbor_default_originate_rmap_cmd); install_element (BGP_IPV4_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV4_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_default_originate_rmap_cmd); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV4M_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV6_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_cmd); install_element (BGP_IPV6M_NODE, &neighbor_default_originate_rmap_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_default_originate_rmap_cmd); /* "neighbor port" commands. */ install_element (BGP_NODE, &neighbor_port_cmd); install_element (BGP_NODE, &no_neighbor_port_cmd); install_element (BGP_NODE, &no_neighbor_port_val_cmd); /* "neighbor weight" commands. */ install_element (BGP_NODE, &neighbor_weight_cmd); install_element (BGP_NODE, &no_neighbor_weight_cmd); install_element (BGP_NODE, &no_neighbor_weight_val_cmd); /* "neighbor override-capability" commands. */ install_element (BGP_NODE, &neighbor_override_capability_cmd); install_element (BGP_NODE, &no_neighbor_override_capability_cmd); /* "neighbor strict-capability-match" commands. */ install_element (BGP_NODE, &neighbor_strict_capability_cmd); install_element (BGP_NODE, &no_neighbor_strict_capability_cmd); /* "neighbor timers" commands. */ install_element (BGP_NODE, &neighbor_timers_cmd); install_element (BGP_NODE, &no_neighbor_timers_cmd); /* "neighbor timers connect" commands. */ install_element (BGP_NODE, &neighbor_timers_connect_cmd); install_element (BGP_NODE, &no_neighbor_timers_connect_cmd); install_element (BGP_NODE, &no_neighbor_timers_connect_val_cmd); /* "neighbor advertisement-interval" commands. */ install_element (BGP_NODE, &neighbor_advertise_interval_cmd); install_element (BGP_NODE, &no_neighbor_advertise_interval_cmd); install_element (BGP_NODE, &no_neighbor_advertise_interval_val_cmd); /* "neighbor version" commands. */ install_element (BGP_NODE, &neighbor_version_cmd); /* "neighbor interface" commands. */ install_element (BGP_NODE, &neighbor_interface_cmd); install_element (BGP_NODE, &no_neighbor_interface_cmd); /* "neighbor distribute" commands. */ install_element (BGP_NODE, &neighbor_distribute_list_cmd); install_element (BGP_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV4_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_distribute_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_distribute_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_distribute_list_cmd); /* "neighbor prefix-list" commands. */ install_element (BGP_NODE, &neighbor_prefix_list_cmd); install_element (BGP_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV4_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_prefix_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_prefix_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_prefix_list_cmd); /* "neighbor filter-list" commands. */ install_element (BGP_NODE, &neighbor_filter_list_cmd); install_element (BGP_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV4_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV4M_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV6_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_IPV6M_NODE, &neighbor_filter_list_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &neighbor_filter_list_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_filter_list_cmd); /* "neighbor route-map" commands. */ install_element (BGP_NODE, &neighbor_route_map_cmd); install_element (BGP_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV4_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV4M_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV6_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_route_map_cmd); install_element (BGP_IPV6M_NODE, &neighbor_route_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_route_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element (BGP_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV4_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV4M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV6_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &neighbor_unsuppress_map_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_unsuppress_map_cmd); /* "neighbor maximum-prefix" commands. */ install_element (BGP_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV4M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6M_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_warning_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV4_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_val_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_warning_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_warning_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_restart_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_threshold_restart_cmd); /* "neighbor allowas-in" */ install_element (BGP_NODE, &neighbor_allowas_in_cmd); install_element (BGP_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV4_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_IPV4_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV4M_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_IPV4M_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV6_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_IPV6_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_cmd); install_element (BGP_IPV6M_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_IPV6M_NODE, &no_neighbor_allowas_in_cmd); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_cmd); install_element (BGP_VPNV4_NODE, &neighbor_allowas_in_arg_cmd); install_element (BGP_VPNV4_NODE, &no_neighbor_allowas_in_cmd); /* address-family commands. */ install_element (BGP_NODE, &address_family_ipv4_cmd); install_element (BGP_NODE, &address_family_ipv4_safi_cmd); #ifdef HAVE_IPV6 install_element (BGP_NODE, &address_family_ipv6_cmd); install_element (BGP_NODE, &address_family_ipv6_safi_cmd); #endif /* HAVE_IPV6 */ install_element (BGP_NODE, &address_family_vpnv4_cmd); install_element (BGP_NODE, &address_family_vpnv4_unicast_cmd); /* "exit-address-family" command. */ install_element (BGP_IPV4_NODE, &exit_address_family_cmd); install_element (BGP_IPV4M_NODE, &exit_address_family_cmd); install_element (BGP_IPV6_NODE, &exit_address_family_cmd); install_element (BGP_IPV6M_NODE, &exit_address_family_cmd); install_element (BGP_VPNV4_NODE, &exit_address_family_cmd); /* "clear ip bgp commands" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_cmd); install_element (ENABLE_NODE, &clear_bgp_external_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_cmd); install_element (ENABLE_NODE, &clear_bgp_as_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft in" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_in_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_in_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_all_in_cmd); install_element (ENABLE_NODE, &clear_bgp_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_external_in_cmd); install_element (ENABLE_NODE, &clear_bgp_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_as_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_in_prefix_filter_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_in_prefix_filter_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft out" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_out_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_out_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_all_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_external_out_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_as_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_out_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_out_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor soft" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_group_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_external_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_ipv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_all_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_vpnv4_soft_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_as_vpnv4_soft_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_external_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_as_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_group_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_external_soft_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_as_soft_cmd); #endif /* HAVE_IPV6 */ /* "clear ip bgp neighbor rsclient" */ install_element (ENABLE_NODE, &clear_ip_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_instance_peer_rsclient_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &clear_bgp_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_all_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_instance_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_peer_rsclient_cmd); install_element (ENABLE_NODE, &clear_bgp_ipv6_instance_peer_rsclient_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp summary" commands. */ install_element (VIEW_NODE, &show_ip_bgp_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (RESTRICTED_NODE, &show_bgp_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp neighbors" commands. */ install_element (VIEW_NODE, &show_ip_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_neighbors_peer_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (VIEW_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_cmd); install_element (ENABLE_NODE, &show_bgp_instance_neighbors_peer_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_neighbors_peer_cmd); /* Old commands. */ install_element (VIEW_NODE, &show_ipv6_bgp_summary_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_summary_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_summary_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp rsclient" commands. */ install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd); #ifdef HAVE_IPV6 install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd); #endif /* HAVE_IPV6 */ /* "show ip bgp paths" commands. */ install_element (VIEW_NODE, &show_ip_bgp_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_paths_cmd); /* "show ip bgp community" commands. */ install_element (VIEW_NODE, &show_ip_bgp_community_info_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_info_cmd); /* "show ip bgp attribute-info" commands. */ install_element (VIEW_NODE, &show_ip_bgp_attr_info_cmd); install_element (ENABLE_NODE, &show_ip_bgp_attr_info_cmd); /* "redistribute" commands. */ install_element (BGP_NODE, &bgp_redistribute_ipv4_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_rmap_metric_cmd); install_element (BGP_NODE, &bgp_redistribute_ipv4_metric_rmap_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_rmap_metric_cmd); install_element (BGP_NODE, &no_bgp_redistribute_ipv4_metric_rmap_cmd); #ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); install_element (BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_rmap_metric_cmd); install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd); #endif /* HAVE_IPV6 */ /* ttl_security commands */ install_element (BGP_NODE, &neighbor_ttl_security_cmd); install_element (BGP_NODE, &no_neighbor_ttl_security_cmd); /* "show bgp memory" commands. */ install_element (VIEW_NODE, &show_bgp_memory_cmd); install_element (RESTRICTED_NODE, &show_bgp_memory_cmd); install_element (ENABLE_NODE, &show_bgp_memory_cmd); /* "show bgp views" commands. */ install_element (VIEW_NODE, &show_bgp_views_cmd); install_element (RESTRICTED_NODE, &show_bgp_views_cmd); install_element (ENABLE_NODE, &show_bgp_views_cmd); /* Community-list. */ community_list_vty (); } #include "memory.h" #include "bgp_regex.h" #include "bgp_clist.h" #include "bgp_ecommunity.h" /* VTY functions. */ /* Direction value to string conversion. */ static const char * community_direct_str (int direct) { switch (direct) { case COMMUNITY_DENY: return "deny"; case COMMUNITY_PERMIT: return "permit"; default: return "unknown"; } } /* Display error string. */ static void community_list_perror (struct vty *vty, int ret) { switch (ret) { case COMMUNITY_LIST_ERR_CANT_FIND_LIST: vty_out (vty, "%% Can't find community-list%s", VTY_NEWLINE); break; case COMMUNITY_LIST_ERR_MALFORMED_VAL: vty_out (vty, "%% Malformed community-list value%s", VTY_NEWLINE); break; case COMMUNITY_LIST_ERR_STANDARD_CONFLICT: vty_out (vty, "%% Community name conflict, previously defined as standard community%s", VTY_NEWLINE); break; case COMMUNITY_LIST_ERR_EXPANDED_CONFLICT: vty_out (vty, "%% Community name conflict, previously defined as expanded community%s", VTY_NEWLINE); break; } } /* VTY interface for community_set() function. */ static int community_list_set_vty (struct vty *vty, int argc, const char **argv, int style, int reject_all_digit_name) { int ret; int direct; char *str; /* Check the list type. */ if (strncmp (argv[1], "p", 1) == 0) direct = COMMUNITY_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) direct = COMMUNITY_DENY; else { vty_out (vty, "%% Matching condition must be permit or deny%s", VTY_NEWLINE); return CMD_WARNING; } /* All digit name check. */ if (reject_all_digit_name && all_digit (argv[0])) { vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); return CMD_WARNING; } /* Concat community string argument. */ if (argc > 1) str = argv_concat (argv, argc, 2); else str = NULL; /* When community_list_set() return nevetive value, it means malformed community string. */ ret = community_list_set (bgp_clist, argv[0], str, direct, style); /* Free temporary community list string allocated by argv_concat(). */ if (str) XFREE (MTYPE_TMP, str); if (ret < 0) { /* Display error string. */ community_list_perror (vty, ret); return CMD_WARNING; } return CMD_SUCCESS; } /* Communiyt-list entry delete. */ static int community_list_unset_vty (struct vty *vty, int argc, const char **argv, int style) { int ret; int direct = 0; char *str = NULL; if (argc > 1) { /* Check the list direct. */ if (strncmp (argv[1], "p", 1) == 0) direct = COMMUNITY_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) direct = COMMUNITY_DENY; else { vty_out (vty, "%% Matching condition must be permit or deny%s", VTY_NEWLINE); return CMD_WARNING; } /* Concat community string argument. */ str = argv_concat (argv, argc, 2); } /* Unset community list. */ ret = community_list_unset (bgp_clist, argv[0], str, direct, style); /* Free temporary community list string allocated by argv_concat(). */ if (str) XFREE (MTYPE_TMP, str); if (ret < 0) { community_list_perror (vty, ret); return CMD_WARNING; } return CMD_SUCCESS; } /* "community-list" keyword help string. */ #define COMMUNITY_LIST_STR "Add a community list entry\n" #define COMMUNITY_VAL_STR "Community number in aa:nn format or internet|local-AS|no-advertise|no-export\n" DEFUN (ip_community_list_standard, ip_community_list_standard_cmd, "ip community-list <1-99> (deny|permit) .AA:NN", IP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" COMMUNITY_VAL_STR) { return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 0); } ALIAS (ip_community_list_standard, ip_community_list_standard2_cmd, "ip community-list <1-99> (deny|permit)", IP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n") DEFUN (ip_community_list_expanded, ip_community_list_expanded_cmd, "ip community-list <100-500> (deny|permit) .LINE", IP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 0); } DEFUN (ip_community_list_name_standard, ip_community_list_name_standard_cmd, "ip community-list standard WORD (deny|permit) .AA:NN", IP_STR COMMUNITY_LIST_STR "Add a standard community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" COMMUNITY_VAL_STR) { return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD, 1); } ALIAS (ip_community_list_name_standard, ip_community_list_name_standard2_cmd, "ip community-list standard WORD (deny|permit)", IP_STR COMMUNITY_LIST_STR "Add a standard community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n") DEFUN (ip_community_list_name_expanded, ip_community_list_name_expanded_cmd, "ip community-list expanded WORD (deny|permit) .LINE", IP_STR COMMUNITY_LIST_STR "Add an expanded community-list entry\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return community_list_set_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED, 1); } DEFUN (no_ip_community_list_standard_all, no_ip_community_list_standard_all_cmd, "no ip community-list <1-99>", NO_STR IP_STR COMMUNITY_LIST_STR "Community list number (standard)\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_community_list_expanded_all, no_ip_community_list_expanded_all_cmd, "no ip community-list <100-500>", NO_STR IP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_community_list_name_standard_all, no_ip_community_list_name_standard_all_cmd, "no ip community-list standard WORD", NO_STR IP_STR COMMUNITY_LIST_STR "Add a standard community-list entry\n" "Community list name\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_community_list_name_expanded_all, no_ip_community_list_name_expanded_all_cmd, "no ip community-list expanded WORD", NO_STR IP_STR COMMUNITY_LIST_STR "Add an expanded community-list entry\n" "Community list name\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_community_list_standard, no_ip_community_list_standard_cmd, "no ip community-list <1-99> (deny|permit) .AA:NN", NO_STR IP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" COMMUNITY_VAL_STR) { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_community_list_expanded, no_ip_community_list_expanded_cmd, "no ip community-list <100-500> (deny|permit) .LINE", NO_STR IP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_community_list_name_standard, no_ip_community_list_name_standard_cmd, "no ip community-list standard WORD (deny|permit) .AA:NN", NO_STR IP_STR COMMUNITY_LIST_STR "Specify a standard community-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" COMMUNITY_VAL_STR) { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_STANDARD); } DEFUN (no_ip_community_list_name_expanded, no_ip_community_list_name_expanded_cmd, "no ip community-list expanded WORD (deny|permit) .LINE", NO_STR IP_STR COMMUNITY_LIST_STR "Specify an expanded community-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return community_list_unset_vty (vty, argc, argv, COMMUNITY_LIST_EXPANDED); } static void community_list_show (struct vty *vty, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry == list->head) { if (all_digit (list->name)) vty_out (vty, "Community %s list %s%s", entry->style == COMMUNITY_LIST_STANDARD ? "standard" : "(expanded) access", list->name, VTY_NEWLINE); else vty_out (vty, "Named Community %s list %s%s", entry->style == COMMUNITY_LIST_STANDARD ? "standard" : "expanded", list->name, VTY_NEWLINE); } if (entry->any) vty_out (vty, " %s%s", community_direct_str (entry->direct), VTY_NEWLINE); else vty_out (vty, " %s %s%s", community_direct_str (entry->direct), entry->style == COMMUNITY_LIST_STANDARD ? community_str (entry->u.com) : entry->config, VTY_NEWLINE); } } DEFUN (show_ip_community_list, show_ip_community_list_cmd, "show ip community-list", SHOW_STR IP_STR "List community-list\n") { struct community_list *list; struct community_list_master *cm; cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER); if (! cm) return CMD_SUCCESS; for (list = cm->num.head; list; list = list->next) community_list_show (vty, list); for (list = cm->str.head; list; list = list->next) community_list_show (vty, list); return CMD_SUCCESS; } DEFUN (show_ip_community_list_arg, show_ip_community_list_arg_cmd, "show ip community-list (<1-500>|WORD)", SHOW_STR IP_STR "List community-list\n" "Community-list number\n" "Community-list name\n") { struct community_list *list; list = community_list_lookup (bgp_clist, argv[0], COMMUNITY_LIST_MASTER); if (! list) { vty_out (vty, "%% Can't find community-list%s", VTY_NEWLINE); return CMD_WARNING; } community_list_show (vty, list); return CMD_SUCCESS; } static int extcommunity_list_set_vty (struct vty *vty, int argc, const char **argv, int style, int reject_all_digit_name) { int ret; int direct; char *str; /* Check the list type. */ if (strncmp (argv[1], "p", 1) == 0) direct = COMMUNITY_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) direct = COMMUNITY_DENY; else { vty_out (vty, "%% Matching condition must be permit or deny%s", VTY_NEWLINE); return CMD_WARNING; } /* All digit name check. */ if (reject_all_digit_name && all_digit (argv[0])) { vty_out (vty, "%% Community name cannot have all digits%s", VTY_NEWLINE); return CMD_WARNING; } /* Concat community string argument. */ if (argc > 1) str = argv_concat (argv, argc, 2); else str = NULL; ret = extcommunity_list_set (bgp_clist, argv[0], str, direct, style); /* Free temporary community list string allocated by argv_concat(). */ if (str) XFREE (MTYPE_TMP, str); if (ret < 0) { community_list_perror (vty, ret); return CMD_WARNING; } return CMD_SUCCESS; } static int extcommunity_list_unset_vty (struct vty *vty, int argc, const char **argv, int style) { int ret; int direct = 0; char *str = NULL; if (argc > 1) { /* Check the list direct. */ if (strncmp (argv[1], "p", 1) == 0) direct = COMMUNITY_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) direct = COMMUNITY_DENY; else { vty_out (vty, "%% Matching condition must be permit or deny%s", VTY_NEWLINE); return CMD_WARNING; } /* Concat community string argument. */ str = argv_concat (argv, argc, 2); } /* Unset community list. */ ret = extcommunity_list_unset (bgp_clist, argv[0], str, direct, style); /* Free temporary community list string allocated by argv_concat(). */ if (str) XFREE (MTYPE_TMP, str); if (ret < 0) { community_list_perror (vty, ret); return CMD_WARNING; } return CMD_SUCCESS; } /* "extcommunity-list" keyword help string. */ #define EXTCOMMUNITY_LIST_STR "Add a extended community list entry\n" #define EXTCOMMUNITY_VAL_STR "Extended community attribute in 'rt aa:nn_or_IPaddr:nn' OR 'soo aa:nn_or_IPaddr:nn' format\n" DEFUN (ip_extcommunity_list_standard, ip_extcommunity_list_standard_cmd, "ip extcommunity-list <1-99> (deny|permit) .AA:NN", IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" EXTCOMMUNITY_VAL_STR) { return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 0); } ALIAS (ip_extcommunity_list_standard, ip_extcommunity_list_standard2_cmd, "ip extcommunity-list <1-99> (deny|permit)", IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n") DEFUN (ip_extcommunity_list_expanded, ip_extcommunity_list_expanded_cmd, "ip extcommunity-list <100-500> (deny|permit) .LINE", IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 0); } DEFUN (ip_extcommunity_list_name_standard, ip_extcommunity_list_name_standard_cmd, "ip extcommunity-list standard WORD (deny|permit) .AA:NN", IP_STR EXTCOMMUNITY_LIST_STR "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" EXTCOMMUNITY_VAL_STR) { return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD, 1); } ALIAS (ip_extcommunity_list_name_standard, ip_extcommunity_list_name_standard2_cmd, "ip extcommunity-list standard WORD (deny|permit)", IP_STR EXTCOMMUNITY_LIST_STR "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n") DEFUN (ip_extcommunity_list_name_expanded, ip_extcommunity_list_name_expanded_cmd, "ip extcommunity-list expanded WORD (deny|permit) .LINE", IP_STR EXTCOMMUNITY_LIST_STR "Specify expanded extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return extcommunity_list_set_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED, 1); } DEFUN (no_ip_extcommunity_list_standard_all, no_ip_extcommunity_list_standard_all_cmd, "no ip extcommunity-list <1-99>", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); } DEFUN (no_ip_extcommunity_list_expanded_all, no_ip_extcommunity_list_expanded_all_cmd, "no ip extcommunity-list <100-500>", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_extcommunity_list_name_standard_all, no_ip_extcommunity_list_name_standard_all_cmd, "no ip extcommunity-list standard WORD", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Specify standard extcommunity-list\n" "Extended Community list name\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); } DEFUN (no_ip_extcommunity_list_name_expanded_all, no_ip_extcommunity_list_name_expanded_all_cmd, "no ip extcommunity-list expanded WORD", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Specify expanded extcommunity-list\n" "Extended Community list name\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_extcommunity_list_standard, no_ip_extcommunity_list_standard_cmd, "no ip extcommunity-list <1-99> (deny|permit) .AA:NN", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" "Specify community to reject\n" "Specify community to accept\n" EXTCOMMUNITY_VAL_STR) { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); } DEFUN (no_ip_extcommunity_list_expanded, no_ip_extcommunity_list_expanded_cmd, "no ip extcommunity-list <100-500> (deny|permit) .LINE", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); } DEFUN (no_ip_extcommunity_list_name_standard, no_ip_extcommunity_list_name_standard_cmd, "no ip extcommunity-list standard WORD (deny|permit) .AA:NN", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Specify standard extcommunity-list\n" "Extended Community list name\n" "Specify community to reject\n" "Specify community to accept\n" EXTCOMMUNITY_VAL_STR) { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_STANDARD); } DEFUN (no_ip_extcommunity_list_name_expanded, no_ip_extcommunity_list_name_expanded_cmd, "no ip extcommunity-list expanded WORD (deny|permit) .LINE", NO_STR IP_STR EXTCOMMUNITY_LIST_STR "Specify expanded extcommunity-list\n" "Community list name\n" "Specify community to reject\n" "Specify community to accept\n" "An ordered list as a regular-expression\n") { return extcommunity_list_unset_vty (vty, argc, argv, EXTCOMMUNITY_LIST_EXPANDED); } static void extcommunity_list_show (struct vty *vty, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry == list->head) { if (all_digit (list->name)) vty_out (vty, "Extended community %s list %s%s", entry->style == EXTCOMMUNITY_LIST_STANDARD ? "standard" : "(expanded) access", list->name, VTY_NEWLINE); else vty_out (vty, "Named extended community %s list %s%s", entry->style == EXTCOMMUNITY_LIST_STANDARD ? "standard" : "expanded", list->name, VTY_NEWLINE); } if (entry->any) vty_out (vty, " %s%s", community_direct_str (entry->direct), VTY_NEWLINE); else vty_out (vty, " %s %s%s", community_direct_str (entry->direct), entry->style == EXTCOMMUNITY_LIST_STANDARD ? entry->u.ecom->str : entry->config, VTY_NEWLINE); } } DEFUN (show_ip_extcommunity_list, show_ip_extcommunity_list_cmd, "show ip extcommunity-list", SHOW_STR IP_STR "List extended-community list\n") { struct community_list *list; struct community_list_master *cm; cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER); if (! cm) return CMD_SUCCESS; for (list = cm->num.head; list; list = list->next) extcommunity_list_show (vty, list); for (list = cm->str.head; list; list = list->next) extcommunity_list_show (vty, list); return CMD_SUCCESS; } DEFUN (show_ip_extcommunity_list_arg, show_ip_extcommunity_list_arg_cmd, "show ip extcommunity-list (<1-500>|WORD)", SHOW_STR IP_STR "List extended-community list\n" "Extcommunity-list number\n" "Extcommunity-list name\n") { struct community_list *list; list = community_list_lookup (bgp_clist, argv[0], EXTCOMMUNITY_LIST_MASTER); if (! list) { vty_out (vty, "%% Can't find extcommunity-list%s", VTY_NEWLINE); return CMD_WARNING; } extcommunity_list_show (vty, list); return CMD_SUCCESS; } /* Return configuration string of community-list entry. */ static const char * community_list_config_str (struct community_entry *entry) { const char *str; if (entry->any) str = ""; else { if (entry->style == COMMUNITY_LIST_STANDARD) str = community_str (entry->u.com); else str = entry->config; } return str; } /* Display community-list and extcommunity-list configuration. */ static int community_list_config_write (struct vty *vty) { struct community_list *list; struct community_entry *entry; struct community_list_master *cm; int write = 0; /* Community-list. */ cm = community_list_master_lookup (bgp_clist, COMMUNITY_LIST_MASTER); for (list = cm->num.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { vty_out (vty, "ip community-list %s %s %s%s", list->name, community_direct_str (entry->direct), community_list_config_str (entry), VTY_NEWLINE); write++; } for (list = cm->str.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { vty_out (vty, "ip community-list %s %s %s %s%s", entry->style == COMMUNITY_LIST_STANDARD ? "standard" : "expanded", list->name, community_direct_str (entry->direct), community_list_config_str (entry), VTY_NEWLINE); write++; } /* Extcommunity-list. */ cm = community_list_master_lookup (bgp_clist, EXTCOMMUNITY_LIST_MASTER); for (list = cm->num.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { vty_out (vty, "ip extcommunity-list %s %s %s%s", list->name, community_direct_str (entry->direct), community_list_config_str (entry), VTY_NEWLINE); write++; } for (list = cm->str.head; list; list = list->next) for (entry = list->head; entry; entry = entry->next) { vty_out (vty, "ip extcommunity-list %s %s %s %s%s", entry->style == EXTCOMMUNITY_LIST_STANDARD ? "standard" : "expanded", list->name, community_direct_str (entry->direct), community_list_config_str (entry), VTY_NEWLINE); write++; } return write; } static struct cmd_node community_list_node = { COMMUNITY_LIST_NODE, "", 1 /* Export to vtysh. */ }; static void community_list_vty (void) { install_node (&community_list_node, community_list_config_write); /* Community-list. */ install_element (CONFIG_NODE, &ip_community_list_standard_cmd); install_element (CONFIG_NODE, &ip_community_list_standard2_cmd); install_element (CONFIG_NODE, &ip_community_list_expanded_cmd); install_element (CONFIG_NODE, &ip_community_list_name_standard_cmd); install_element (CONFIG_NODE, &ip_community_list_name_standard2_cmd); install_element (CONFIG_NODE, &ip_community_list_name_expanded_cmd); install_element (CONFIG_NODE, &no_ip_community_list_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_community_list_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_community_list_standard_cmd); install_element (CONFIG_NODE, &no_ip_community_list_expanded_cmd); install_element (CONFIG_NODE, &no_ip_community_list_name_standard_cmd); install_element (CONFIG_NODE, &no_ip_community_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_community_list_cmd); install_element (VIEW_NODE, &show_ip_community_list_arg_cmd); install_element (ENABLE_NODE, &show_ip_community_list_cmd); install_element (ENABLE_NODE, &show_ip_community_list_arg_cmd); /* Extcommunity-list. */ install_element (CONFIG_NODE, &ip_extcommunity_list_standard_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_standard2_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_standard2_cmd); install_element (CONFIG_NODE, &ip_extcommunity_list_name_expanded_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_all_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_standard_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_expanded_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_standard_cmd); install_element (CONFIG_NODE, &no_ip_extcommunity_list_name_expanded_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_cmd); install_element (VIEW_NODE, &show_ip_extcommunity_list_arg_cmd); install_element (ENABLE_NODE, &show_ip_extcommunity_list_cmd); install_element (ENABLE_NODE, &show_ip_extcommunity_list_arg_cmd); } quagga-0.99.24.1/bgpd/bgp_advertise.c0000644000175000017500000002256212476520570014141 00000000000000/* BGP advertisement and adjacency Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "memory.h" #include "prefix.h" #include "hash.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" /* BGP advertise attribute is used for pack same attribute update into one packet. To do that we maintain attribute hash in struct peer. */ static struct bgp_advertise_attr * baa_new (void) { return (struct bgp_advertise_attr *) XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); } static void baa_free (struct bgp_advertise_attr *baa) { XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); } static void * baa_hash_alloc (void *p) { struct bgp_advertise_attr * ref = (struct bgp_advertise_attr *) p; struct bgp_advertise_attr *baa; baa = baa_new (); baa->attr = ref->attr; return baa; } static unsigned int baa_hash_key (void *p) { struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p; return attrhash_key_make (baa->attr); } static int baa_hash_cmp (const void *p1, const void *p2) { const struct bgp_advertise_attr * baa1 = p1; const struct bgp_advertise_attr * baa2 = p2; return attrhash_cmp (baa1->attr, baa2->attr); } /* BGP update and withdraw information is stored in BGP advertise structure. This structure is referred from BGP adjacency information. */ static struct bgp_advertise * bgp_advertise_new (void) { return (struct bgp_advertise *) XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); } static void bgp_advertise_free (struct bgp_advertise *adv) { if (adv->binfo) bgp_info_unlock (adv->binfo); /* bgp_advertise bgp_info reference */ XFREE (MTYPE_BGP_ADVERTISE, adv); } static void bgp_advertise_add (struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { adv->next = baa->adv; if (baa->adv) baa->adv->prev = adv; baa->adv = adv; } static void bgp_advertise_delete (struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { if (adv->next) adv->next->prev = adv->prev; if (adv->prev) adv->prev->next = adv->next; else baa->adv = adv->next; } static struct bgp_advertise_attr * bgp_advertise_intern (struct hash *hash, struct attr *attr) { struct bgp_advertise_attr ref; struct bgp_advertise_attr *baa; ref.attr = bgp_attr_intern (attr); baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); baa->refcnt++; return baa; } static void bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) { if (baa->refcnt) baa->refcnt--; if (baa->refcnt && baa->attr) bgp_attr_unintern (&baa->attr); else { if (baa->attr) { hash_release (hash, baa); bgp_attr_unintern (&baa->attr); } baa_free (baa); } } /* BGP adjacency keeps minimal advertisement information. */ static void bgp_adj_out_free (struct bgp_adj_out *adj) { peer_unlock (adj->peer); /* adj_out peer reference */ XFREE (MTYPE_BGP_ADJ_OUT, adj); } int bgp_adj_out_lookup (struct peer *peer, struct prefix *p, afi_t afi, safi_t safi, struct bgp_node *rn) { struct bgp_adj_out *adj; for (adj = rn->adj_out; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return 0; return (adj->adv ? (adj->adv->baa ? 1 : 0) : (adj->attr ? 1 : 0)); } struct bgp_advertise * bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, afi_t afi, safi_t safi) { struct bgp_advertise *adv; struct bgp_advertise_attr *baa; struct bgp_advertise *next; adv = adj->adv; baa = adv->baa; next = NULL; if (baa) { /* Unlink myself from advertise attribute FIFO. */ bgp_advertise_delete (baa, adv); /* Fetch next advertise candidate. */ next = baa->adv; /* Unintern BGP advertise attribute. */ bgp_advertise_unintern (peer->hash[afi][safi], baa); } /* Unlink myself from advertisement FIFO. */ FIFO_DEL (adv); /* Free memory. */ bgp_advertise_free (adj->adv); adj->adv = NULL; return next; } void bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, struct bgp_info *binfo) { struct bgp_adj_out *adj = NULL; struct bgp_advertise *adv; if (DISABLE_BGP_ANNOUNCE) return; /* Look for adjacency information. */ if (rn) { for (adj = rn->adj_out; adj; adj = adj->next) if (adj->peer == peer) break; } if (! adj) { adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); adj->peer = peer_lock (peer); /* adj_out peer reference */ if (rn) { BGP_ADJ_OUT_ADD (rn, adj); bgp_lock_node (rn); } } if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); adj->adv = bgp_advertise_new (); adv = adj->adv; adv->rn = rn; assert (adv->binfo == NULL); adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */ if (attr) adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); else adv->baa = baa_new (); adv->adj = adj; /* Add new advertisement to advertisement attribute list. */ bgp_advertise_add (adv->baa, adv); FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); } void bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_adj_out *adj; struct bgp_advertise *adv; if (DISABLE_BGP_ANNOUNCE) return; /* Lookup existing adjacency, if it is not there return immediately. */ for (adj = rn->adj_out; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return; /* Clearn up previous advertisement. */ if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); if (adj->attr) { /* We need advertisement structure. */ adj->adv = bgp_advertise_new (); adv = adj->adv; adv->rn = rn; adv->adj = adj; /* Add to synchronization entry for withdraw announcement. */ FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); /* Schedule packet write. */ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } else { /* Remove myself from adjacency. */ BGP_ADJ_OUT_DEL (rn, adj); /* Free allocated information. */ bgp_adj_out_free (adj); bgp_unlock_node (rn); } } void bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, struct peer *peer, afi_t afi, safi_t safi) { if (adj->attr) bgp_attr_unintern (&adj->attr); if (adj->adv) bgp_advertise_clean (peer, adj, afi, safi); BGP_ADJ_OUT_DEL (rn, adj); bgp_adj_out_free (adj); } void bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) { struct bgp_adj_in *adj; for (adj = rn->adj_in; adj; adj = adj->next) { if (adj->peer == peer) { if (adj->attr != attr) { bgp_attr_unintern (&adj->attr); adj->attr = bgp_attr_intern (attr); } return; } } adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); adj->peer = peer_lock (peer); /* adj_in peer reference */ adj->attr = bgp_attr_intern (attr); BGP_ADJ_IN_ADD (rn, adj); bgp_lock_node (rn); } void bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) { bgp_attr_unintern (&bai->attr); BGP_ADJ_IN_DEL (rn, bai); peer_unlock (bai->peer); /* adj_in peer reference */ XFREE (MTYPE_BGP_ADJ_IN, bai); } void bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) { struct bgp_adj_in *adj; for (adj = rn->adj_in; adj; adj = adj->next) if (adj->peer == peer) break; if (! adj) return; bgp_adj_in_remove (rn, adj); bgp_unlock_node (rn); } void bgp_sync_init (struct peer *peer) { afi_t afi; safi_t safi; struct bgp_synchronize *sync; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { sync = XCALLOC (MTYPE_BGP_SYNCHRONISE, sizeof (struct bgp_synchronize)); FIFO_INIT (&sync->update); FIFO_INIT (&sync->withdraw); FIFO_INIT (&sync->withdraw_low); peer->sync[afi][safi] = sync; peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); } } void bgp_sync_delete (struct peer *peer) { afi_t afi; safi_t safi; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (peer->sync[afi][safi]) XFREE (MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); peer->sync[afi][safi] = NULL; if (peer->hash[afi][safi]) hash_free (peer->hash[afi][safi]); peer->hash[afi][safi] = NULL; } } quagga-0.99.24.1/bgpd/bgp_table.c0000644000175000017500000000507312476520570013240 00000000000000/* BGP routing table Copyright (C) 1998, 2001 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "memory.h" #include "sockunion.h" #include "vty.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" void bgp_table_lock (struct bgp_table *rt) { rt->lock++; } void bgp_table_unlock (struct bgp_table *rt) { assert (rt->lock > 0); rt->lock--; if (rt->lock != 0) { return; } route_table_finish (rt->route_table); rt->route_table = NULL; if (rt->owner) { peer_unlock (rt->owner); rt->owner = NULL; } XFREE (MTYPE_BGP_TABLE, rt); } void bgp_table_finish (struct bgp_table **rt) { if (*rt != NULL) { bgp_table_unlock(*rt); *rt = NULL; } } /* * bgp_node_create */ static struct route_node * bgp_node_create (route_table_delegate_t *delegate, struct route_table *table) { struct bgp_node *node; node = XCALLOC (MTYPE_BGP_NODE, sizeof (struct bgp_node)); return bgp_node_to_rnode (node); } /* * bgp_node_destroy */ static void bgp_node_destroy (route_table_delegate_t *delegate, struct route_table *table, struct route_node *node) { struct bgp_node *bgp_node; bgp_node = bgp_node_from_rnode (node); XFREE (MTYPE_BGP_NODE, bgp_node); } /* * Function vector to customize the behavior of the route table * library for BGP route tables. */ route_table_delegate_t bgp_table_delegate = { .create_node = bgp_node_create, .destroy_node = bgp_node_destroy }; /* * bgp_table_init */ struct bgp_table * bgp_table_init (afi_t afi, safi_t safi) { struct bgp_table *rt; rt = XCALLOC (MTYPE_BGP_TABLE, sizeof (struct bgp_table)); rt->route_table = route_table_init_with_delegate (&bgp_table_delegate); /* * Set up back pointer to bgp_table. */ rt->route_table->info = rt; bgp_table_lock (rt); rt->type = BGP_TABLE_MAIN; rt->afi = afi; rt->safi = safi; return rt; } quagga-0.99.24.1/bgpd/bgp_damp.c0000644000175000017500000004203412476520570013070 00000000000000/* BGP flap dampening Copyright (C) 2001 IP Infusion Inc. This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "prefix.h" #include "memory.h" #include "command.h" #include "log.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_advertise.h" /* Global variable to access damping configuration */ struct bgp_damp_config bgp_damp_cfg; static struct bgp_damp_config *damp = &bgp_damp_cfg; /* Utility macro to add and delete BGP dampening information to no used list. */ #define BGP_DAMP_LIST_ADD(N,A) BGP_INFO_ADD(N,A,no_reuse_list) #define BGP_DAMP_LIST_DEL(N,A) BGP_INFO_DEL(N,A,no_reuse_list) /* Calculate reuse list index by penalty value. */ static int bgp_reuse_index (int penalty) { unsigned int i; int index; i = (int)(((double) penalty / damp->reuse_limit - 1.0) * damp->scale_factor); if ( i >= damp->reuse_index_size ) i = damp->reuse_index_size - 1; index = damp->reuse_index[i] - damp->reuse_index[0]; return (damp->reuse_offset + index) % damp->reuse_list_size; } /* Add BGP dampening information to reuse list. */ static void bgp_reuse_list_add (struct bgp_damp_info *bdi) { int index; index = bdi->index = bgp_reuse_index (bdi->penalty); bdi->prev = NULL; bdi->next = damp->reuse_list[index]; if (damp->reuse_list[index]) damp->reuse_list[index]->prev = bdi; damp->reuse_list[index] = bdi; } /* Delete BGP dampening information from reuse list. */ static void bgp_reuse_list_delete (struct bgp_damp_info *bdi) { if (bdi->next) bdi->next->prev = bdi->prev; if (bdi->prev) bdi->prev->next = bdi->next; else damp->reuse_list[bdi->index] = bdi->next; } /* Return decayed penalty value. */ int bgp_damp_decay (time_t tdiff, int penalty) { unsigned int i; i = (int) ((double) tdiff / DELTA_T); if (i == 0) return penalty; if (i >= damp->decay_array_size) return 0; return (int) (penalty * damp->decay_array[i]); } /* Handler of reuse timer event. Each route in the current reuse-list is evaluated. RFC2439 Section 4.8.7. */ static int bgp_reuse_timer (struct thread *t) { struct bgp_damp_info *bdi; struct bgp_damp_info *next; time_t t_now, t_diff; damp->t_reuse = NULL; damp->t_reuse = thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); t_now = bgp_clock (); /* 1. save a pointer to the current zeroth queue head and zero the list head entry. */ bdi = damp->reuse_list[damp->reuse_offset]; damp->reuse_list[damp->reuse_offset] = NULL; /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby rotating the circular queue of list-heads. */ damp->reuse_offset = (damp->reuse_offset + 1) % damp->reuse_list_size; /* 3. if ( the saved list head pointer is non-empty ) */ for (; bdi; bdi = next) { struct bgp *bgp = bdi->binfo->peer->bgp; next = bdi->next; /* Set t-diff = t-now - t-updated. */ t_diff = t_now - bdi->t_updated; /* Set figure-of-merit = figure-of-merit * decay-array-ok [t-diff] */ bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); /* Set t-updated = t-now. */ bdi->t_updated = t_now; /* if (figure-of-merit < reuse). */ if (bdi->penalty < damp->reuse_limit) { /* Reuse the route. */ bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_DAMPED); bdi->suppress_time = 0; if (bdi->lastrecord == BGP_RECORD_UPDATE) { bgp_info_unset_flag (bdi->rn, bdi->binfo, BGP_INFO_HISTORY); bgp_aggregate_increment (bgp, &bdi->rn->p, bdi->binfo, bdi->afi, bdi->safi); bgp_process (bgp, bdi->rn, bdi->afi, bdi->safi); } if (bdi->penalty <= damp->reuse_limit / 2.0) bgp_damp_info_free (bdi, 1); else BGP_DAMP_LIST_ADD (damp, bdi); } else /* Re-insert into another list (See RFC2439 Section 4.8.6). */ bgp_reuse_list_add (bdi); } return 0; } /* A route becomes unreachable (RFC2439 Section 4.8.2). */ int bgp_damp_withdraw (struct bgp_info *binfo, struct bgp_node *rn, afi_t afi, safi_t safi, int attr_change) { time_t t_now; struct bgp_damp_info *bdi = NULL; double last_penalty = 0; t_now = bgp_clock (); /* Processing Unreachable Messages. */ if (binfo->extra) bdi = binfo->extra->damp_info; if (bdi == NULL) { /* If there is no previous stability history. */ /* RFC2439 said: 1. allocate a damping structure. 2. set figure-of-merit = 1. 3. withdraw the route. */ bdi = XCALLOC (MTYPE_BGP_DAMP_INFO, sizeof (struct bgp_damp_info)); bdi->binfo = binfo; bdi->rn = rn; bdi->penalty = (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY); bdi->flap = 1; bdi->start_time = t_now; bdi->suppress_time = 0; bdi->index = -1; bdi->afi = afi; bdi->safi = safi; (bgp_info_extra_get (binfo))->damp_info = bdi; BGP_DAMP_LIST_ADD (damp, bdi); } else { last_penalty = bdi->penalty; /* 1. Set t-diff = t-now - t-updated. */ bdi->penalty = (bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty) + (attr_change ? DEFAULT_PENALTY / 2 : DEFAULT_PENALTY)); if (bdi->penalty > damp->ceiling) bdi->penalty = damp->ceiling; bdi->flap++; } assert ((rn == bdi->rn) && (binfo == bdi->binfo)); bdi->lastrecord = BGP_RECORD_WITHDRAW; bdi->t_updated = t_now; /* Make this route as historical status. */ bgp_info_set_flag (rn, binfo, BGP_INFO_HISTORY); /* Remove the route from a reuse list if it is on one. */ if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED)) { /* If decay rate isn't equal to 0, reinsert brn. */ if (bdi->penalty != last_penalty) { bgp_reuse_list_delete (bdi); bgp_reuse_list_add (bdi); } return BGP_DAMP_SUPPRESSED; } /* If not suppressed before, do annonunce this withdraw and insert into reuse_list. */ if (bdi->penalty >= damp->suppress_value) { bgp_info_set_flag (rn, binfo, BGP_INFO_DAMPED); bdi->suppress_time = t_now; BGP_DAMP_LIST_DEL (damp, bdi); bgp_reuse_list_add (bdi); } return BGP_DAMP_USED; } int bgp_damp_update (struct bgp_info *binfo, struct bgp_node *rn, afi_t afi, safi_t safi) { time_t t_now; struct bgp_damp_info *bdi; int status; if (!binfo->extra || !((bdi = binfo->extra->damp_info))) return BGP_DAMP_USED; t_now = bgp_clock (); bgp_info_unset_flag (rn, binfo, BGP_INFO_HISTORY); bdi->lastrecord = BGP_RECORD_UPDATE; bdi->penalty = bgp_damp_decay (t_now - bdi->t_updated, bdi->penalty); if (! CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) && (bdi->penalty < damp->suppress_value)) status = BGP_DAMP_USED; else if (CHECK_FLAG (bdi->binfo->flags, BGP_INFO_DAMPED) && (bdi->penalty < damp->reuse_limit) ) { bgp_info_unset_flag (rn, binfo, BGP_INFO_DAMPED); bgp_reuse_list_delete (bdi); BGP_DAMP_LIST_ADD (damp, bdi); bdi->suppress_time = 0; status = BGP_DAMP_USED; } else status = BGP_DAMP_SUPPRESSED; if (bdi->penalty > damp->reuse_limit / 2.0) bdi->t_updated = t_now; else bgp_damp_info_free (bdi, 0); return status; } /* Remove dampening information and history route. */ int bgp_damp_scan (struct bgp_info *binfo, afi_t afi, safi_t safi) { time_t t_now, t_diff; struct bgp_damp_info *bdi; assert (binfo->extra && binfo->extra->damp_info); t_now = bgp_clock (); bdi = binfo->extra->damp_info; if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) { t_diff = t_now - bdi->suppress_time; if (t_diff >= damp->max_suppress_time) { bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_DAMPED); bgp_reuse_list_delete (bdi); BGP_DAMP_LIST_ADD (damp, bdi); bdi->penalty = damp->reuse_limit; bdi->suppress_time = 0; bdi->t_updated = t_now; /* Need to announce UPDATE once this binfo is usable again. */ if (bdi->lastrecord == BGP_RECORD_UPDATE) return 1; else return 0; } } else { t_diff = t_now - bdi->t_updated; bdi->penalty = bgp_damp_decay (t_diff, bdi->penalty); if (bdi->penalty <= damp->reuse_limit / 2.0) { /* release the bdi, bdi->binfo. */ bgp_damp_info_free (bdi, 1); return 0; } else bdi->t_updated = t_now; } return 0; } void bgp_damp_info_free (struct bgp_damp_info *bdi, int withdraw) { struct bgp_info *binfo; if (! bdi) return; binfo = bdi->binfo; binfo->extra->damp_info = NULL; if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) bgp_reuse_list_delete (bdi); else BGP_DAMP_LIST_DEL (damp, bdi); bgp_info_unset_flag (bdi->rn, binfo, BGP_INFO_HISTORY|BGP_INFO_DAMPED); if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) bgp_info_delete (bdi->rn, binfo); XFREE (MTYPE_BGP_DAMP_INFO, bdi); } static void bgp_damp_parameter_set (int hlife, int reuse, int sup, int maxsup) { double reuse_max_ratio; unsigned int i; double j; damp->suppress_value = sup; damp->half_life = hlife; damp->reuse_limit = reuse; damp->max_suppress_time = maxsup; /* Initialize params per bgp_damp_config. */ damp->reuse_index_size = REUSE_ARRAY_SIZE; damp->ceiling = (int)(damp->reuse_limit * (pow(2, (double)damp->max_suppress_time/damp->half_life))); /* Decay-array computations */ damp->decay_array_size = ceil ((double) damp->max_suppress_time / DELTA_T); damp->decay_array = XMALLOC (MTYPE_BGP_DAMP_ARRAY, sizeof(double) * (damp->decay_array_size)); damp->decay_array[0] = 1.0; damp->decay_array[1] = exp ((1.0/((double)damp->half_life/DELTA_T)) * log(0.5)); /* Calculate decay values for all possible times */ for (i = 2; i < damp->decay_array_size; i++) damp->decay_array[i] = damp->decay_array[i-1] * damp->decay_array[1]; /* Reuse-list computations */ i = ceil ((double)damp->max_suppress_time / DELTA_REUSE) + 1; if (i > REUSE_LIST_SIZE || i == 0) i = REUSE_LIST_SIZE; damp->reuse_list_size = i; damp->reuse_list = XCALLOC (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list_size * sizeof (struct bgp_reuse_node *)); /* Reuse-array computations */ damp->reuse_index = XCALLOC (MTYPE_BGP_DAMP_ARRAY, sizeof(int) * damp->reuse_index_size); reuse_max_ratio = (double)damp->ceiling/damp->reuse_limit; j = (exp((double)damp->max_suppress_time/damp->half_life) * log10(2.0)); if ( reuse_max_ratio > j && j != 0 ) reuse_max_ratio = j; damp->scale_factor = (double)damp->reuse_index_size/(reuse_max_ratio - 1); for (i = 0; i < damp->reuse_index_size; i++) { damp->reuse_index[i] = (int)(((double)damp->half_life / DELTA_REUSE) * log10 (1.0 / (damp->reuse_limit * ( 1.0 + ((double)i/damp->scale_factor)))) / log10(0.5)); } } int bgp_damp_enable (struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max) { if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { if (damp->half_life == half && damp->reuse_limit == reuse && damp->suppress_value == suppress && damp->max_suppress_time == max) return 0; bgp_damp_disable (bgp, afi, safi); } SET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); bgp_damp_parameter_set (half, reuse, suppress, max); /* Register reuse timer. */ if (! damp->t_reuse) damp->t_reuse = thread_add_timer (master, bgp_reuse_timer, NULL, DELTA_REUSE); return 0; } static void bgp_damp_config_clean (struct bgp_damp_config *damp) { /* Free decay array */ XFREE (MTYPE_BGP_DAMP_ARRAY, damp->decay_array); /* Free reuse index array */ XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_index); /* Free reuse list array. */ XFREE (MTYPE_BGP_DAMP_ARRAY, damp->reuse_list); } /* Clean all the bgp_damp_info stored in reuse_list. */ void bgp_damp_info_clean (void) { unsigned int i; struct bgp_damp_info *bdi, *next; damp->reuse_offset = 0; for (i = 0; i < damp->reuse_list_size; i++) { if (! damp->reuse_list[i]) continue; for (bdi = damp->reuse_list[i]; bdi; bdi = next) { next = bdi->next; bgp_damp_info_free (bdi, 1); } damp->reuse_list[i] = NULL; } for (bdi = damp->no_reuse_list; bdi; bdi = next) { next = bdi->next; bgp_damp_info_free (bdi, 1); } damp->no_reuse_list = NULL; } int bgp_damp_disable (struct bgp *bgp, afi_t afi, safi_t safi) { /* If it wasn't enabled, there's nothing to do. */ if (! CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) return 0; /* Cancel reuse thread. */ if (damp->t_reuse ) thread_cancel (damp->t_reuse); damp->t_reuse = NULL; /* Clean BGP dampening information. */ bgp_damp_info_clean (); /* Clear configuration */ bgp_damp_config_clean (&bgp_damp_cfg); UNSET_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); return 0; } void bgp_config_write_damp (struct vty *vty) { if (bgp_damp_cfg.half_life == DEFAULT_HALF_LIFE*60 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) vty_out (vty, " bgp dampening%s", VTY_NEWLINE); else if (bgp_damp_cfg.half_life != DEFAULT_HALF_LIFE*60 && bgp_damp_cfg.reuse_limit == DEFAULT_REUSE && bgp_damp_cfg.suppress_value == DEFAULT_SUPPRESS && bgp_damp_cfg.max_suppress_time == bgp_damp_cfg.half_life*4) vty_out (vty, " bgp dampening %ld%s", bgp_damp_cfg.half_life/60, VTY_NEWLINE); else vty_out (vty, " bgp dampening %ld %d %d %ld%s", bgp_damp_cfg.half_life/60, bgp_damp_cfg.reuse_limit, bgp_damp_cfg.suppress_value, bgp_damp_cfg.max_suppress_time/60, VTY_NEWLINE); } static const char * bgp_get_reuse_time (unsigned int penalty, char *buf, size_t len) { time_t reuse_time = 0; struct tm *tm = NULL; if (penalty > damp->reuse_limit) { reuse_time = (int) (DELTA_T * ((log((double)damp->reuse_limit/penalty))/(log(damp->decay_array[1])))); if (reuse_time > damp->max_suppress_time) reuse_time = damp->max_suppress_time; tm = gmtime (&reuse_time); } else reuse_time = 0; /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (reuse_time == 0) snprintf (buf, len, "00:00:00"); else if (reuse_time < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (reuse_time < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } void bgp_damp_info_vty (struct vty *vty, struct bgp_info *binfo) { struct bgp_damp_info *bdi; time_t t_now, t_diff; char timebuf[BGP_UPTIME_LEN]; int penalty; if (!binfo->extra) return; /* BGP dampening information. */ bdi = binfo->extra->damp_info; /* If dampening is not enabled or there is no dampening information, return immediately. */ if (! damp || ! bdi) return; /* Calculate new penalty. */ t_now = bgp_clock (); t_diff = t_now - bdi->t_updated; penalty = bgp_damp_decay (t_diff, bdi->penalty); vty_out (vty, " Dampinfo: penalty %d, flapped %d times in %s", penalty, bdi->flap, peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN)); if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, ", reuse in %s", bgp_get_reuse_time (penalty, timebuf, BGP_UPTIME_LEN)); vty_out (vty, "%s", VTY_NEWLINE); } const char * bgp_damp_reuse_time_vty (struct vty *vty, struct bgp_info *binfo, char *timebuf, size_t len) { struct bgp_damp_info *bdi; time_t t_now, t_diff; int penalty; if (!binfo->extra) return NULL; /* BGP dampening information. */ bdi = binfo->extra->damp_info; /* If dampening is not enabled or there is no dampening information, return immediately. */ if (! damp || ! bdi) return NULL; /* Calculate new penalty. */ t_now = bgp_clock (); t_diff = t_now - bdi->t_updated; penalty = bgp_damp_decay (t_diff, bdi->penalty); return bgp_get_reuse_time (penalty, timebuf, len); } quagga-0.99.24.1/bgpd/bgp_nexthop.c0000644000175000017500000010551612476520570013641 00000000000000/* BGP nexthop scan Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "thread.h" #include "prefix.h" #include "zclient.h" #include "stream.h" #include "network.h" #include "log.h" #include "memory.h" #include "hash.h" #include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_damp.h" #include "zebra/rib.h" #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ struct bgp_nexthop_cache *zlookup_query (struct in_addr); #ifdef HAVE_IPV6 struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); #endif /* HAVE_IPV6 */ /* Only one BGP scan thread are activated at the same time. */ static struct thread *bgp_scan_thread = NULL; /* BGP import thread */ static struct thread *bgp_import_thread = NULL; /* BGP scan interval. */ static int bgp_scan_interval; /* BGP import interval. */ static int bgp_import_interval; /* Route table for next-hop lookup cache. */ static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; static struct bgp_table *cache1_table[AFI_MAX]; static struct bgp_table *cache2_table[AFI_MAX]; /* Route table for connected route. */ static struct bgp_table *bgp_connected_table[AFI_MAX]; /* BGP nexthop lookup query client. */ struct zclient *zlookup = NULL; /* Add nexthop to the end of the list. */ static void bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) { struct nexthop *last; for (last = bnc->nexthop; last && last->next; last = last->next) ; if (last) last->next = nexthop; else bnc->nexthop = nexthop; nexthop->prev = last; } static void bnc_nexthop_free (struct bgp_nexthop_cache *bnc) { struct nexthop *nexthop; struct nexthop *next = NULL; for (nexthop = bnc->nexthop; nexthop; nexthop = next) { next = nexthop->next; XFREE (MTYPE_NEXTHOP, nexthop); } } static struct bgp_nexthop_cache * bnc_new (void) { return XCALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); } static void bnc_free (struct bgp_nexthop_cache *bnc) { bnc_nexthop_free (bnc); XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); } static int bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) { if (next1->type != next2->type) return 0; switch (next1->type) { case ZEBRA_NEXTHOP_IPV4: if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) return 0; break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4) || next1->ifindex != next2->ifindex) return 0; break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: if (next1->ifindex != next2->ifindex) return 0; break; #ifdef HAVE_IPV6 case ZEBRA_NEXTHOP_IPV6: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) return 0; if (next1->ifindex != next2->ifindex) return 0; break; #endif /* HAVE_IPV6 */ default: /* do nothing */ break; } return 1; } static int bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1, struct bgp_nexthop_cache *bnc2) { int i; struct nexthop *next1, *next2; if (bnc1->nexthop_num != bnc2->nexthop_num) return 1; next1 = bnc1->nexthop; next2 = bnc2->nexthop; for (i = 0; i < bnc1->nexthop_num; i++) { if (! bgp_nexthop_same (next1, next2)) return 1; next1 = next1->next; next2 = next2->next; } return 0; } /* If nexthop exists on connected network return 1. */ int bgp_nexthop_onlink (afi_t afi, struct attr *attr) { struct bgp_node *rn; /* If zebra is not enabled return */ if (zlookup->sock < 0) return 1; /* Lookup the address is onlink or not. */ if (afi == AFI_IP) { rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); if (rn) { bgp_unlock_node (rn); return 1; } } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { if (attr->extra->mp_nexthop_len == 32) return 1; else if (attr->extra->mp_nexthop_len == 16) { if (IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6], &attr->extra->mp_nexthop_global); if (rn) { bgp_unlock_node (rn); return 1; } } } #endif /* HAVE_IPV6 */ return 0; } #ifdef HAVE_IPV6 /* Check specified next-hop is reachable or not. */ static int bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct attr *attr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } /* Only check IPv6 global address only nexthop. */ attr = ri->attr; if (attr->extra->mp_nexthop_len != 16 || IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_global)) return 1; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET6; p.prefixlen = IPV6_MAX_BITLEN; p.u.prefix6 = attr->extra->mp_nexthop_global; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) old = cache2_table[AFI_IP6]; else old = cache1_table[AFI_IP6]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get (ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; } #endif /* HAVE_IPV6 */ /* Check specified next-hop is reachable or not. */ int bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, int *changed, int *metricchanged) { struct bgp_node *rn; struct prefix p; struct bgp_nexthop_cache *bnc; struct in_addr addr; /* If lookup is not enabled, return valid. */ if (zlookup->sock < 0) { if (ri->extra) ri->extra->igpmetric = 0; return 1; } #ifdef HAVE_IPV6 if (afi == AFI_IP6) return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); #endif /* HAVE_IPV6 */ addr = ri->attr->nexthop; memset (&p, 0, sizeof (struct prefix)); p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.u.prefix4 = addr; /* IBGP or ebgp-multihop */ rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); if (rn->info) { bnc = rn->info; bgp_unlock_node (rn); } else { if (NULL == (bnc = zlookup_query (addr))) bnc = bnc_new (); else { if (changed) { struct bgp_table *old; struct bgp_node *oldrn; if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) old = cache2_table[AFI_IP]; else old = cache1_table[AFI_IP]; oldrn = bgp_node_lookup (old, &p); if (oldrn) { struct bgp_nexthop_cache *oldbnc = oldrn->info; bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc); if (bnc->metric != oldbnc->metric) bnc->metricchanged = 1; bgp_unlock_node (oldrn); } } } rn->info = bnc; } if (changed) *changed = bnc->changed; if (metricchanged) *metricchanged = bnc->metricchanged; if (bnc->valid && bnc->metric) (bgp_info_extra_get(ri))->igpmetric = bnc->metric; else if (ri->extra) ri->extra->igpmetric = 0; return bnc->valid; } /* Reset and free all BGP nexthop cache. */ static void bgp_nexthop_cache_reset (struct bgp_table *table) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { bnc_free (bnc); rn->info = NULL; bgp_unlock_node (rn); } } static void bgp_scan (afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp *bgp; struct bgp_info *bi; struct bgp_info *next; struct peer *peer; struct listnode *node, *nnode; int valid; int current; int changed; int metricchanged; /* Change cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_table[afi] = cache2_table[afi]; else bgp_nexthop_cache_table[afi] = cache1_table[afi]; /* Get default bgp. */ bgp = bgp_get_default (); if (bgp == NULL) return; /* Maximum prefix check */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->status != Established) continue; if (peer->afc[afi][SAFI_UNICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1); if (peer->afc[afi][SAFI_MULTICAST]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1); if (peer->afc[afi][SAFI_MPLS_VPN]) bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1); } for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next (rn)) { for (bi = rn->info; bi; bi = next) { next = bi->next; if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) { changed = 0; metricchanged = 0; if (bi->peer->sort == BGP_PEER_EBGP && bi->peer->ttl == 1 && !CHECK_FLAG(bi->peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) valid = bgp_nexthop_onlink (afi, bi->attr); else valid = bgp_nexthop_lookup (afi, bi->peer, bi, &changed, &metricchanged); current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; if (changed) SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); else UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); if (valid != current) { if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) { bgp_aggregate_decrement (bgp, &rn->p, bi, afi, SAFI_UNICAST); bgp_info_unset_flag (rn, bi, BGP_INFO_VALID); } else { bgp_info_set_flag (rn, bi, BGP_INFO_VALID); bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_DAMPENING) && bi->extra && bi->extra->damp_info ) if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) bgp_aggregate_increment (bgp, &rn->p, bi, afi, SAFI_UNICAST); } } bgp_process (bgp, rn, afi, SAFI_UNICAST); } /* Flash old cache. */ if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) bgp_nexthop_cache_reset (cache2_table[afi]); else bgp_nexthop_cache_reset (cache1_table[afi]); if (BGP_DEBUG (events, EVENTS)) { if (afi == AFI_IP) zlog_debug ("scanning IPv4 Unicast routing tables"); else if (afi == AFI_IP6) zlog_debug ("scanning IPv6 Unicast routing tables"); } /* Reevaluate default-originate route-maps and announce/withdraw * default route if neccesary. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->status == Established && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) && peer->default_rmap[afi][safi].name) bgp_default_originate (peer, afi, safi, 0); } } /* BGP scan thread. This thread check nexthop reachability. */ static int bgp_scan_timer (struct thread *t) { bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Performing BGP general scanning"); bgp_scan (AFI_IP, SAFI_UNICAST); #ifdef HAVE_IPV6 bgp_scan (AFI_IP6, SAFI_UNICAST); #endif /* HAVE_IPV6 */ return 0; } /* BGP own address structure */ struct bgp_addr { struct in_addr addr; int refcnt; }; static struct hash *bgp_address_hash; static void * bgp_address_hash_alloc (void *p) { struct in_addr *val = p; struct bgp_addr *addr; addr = XMALLOC (MTYPE_BGP_ADDR, sizeof (struct bgp_addr)); addr->refcnt = 0; addr->addr.s_addr = val->s_addr; return addr; } static unsigned int bgp_address_hash_key_make (void *p) { const struct bgp_addr *addr = p; return jhash_1word(addr->addr.s_addr, 0); } static int bgp_address_hash_cmp (const void *p1, const void *p2) { const struct bgp_addr *addr1 = p1; const struct bgp_addr *addr2 = p2; return addr1->addr.s_addr == addr2->addr.s_addr; } void bgp_address_init (void) { bgp_address_hash = hash_create (bgp_address_hash_key_make, bgp_address_hash_cmp); } static void bgp_address_add (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_get (bgp_address_hash, &tmp, bgp_address_hash_alloc); addr->refcnt++; } static void bgp_address_del (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_lookup (bgp_address_hash, &tmp); /* may have been deleted earlier by bgp_interface_down() */ if (addr == NULL) return; addr->refcnt--; if (addr->refcnt == 0) { hash_release (bgp_address_hash, addr); XFREE (MTYPE_BGP_ADDR, addr); } } struct bgp_connected_ref { unsigned int refcnt; }; void bgp_connected_add (struct connected *ifc) { struct prefix p; struct prefix *addr; struct interface *ifp; struct bgp_node *rn; struct bgp_connected_ref *bc; ifp = ifc->ifp; if (! ifp) return; if (if_is_loopback (ifp)) return; addr = ifc->address; if (addr->family == AF_INET) { PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; bgp_address_add (addr); rn = bgp_node_get (bgp_connected_table[AFI_IP], (struct prefix *) &p); if (rn->info) { bc = rn->info; bc->refcnt++; } else { bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 ((struct prefix_ipv6 *) &p); if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) return; if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) return; rn = bgp_node_get (bgp_connected_table[AFI_IP6], (struct prefix *) &p); if (rn->info) { bc = rn->info; bc->refcnt++; } else { bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref)); bc->refcnt = 1; rn->info = bc; } } #endif /* HAVE_IPV6 */ } void bgp_connected_delete (struct connected *ifc) { struct prefix p; struct prefix *addr; struct interface *ifp; struct bgp_node *rn; struct bgp_connected_ref *bc; ifp = ifc->ifp; if (if_is_loopback (ifp)) return; addr = ifc->address; if (addr->family == AF_INET) { PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv4 ((struct prefix_ipv4 *) &p); if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) return; bgp_address_del (addr); rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } #ifdef HAVE_IPV6 else if (addr->family == AF_INET6) { PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc)); apply_mask_ipv6 ((struct prefix_ipv6 *) &p); if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) return; if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) return; rn = bgp_node_lookup (bgp_connected_table[AFI_IP6], (struct prefix *) &p); if (! rn) return; bc = rn->info; bc->refcnt--; if (bc->refcnt == 0) { XFREE (MTYPE_BGP_CONN, bc); rn->info = NULL; } bgp_unlock_node (rn); bgp_unlock_node (rn); } #endif /* HAVE_IPV6 */ } int bgp_nexthop_self (struct attr *attr) { struct bgp_addr tmp, *addr; tmp.addr = attr->nexthop; addr = hash_lookup (bgp_address_hash, &tmp); if (addr) return 1; return 0; } static struct bgp_nexthop_cache * zlookup_read (void) { struct stream *s; uint16_t length; u_char marker; u_char version; uint16_t command __attribute__((unused)); int nbytes __attribute__((unused)); struct in_addr raddr __attribute__((unused)); uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); /* nbytes not being checked */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } /* XXX: not checking command */ command = stream_getw (s); /* XXX: not doing anything with raddr */ raddr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV4: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; } struct bgp_nexthop_cache * zlookup_query (struct in_addr addr) { int ret; struct stream *s; /* Check socket. */ if (zlookup->sock < 0) return NULL; s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); stream_put_in_addr (s, &addr); stream_putw_at (s, 0, stream_get_endp (s)); ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return NULL; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return NULL; } return zlookup_read (); } #ifdef HAVE_IPV6 static struct bgp_nexthop_cache * zlookup_read_ipv6 (void) { struct stream *s; uint16_t length; u_char version, marker; struct in6_addr raddr; uint32_t metric; int i; u_char nexthop_num; struct nexthop *nexthop; struct bgp_nexthop_cache *bnc; s = zlookup->ibuf; stream_reset (s); /* XXX: ignoring nbytes, see also zread_lookup */ stream_read (s, zlookup->sock, 2); length = stream_getw (s); stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return NULL; } /* XXX: ignoring command */ stream_getw (s); /* XXX: not actually doing anything with raddr */ stream_get (&raddr, s, 16); metric = stream_getl (s); nexthop_num = stream_getc (s); if (nexthop_num) { bnc = bnc_new (); bnc->valid = 1; bnc->metric = metric; bnc->nexthop_num = nexthop_num; for (i = 0; i < nexthop_num; i++) { nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = stream_getc (s); switch (nexthop->type) { case ZEBRA_NEXTHOP_IPV6: stream_get (&nexthop->gate.ipv6, s, 16); break; case ZEBRA_NEXTHOP_IPV6_IFINDEX: case ZEBRA_NEXTHOP_IPV6_IFNAME: stream_get (&nexthop->gate.ipv6, s, 16); nexthop->ifindex = stream_getl (s); break; case ZEBRA_NEXTHOP_IFINDEX: case ZEBRA_NEXTHOP_IFNAME: nexthop->ifindex = stream_getl (s); break; default: /* do nothing */ break; } bnc_nexthop_add (bnc, nexthop); } } else return NULL; return bnc; } struct bgp_nexthop_cache * zlookup_query_ipv6 (struct in6_addr *addr) { int ret; struct stream *s; /* Check socket. */ if (zlookup->sock < 0) return NULL; s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); stream_put (s, addr, 16); stream_putw_at (s, 0, stream_get_endp (s)); ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return NULL; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return NULL; } return zlookup_read_ipv6 (); } #endif /* HAVE_IPV6 */ static int bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) { struct stream *s; int ret; u_int16_t length, command __attribute__((unused)); u_char version, marker; int nbytes __attribute__((unused)); struct in_addr addr __attribute__((unused)); struct in_addr nexthop; u_int32_t metric = 0; u_char nexthop_num; u_char nexthop_type; /* If lookup connection is not available return valid. */ if (zlookup->sock < 0) { if (igpmetric) *igpmetric = 0; return 1; } /* Send query to the lookup connection */ s = zlookup->obuf; stream_reset (s); zclient_create_header (s, ZEBRA_IPV4_IMPORT_LOOKUP); stream_putc (s, p->prefixlen); stream_put_in_addr (s, &p->u.prefix4); stream_putw_at (s, 0, stream_get_endp (s)); /* Write the packet. */ ret = writen (zlookup->sock, s->data, stream_get_endp (s)); if (ret < 0) { zlog_err ("can't write to zlookup->sock"); close (zlookup->sock); zlookup->sock = -1; return 1; } if (ret == 0) { zlog_err ("zlookup->sock connection closed"); close (zlookup->sock); zlookup->sock = -1; return 1; } /* Get result. */ stream_reset (s); /* Fetch length. */ /* XXX: not using nbytes */ nbytes = stream_read (s, zlookup->sock, 2); length = stream_getw (s); /* Fetch whole data. */ nbytes = stream_read (s, zlookup->sock, length - 2); marker = stream_getc (s); version = stream_getc (s); if (version != ZSERV_VERSION || marker != ZEBRA_HEADER_MARKER) { zlog_err("%s: socket %d version mismatch, marker %d, version %d", __func__, zlookup->sock, marker, version); return 0; } /* XXX: not using command */ command = stream_getw (s); /* XXX: not using addr */ addr.s_addr = stream_get_ipv4 (s); metric = stream_getl (s); nexthop_num = stream_getc (s); /* Set IGP metric value. */ if (igpmetric) *igpmetric = metric; /* If there is nexthop then this is active route. */ if (nexthop_num) { nexthop.s_addr = 0; nexthop_type = stream_getc (s); switch (nexthop_type) { case ZEBRA_NEXTHOP_IPV4: nexthop.s_addr = stream_get_ipv4 (s); break; case ZEBRA_NEXTHOP_IPV4_IFINDEX: nexthop.s_addr = stream_get_ipv4 (s); /* ifindex */ (void)stream_getl (s); break; default: /* do nothing */ break; } *igpnexthop = nexthop; return 1; } else return 0; } /* Scan all configured BGP route then check the route exists in IGP or not. */ static int bgp_import (struct thread *t) { struct bgp *bgp; struct bgp_node *rn; struct bgp_static *bgp_static; struct listnode *node, *nnode; int valid; u_int32_t metric; struct in_addr nexthop; afi_t afi; safi_t safi; bgp_import_thread = thread_add_timer (master, bgp_import, NULL, bgp_import_interval); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("Import timer expired."); for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { if (bgp_static->backdoor) continue; valid = bgp_static->valid; metric = bgp_static->igpmetric; nexthop = bgp_static->igpnexthop; if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) && afi == AFI_IP && safi == SAFI_UNICAST) bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, &bgp_static->igpnexthop); else { bgp_static->valid = 1; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; } if (bgp_static->valid != valid) { if (bgp_static->valid) bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); else bgp_static_withdraw (bgp, &rn->p, afi, safi); } else if (bgp_static->valid) { if (bgp_static->igpmetric != metric || bgp_static->igpnexthop.s_addr != nexthop.s_addr || bgp_static->rmap.name) bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); } } } return 0; } /* Connect to zebra for nexthop lookup. */ static int zlookup_connect (struct thread *t) { struct zclient *zlookup; zlookup = THREAD_ARG (t); zlookup->t_connect = NULL; if (zlookup->sock != -1) return 0; if (zclient_socket_connect (zlookup) < 0) return -1; return 0; } /* Check specified multiaccess next-hop. */ int bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) { struct bgp_node *rn1; struct bgp_node *rn2; struct prefix p1; struct prefix p2; struct in_addr addr; int ret; ret = inet_aton (peer, &addr); if (! ret) return 0; memset (&p1, 0, sizeof (struct prefix)); p1.family = AF_INET; p1.prefixlen = IPV4_MAX_BITLEN; p1.u.prefix4 = nexthop; memset (&p2, 0, sizeof (struct prefix)); p2.family = AF_INET; p2.prefixlen = IPV4_MAX_BITLEN; p2.u.prefix4 = addr; /* If bgp scan is not enabled, return invalid. */ if (zlookup->sock < 0) return 0; rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); if (! rn1) return 0; bgp_unlock_node (rn1); rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); if (! rn2) return 0; bgp_unlock_node (rn2); /* This is safe, even with above unlocks, since we are just comparing pointers to the objects, not the objects themselves. */ if (rn1 == rn2) return 1; return 0; } DEFUN (bgp_scan_time, bgp_scan_time_cmd, "bgp scan-time <5-60>", "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") { bgp_scan_interval = atoi (argv[0]); if (bgp_scan_thread) { thread_cancel (bgp_scan_thread); bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; } DEFUN (no_bgp_scan_time, no_bgp_scan_time_cmd, "no bgp scan-time", NO_STR "BGP specific commands\n" "Configure background scanner interval\n") { bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; if (bgp_scan_thread) { thread_cancel (bgp_scan_thread); bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); } return CMD_SUCCESS; } ALIAS (no_bgp_scan_time, no_bgp_scan_time_val_cmd, "no bgp scan-time <5-60>", NO_STR "BGP specific commands\n" "Configure background scanner interval\n" "Scanner interval (seconds)\n") static int show_ip_bgp_scan_tables (struct vty *vty, const char detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; char buf[INET6_ADDRSTRLEN]; u_char i; if (bgp_scan_thread) vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); else vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) { vty_out (vty, " %s valid [IGP metric %d]%s", inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) switch (bnc->nexthop[i].type) { case NEXTHOP_TYPE_IPV4: vty_out (vty, " gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IPV4_IFINDEX: vty_out (vty, " gate %s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN)); vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; default: vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); } } else vty_out (vty, " %s invalid%s", inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } #ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if ((bnc = rn->info) != NULL) { if (bnc->valid) { vty_out (vty, " %s valid [IGP metric %d]%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); if (detail) for (i = 0; i < bnc->nexthop_num; i++) switch (bnc->nexthop[i].type) { case NEXTHOP_TYPE_IPV6: vty_out (vty, " gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); break; case NEXTHOP_TYPE_IFINDEX: vty_out (vty, " ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); break; default: vty_out (vty, " invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); } } else vty_out (vty, " %s invalid%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } } #endif /* HAVE_IPV6 */ vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, VTY_NEWLINE); #ifdef HAVE_IPV6 { for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) vty_out (vty, " %s/%d%s", inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN), rn->p.prefixlen, VTY_NEWLINE); } #endif /* HAVE_IPV6 */ return CMD_SUCCESS; } DEFUN (show_ip_bgp_scan, show_ip_bgp_scan_cmd, "show ip bgp scan", SHOW_STR IP_STR BGP_STR "BGP scan status\n") { return show_ip_bgp_scan_tables (vty, 0); } DEFUN (show_ip_bgp_scan_detail, show_ip_bgp_scan_detail_cmd, "show ip bgp scan detail", SHOW_STR IP_STR BGP_STR "BGP scan status\n" "More detailed output\n") { return show_ip_bgp_scan_tables (vty, 1); } int bgp_config_write_scan_time (struct vty *vty) { if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); return CMD_SUCCESS; } void bgp_scan_init (void) { zlookup = zclient_new (); zlookup->sock = -1; zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; cache1_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); cache2_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP]; bgp_connected_table[AFI_IP] = bgp_table_init (AFI_IP, SAFI_UNICAST); #ifdef HAVE_IPV6 cache1_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); cache2_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; bgp_connected_table[AFI_IP6] = bgp_table_init (AFI_IP6, SAFI_UNICAST); #endif /* HAVE_IPV6 */ /* Make BGP scan thread. */ bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); /* Make BGP import there. */ bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); install_element (BGP_NODE, &bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_cmd); install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd); } void bgp_scan_finish (void) { /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]); bgp_table_unlock (cache1_table[AFI_IP]); cache1_table[AFI_IP] = NULL; bgp_table_unlock (cache2_table[AFI_IP]); cache2_table[AFI_IP] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP]); bgp_connected_table[AFI_IP] = NULL; #ifdef HAVE_IPV6 /* Only the current one needs to be reset. */ bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]); bgp_table_unlock (cache1_table[AFI_IP6]); cache1_table[AFI_IP6] = NULL; bgp_table_unlock (cache2_table[AFI_IP6]); cache2_table[AFI_IP6] = NULL; bgp_table_unlock (bgp_connected_table[AFI_IP6]); bgp_connected_table[AFI_IP6] = NULL; #endif /* HAVE_IPV6 */ } quagga-0.99.24.1/bgpd/bgp_mplsvpn.c0000644000175000017500000004702112476520570013647 00000000000000/* MPLS-VPN Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "log.h" #include "memory.h" #include "stream.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_mplsvpn.h" static u_int16_t decode_rd_type (u_char *pnt) { u_int16_t v; v = ((u_int16_t) *pnt++ << 8); v |= (u_int16_t) *pnt; return v; } u_int32_t decode_label (u_char *pnt) { u_int32_t l; l = ((u_int32_t) *pnt++ << 12); l |= (u_int32_t) *pnt++ << 4; l |= (u_int32_t) ((*pnt & 0xf0) >> 4); return l; } static void decode_rd_as (u_char *pnt, struct rd_as *rd_as) { rd_as->as = (u_int16_t) *pnt++ << 8; rd_as->as |= (u_int16_t) *pnt++; rd_as->val = ((u_int32_t) *pnt++ << 24); rd_as->val |= ((u_int32_t) *pnt++ << 16); rd_as->val |= ((u_int32_t) *pnt++ << 8); rd_as->val |= (u_int32_t) *pnt; } static void decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) { memcpy (&rd_ip->ip, pnt, 4); pnt += 4; rd_ip->val = ((u_int16_t) *pnt++ << 8); rd_ip->val |= (u_int16_t) *pnt; } int bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; int psize; int prefixlen; u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; struct prefix_rd prd; u_char *tagpnt; /* Check peer status. */ if (peer->status != Established) return 0; /* Make prefix_rd */ prd.family = AF_UNSPEC; prd.prefixlen = 64; pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ prefixlen = *pnt++; p.family = AF_INET; psize = PSIZE (prefixlen); if (prefixlen < 88) { zlog_err ("prefix length is less than 88: %d", prefixlen); return -1; } /* XXX: Not doing anything with the label */ decode_label (pnt); /* Copyr label to prefix. */ tagpnt = pnt;; /* Copy routing distinguisher to rd. */ memcpy (&prd.val, pnt + 3, 8); /* Decode RD type. */ type = decode_rd_type (pnt + 3); /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 5, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 5, &rd_ip); else { zlog_err ("Invalid RD type %d", type); return -1; } p.prefixlen = prefixlen - 88; memcpy (&p.u.prefix, pnt + 11, psize - 11); #if 0 if (type == RD_TYPE_AS) zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val, inet_ntoa (p.u.prefix4), p.prefixlen); else if (type == RD_TYPE_IP) zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip), rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen); #endif /* 0 */ if (pnt + psize > lim) return -1; if (attr) bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0); else bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt); } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; } int str2prefix_rd (const char *str, struct prefix_rd *prd) { int ret; char *p; char *p2; struct stream *s; char *half; struct in_addr addr; s = stream_new (8); prd->family = AF_UNSPEC; prd->prefixlen = 64; p = strchr (str, ':'); if (! p) return 0; if (! all_digit (p + 1)) return 0; half = XMALLOC (MTYPE_TMP, (p - str) + 1); memcpy (half, str, (p - str)); half[p - str] = '\0'; p2 = strchr (str, '.'); if (! p2) { if (! all_digit (half)) { XFREE (MTYPE_TMP, half); return 0; } stream_putw (s, RD_TYPE_AS); stream_putw (s, atoi (half)); stream_putl (s, atol (p + 1)); } else { ret = inet_aton (half, &addr); if (! ret) { XFREE (MTYPE_TMP, half); return 0; } stream_putw (s, RD_TYPE_IP); stream_put_in_addr (s, &addr); stream_putw (s, atol (p + 1)); } memcpy (prd->val, s->data, 8); return 1; } int str2tag (const char *str, u_char *tag) { unsigned long l; char *endptr; u_int32_t t; if (*str == '-') return 0; errno = 0; l = strtoul (str, &endptr, 10); if (*endptr != '\0' || errno || l > UINT32_MAX) return 0; t = (u_int32_t) l; tag[0] = (u_char)(t >> 12); tag[1] = (u_char)(t >> 4); tag[2] = (u_char)(t << 4); return 1; } char * prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) { u_char *pnt; u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; if (size < RD_ADDRSTRLEN) return NULL; pnt = prd->val; type = decode_rd_type (pnt); if (type == RD_TYPE_AS) { decode_rd_as (pnt + 2, &rd_as); snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); return buf; } else if (type == RD_TYPE_IP) { decode_rd_ip (pnt + 2, &rd_ip); snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); return buf; } return NULL; } /* For testing purpose, static route of MPLS-VPN. */ DEFUN (vpnv4_network, vpnv4_network_cmd, "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]); } /* For testing purpose, static route of MPLS-VPN. */ DEFUN (no_vpnv4_network, no_vpnv4_network_cmd, "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify Route Distinguisher\n" "VPN Route Distinguisher\n" "BGP tag\n" "tag value\n") { return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]); } static int show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd) { struct bgp *bgp; struct bgp_table *table; struct bgp_node *rn; struct bgp_node *rm; struct attr *attr; int rd_header; int header = 1; char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) { rd_header = 1; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) if ((attr = rm->info) != NULL) { if (header) { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, v4_header, VTY_NEWLINE); header = 0; } if (rd_header) { u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; u_char *pnt; pnt = rn->p.u.val; /* Decode RD type. */ type = decode_rd_type (pnt); /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "Route Distinguisher: "); if (type == RD_TYPE_AS) vty_out (vty, "%u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_IP) vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); vty_out (vty, "%s", VTY_NEWLINE); rd_header = 0; } route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN); } } } return CMD_SUCCESS; } enum bgp_show_type { bgp_show_type_normal, bgp_show_type_regexp, bgp_show_type_prefix_list, bgp_show_type_filter_list, bgp_show_type_neighbor, bgp_show_type_cidr_only, bgp_show_type_prefix_longer, bgp_show_type_community_all, bgp_show_type_community, bgp_show_type_community_exact, bgp_show_type_community_list, bgp_show_type_community_list_exact }; static int bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, int tags) { struct bgp *bgp; struct bgp_table *table; struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; int rd_header; int header = 1; char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) { rd_header = 1; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) for (ri = rm->info; ri; ri = ri->next) { if (type == bgp_show_type_neighbor) { union sockunion *su = output_arg; if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) continue; } if (header) { if (tags) vty_out (vty, v4_header_tag, VTY_NEWLINE); else { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", VTY_NEWLINE); vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, v4_header, VTY_NEWLINE); } header = 0; } if (rd_header) { u_int16_t type; struct rd_as rd_as; struct rd_ip rd_ip; u_char *pnt; pnt = rn->p.u.val; /* Decode RD type. */ type = decode_rd_type (pnt); /* Decode RD value. */ if (type == RD_TYPE_AS) decode_rd_as (pnt + 2, &rd_as); else if (type == RD_TYPE_IP) decode_rd_ip (pnt + 2, &rd_ip); vty_out (vty, "Route Distinguisher: "); if (type == RD_TYPE_AS) vty_out (vty, "%u:%d", rd_as.as, rd_as.val); else if (type == RD_TYPE_IP) vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); vty_out (vty, "%s", VTY_NEWLINE); rd_header = 0; } if (tags) route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); else route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN); } } } return CMD_SUCCESS; } DEFUN (show_ip_bgp_vpnv4_all, show_ip_bgp_vpnv4_all_cmd, "show ip bgp vpnv4 all", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n") { return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_rd, show_ip_bgp_vpnv4_rd_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_all_tags, show_ip_bgp_vpnv4_all_tags_cmd, "show ip bgp vpnv4 all tags", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Display BGP tags for prefixes\n") { return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_rd_tags, show_ip_bgp_vpnv4_rd_tags_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Display BGP tags for prefixes\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes, show_ip_bgp_vpnv4_all_neighbor_routes_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { union sockunion su; struct peer *peer; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes, show_ip_bgp_vpnv4_rd_neighbor_routes_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { int ret; union sockunion su; struct peer *peer; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0); } DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes, show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd, "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { int ret; struct peer *peer; union sockunion su; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_vpn (vty, peer, NULL); } DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes, show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { int ret; struct peer *peer; struct prefix_rd prd; union sockunion su; ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return show_adj_route_vpn (vty, peer, &prd); } void bgp_mplsvpn_init (void) { install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd); } quagga-0.99.24.1/bgpd/bgp_ecommunity.c0000644000175000017500000004207112476520570014341 00000000000000/* BGP Extended Communities Attribute Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "hash.h" #include "memory.h" #include "prefix.h" #include "command.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_aspath.h" /* Hash of community attribute. */ static struct hash *ecomhash; /* Allocate a new ecommunities. */ static struct ecommunity * ecommunity_new (void) { return (struct ecommunity *) XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity)); } /* Allocate ecommunities. */ void ecommunity_free (struct ecommunity **ecom) { if ((*ecom)->val) XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val); if ((*ecom)->str) XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str); XFREE (MTYPE_ECOMMUNITY, *ecom); ecom = NULL; } /* Add a new Extended Communities value to Extended Communities Attribute structure. When the value is already exists in the structure, we don't add the value. Newly added value is sorted by numerical order. When the value is added to the structure return 1 else return 0. */ static int ecommunity_add_val (struct ecommunity *ecom, struct ecommunity_val *eval) { u_int8_t *p; int ret; int c; /* When this is fist value, just add it. */ if (ecom->val == NULL) { ecom->size++; ecom->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom_length (ecom)); memcpy (ecom->val, eval->val, ECOMMUNITY_SIZE); return 1; } /* If the value already exists in the structure return 0. */ c = 0; for (p = ecom->val; c < ecom->size; p += ECOMMUNITY_SIZE, c++) { ret = memcmp (p, eval->val, ECOMMUNITY_SIZE); if (ret == 0) return 0; if (ret > 0) break; } /* Add the value to the structure with numerical sorting. */ ecom->size++; ecom->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom->val, ecom_length (ecom)); memmove (ecom->val + (c + 1) * ECOMMUNITY_SIZE, ecom->val + c * ECOMMUNITY_SIZE, (ecom->size - 1 - c) * ECOMMUNITY_SIZE); memcpy (ecom->val + c * ECOMMUNITY_SIZE, eval->val, ECOMMUNITY_SIZE); return 1; } /* This function takes pointer to Extended Communites strucutre then create a new Extended Communities structure by uniq and sort each Extended Communities value. */ struct ecommunity * ecommunity_uniq_sort (struct ecommunity *ecom) { int i; struct ecommunity *new; struct ecommunity_val *eval; if (! ecom) return NULL; new = ecommunity_new (); for (i = 0; i < ecom->size; i++) { eval = (struct ecommunity_val *) (ecom->val + (i * ECOMMUNITY_SIZE)); ecommunity_add_val (new, eval); } return new; } /* Parse Extended Communites Attribute in BGP packet. */ struct ecommunity * ecommunity_parse (u_int8_t *pnt, u_short length) { struct ecommunity tmp; struct ecommunity *new; /* Length check. */ if (length % ECOMMUNITY_SIZE) return NULL; /* Prepare tmporary structure for making a new Extended Communities Attribute. */ tmp.size = length / ECOMMUNITY_SIZE; tmp.val = pnt; /* Create a new Extended Communities Attribute by uniq and sort each Extended Communities value */ new = ecommunity_uniq_sort (&tmp); return ecommunity_intern (new); } /* Duplicate the Extended Communities Attribute structure. */ struct ecommunity * ecommunity_dup (struct ecommunity *ecom) { struct ecommunity *new; new = XCALLOC (MTYPE_ECOMMUNITY, sizeof (struct ecommunity)); new->size = ecom->size; if (new->size) { new->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, ecom->size * ECOMMUNITY_SIZE); memcpy (new->val, ecom->val, ecom->size * ECOMMUNITY_SIZE); } else new->val = NULL; return new; } /* Retrun string representation of communities attribute. */ char * ecommunity_str (struct ecommunity *ecom) { if (! ecom->str) ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); return ecom->str; } /* Merge two Extended Communities Attribute structure. */ struct ecommunity * ecommunity_merge (struct ecommunity *ecom1, struct ecommunity *ecom2) { if (ecom1->val) ecom1->val = XREALLOC (MTYPE_ECOMMUNITY_VAL, ecom1->val, (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); else ecom1->val = XMALLOC (MTYPE_ECOMMUNITY_VAL, (ecom1->size + ecom2->size) * ECOMMUNITY_SIZE); memcpy (ecom1->val + (ecom1->size * ECOMMUNITY_SIZE), ecom2->val, ecom2->size * ECOMMUNITY_SIZE); ecom1->size += ecom2->size; return ecom1; } /* Intern Extended Communities Attribute. */ struct ecommunity * ecommunity_intern (struct ecommunity *ecom) { struct ecommunity *find; assert (ecom->refcnt == 0); find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern); if (find != ecom) ecommunity_free (&ecom); find->refcnt++; if (! find->str) find->str = ecommunity_ecom2str (find, ECOMMUNITY_FORMAT_DISPLAY); return find; } /* Unintern Extended Communities Attribute. */ void ecommunity_unintern (struct ecommunity **ecom) { struct ecommunity *ret; if ((*ecom)->refcnt) (*ecom)->refcnt--; /* Pull off from hash. */ if ((*ecom)->refcnt == 0) { /* Extended community must be in the hash. */ ret = (struct ecommunity *) hash_release (ecomhash, *ecom); assert (ret != NULL); ecommunity_free (ecom); } } /* Utinity function to make hash key. */ unsigned int ecommunity_hash_make (void *arg) { const struct ecommunity *ecom = arg; int size = ecom->size * ECOMMUNITY_SIZE; u_int8_t *pnt = ecom->val; unsigned int key = 0; int c; for (c = 0; c < size; c += ECOMMUNITY_SIZE) { key += pnt[c]; key += pnt[c + 1]; key += pnt[c + 2]; key += pnt[c + 3]; key += pnt[c + 4]; key += pnt[c + 5]; key += pnt[c + 6]; key += pnt[c + 7]; } return key; } /* Compare two Extended Communities Attribute structure. */ int ecommunity_cmp (const void *arg1, const void *arg2) { const struct ecommunity *ecom1 = arg1; const struct ecommunity *ecom2 = arg2; return (ecom1->size == ecom2->size && memcmp (ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE) == 0); } /* Initialize Extended Comminities related hash. */ void ecommunity_init (void) { ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); } void ecommunity_finish (void) { hash_free (ecomhash); ecomhash = NULL; } /* Extended Communities token enum. */ enum ecommunity_token { ecommunity_token_rt, ecommunity_token_soo, ecommunity_token_val, ecommunity_token_unknown }; /* Get next Extended Communities token from the string. */ static const char * ecommunity_gettoken (const char *str, struct ecommunity_val *eval, enum ecommunity_token *token) { int ret; int dot = 0; int digit = 0; int separator = 0; const char *p = str; char *endptr; struct in_addr ip; as_t as = 0; u_int32_t val = 0; char buf[INET_ADDRSTRLEN + 1]; /* Skip white space. */ while (isspace ((int) *p)) { p++; str++; } /* Check the end of the line. */ if (*p == '\0') return NULL; /* "rt" and "soo" keyword parse. */ if (! isdigit ((int) *p)) { /* "rt" match check. */ if (tolower ((int) *p) == 'r') { p++; if (tolower ((int) *p) == 't') { p++; *token = ecommunity_token_rt; return p; } if (isspace ((int) *p) || *p == '\0') { *token = ecommunity_token_rt; return p; } goto error; } /* "soo" match check. */ else if (tolower ((int) *p) == 's') { p++; if (tolower ((int) *p) == 'o') { p++; if (tolower ((int) *p) == 'o') { p++; *token = ecommunity_token_soo; return p; } if (isspace ((int) *p) || *p == '\0') { *token = ecommunity_token_soo; return p; } goto error; } if (isspace ((int) *p) || *p == '\0') { *token = ecommunity_token_soo; return p; } goto error; } goto error; } /* What a mess, there are several possibilities: * * a) A.B.C.D:MN * b) EF:OPQR * c) GHJK:MN * * A.B.C.D: Four Byte IP * EF: Two byte ASN * GHJK: Four-byte ASN * MN: Two byte value * OPQR: Four byte value * */ while (isdigit ((int) *p) || *p == ':' || *p == '.') { if (*p == ':') { if (separator) goto error; separator = 1; digit = 0; if ((p - str) > INET_ADDRSTRLEN) goto error; memset (buf, 0, INET_ADDRSTRLEN + 1); memcpy (buf, str, p - str); if (dot) { /* Parsing A.B.C.D in: * A.B.C.D:MN */ ret = inet_aton (buf, &ip); if (ret == 0) goto error; } else { /* ASN */ as = strtoul (buf, &endptr, 10); if (*endptr != '\0' || as == BGP_AS4_MAX) goto error; } } else if (*p == '.') { if (separator) goto error; dot++; if (dot > 4) goto error; } else { digit = 1; /* We're past the IP/ASN part */ if (separator) { val *= 10; val += (*p - '0'); } } p++; } /* Low digit part must be there. */ if (!digit || !separator) goto error; /* Encode result into routing distinguisher. */ if (dot) { if (val > UINT16_MAX) goto error; eval->val[0] = ECOMMUNITY_ENCODE_IP; eval->val[1] = 0; memcpy (&eval->val[2], &ip, sizeof (struct in_addr)); eval->val[6] = (val >> 8) & 0xff; eval->val[7] = val & 0xff; } else if (as > BGP_AS_MAX) { if (val > UINT16_MAX) goto error; eval->val[0] = ECOMMUNITY_ENCODE_AS4; eval->val[1] = 0; eval->val[2] = (as >>24) & 0xff; eval->val[3] = (as >>16) & 0xff; eval->val[4] = (as >>8) & 0xff; eval->val[5] = as & 0xff; eval->val[6] = (val >> 8) & 0xff; eval->val[7] = val & 0xff; } else { eval->val[0] = ECOMMUNITY_ENCODE_AS; eval->val[1] = 0; eval->val[2] = (as >>8) & 0xff; eval->val[3] = as & 0xff; eval->val[4] = (val >>24) & 0xff; eval->val[5] = (val >>16) & 0xff; eval->val[6] = (val >>8) & 0xff; eval->val[7] = val & 0xff; } *token = ecommunity_token_val; return p; error: *token = ecommunity_token_unknown; return p; } /* Convert string to extended community attribute. When type is already known, please specify both str and type. str should not include keyword such as "rt" and "soo". Type is ECOMMUNITY_ROUTE_TARGET or ECOMMUNITY_SITE_ORIGIN. keyword_included should be zero. For example route-map's "set extcommunity" command case: "rt 100:1 100:2 100:3" -> str = "100:1 100:2 100:3" type = ECOMMUNITY_ROUTE_TARGET keyword_included = 0 "soo 100:1" -> str = "100:1" type = ECOMMUNITY_SITE_ORIGIN keyword_included = 0 When string includes keyword for each extended community value. Please specify keyword_included as non-zero value. For example standard extcommunity-list case: "rt 100:1 rt 100:2 soo 100:1" -> str = "rt 100:1 rt 100:2 soo 100:1" type = 0 keyword_include = 1 */ struct ecommunity * ecommunity_str2com (const char *str, int type, int keyword_included) { struct ecommunity *ecom = NULL; enum ecommunity_token token; struct ecommunity_val eval; int keyword = 0; while ((str = ecommunity_gettoken (str, &eval, &token))) { switch (token) { case ecommunity_token_rt: case ecommunity_token_soo: if (! keyword_included || keyword) { if (ecom) ecommunity_free (&ecom); return NULL; } keyword = 1; if (token == ecommunity_token_rt) { type = ECOMMUNITY_ROUTE_TARGET; } if (token == ecommunity_token_soo) { type = ECOMMUNITY_SITE_ORIGIN; } break; case ecommunity_token_val: if (keyword_included) { if (! keyword) { if (ecom) ecommunity_free (&ecom); return NULL; } keyword = 0; } if (ecom == NULL) ecom = ecommunity_new (); eval.val[1] = type; ecommunity_add_val (ecom, &eval); break; case ecommunity_token_unknown: default: if (ecom) ecommunity_free (&ecom); return NULL; } } return ecom; } /* Convert extended community attribute to string. Due to historical reason of industry standard implementation, there are three types of format. route-map set extcommunity format "rt 100:1 100:2" "soo 100:3" extcommunity-list "rt 100:1 rt 100:2 soo 100:3" "show ip bgp" and extcommunity-list regular expression matching "RT:100:1 RT:100:2 SoO:100:3" For each formath please use below definition for format: ECOMMUNITY_FORMAT_ROUTE_MAP ECOMMUNITY_FORMAT_COMMUNITY_LIST ECOMMUNITY_FORMAT_DISPLAY */ char * ecommunity_ecom2str (struct ecommunity *ecom, int format) { int i; u_int8_t *pnt; int encode = 0; int type = 0; #define ECOMMUNITY_STR_DEFAULT_LEN 27 int str_size; int str_pnt; char *str_buf; const char *prefix; int len = 0; int first = 1; /* For parse Extended Community attribute tupple. */ struct ecommunity_as { as_t as; u_int32_t val; } eas; struct ecommunity_ip { struct in_addr ip; u_int16_t val; } eip; if (ecom->size == 0) { str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, 1); str_buf[0] = '\0'; return str_buf; } /* Prepare buffer. */ str_buf = XMALLOC (MTYPE_ECOMMUNITY_STR, ECOMMUNITY_STR_DEFAULT_LEN + 1); str_size = ECOMMUNITY_STR_DEFAULT_LEN + 1; str_pnt = 0; for (i = 0; i < ecom->size; i++) { /* Make it sure size is enough. */ while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) { str_size *= 2; str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); } /* Space between each value. */ if (! first) str_buf[str_pnt++] = ' '; pnt = ecom->val + (i * 8); /* High-order octet of type. */ encode = *pnt++; if (encode != ECOMMUNITY_ENCODE_AS && encode != ECOMMUNITY_ENCODE_IP && encode != ECOMMUNITY_ENCODE_AS4) { len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; first = 0; continue; } /* Low-order octet of type. */ type = *pnt++; if (type != ECOMMUNITY_ROUTE_TARGET && type != ECOMMUNITY_SITE_ORIGIN) { len = sprintf (str_buf + str_pnt, "?"); str_pnt += len; first = 0; continue; } switch (format) { case ECOMMUNITY_FORMAT_COMMUNITY_LIST: prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "rt " : "soo "); break; case ECOMMUNITY_FORMAT_DISPLAY: prefix = (type == ECOMMUNITY_ROUTE_TARGET ? "RT:" : "SoO:"); break; case ECOMMUNITY_FORMAT_ROUTE_MAP: prefix = ""; break; default: prefix = ""; break; } /* Put string into buffer. */ if (encode == ECOMMUNITY_ENCODE_AS4) { eas.as = (*pnt++ << 24); eas.as |= (*pnt++ << 16); eas.as |= (*pnt++ << 8); eas.as |= (*pnt++); eas.val = (*pnt++ << 8); eas.val |= (*pnt++); len = sprintf( str_buf + str_pnt, "%s%u:%u", prefix, eas.as, eas.val ); str_pnt += len; first = 0; } if (encode == ECOMMUNITY_ENCODE_AS) { eas.as = (*pnt++ << 8); eas.as |= (*pnt++); eas.val = (*pnt++ << 24); eas.val |= (*pnt++ << 16); eas.val |= (*pnt++ << 8); eas.val |= (*pnt++); len = sprintf (str_buf + str_pnt, "%s%u:%u", prefix, eas.as, eas.val); str_pnt += len; first = 0; } else if (encode == ECOMMUNITY_ENCODE_IP) { memcpy (&eip.ip, pnt, 4); pnt += 4; eip.val = (*pnt++ << 8); eip.val |= (*pnt++); len = sprintf (str_buf + str_pnt, "%s%s:%u", prefix, inet_ntoa (eip.ip), eip.val); str_pnt += len; first = 0; } } return str_buf; } int ecommunity_match (const struct ecommunity *ecom1, const struct ecommunity *ecom2) { int i = 0; int j = 0; if (ecom1 == NULL && ecom2 == NULL) return 1; if (ecom1 == NULL || ecom2 == NULL) return 0; if (ecom1->size < ecom2->size) return 0; /* Every community on com2 needs to be on com1 for this to match */ while (i < ecom1->size && j < ecom2->size) { if (memcmp (ecom1->val + i, ecom2->val + j, ECOMMUNITY_SIZE) == 0) j++; i++; } if (j == ecom2->size) return 1; else return 0; } quagga-0.99.24.1/bgpd/bgp_snmp.c0000644000175000017500000006124612476520570013132 00000000000000/* BGP4 SNMP support Copyright (C) 1999, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "thread.h" #include "smux.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_snmp.h" /* BGP4-MIB described in RFC1657. */ #define BGP4MIB 1,3,6,1,2,1,15 /* BGP TRAP. */ #define BGPESTABLISHED 1 #define BGPBACKWARDTRANSITION 2 /* BGP MIB bgpVersion. */ #define BGPVERSION 0 /* BGP MIB bgpLocalAs. */ #define BGPLOCALAS 0 /* BGP MIB bgpPeerTable. */ #define BGPPEERIDENTIFIER 1 #define BGPPEERSTATE 2 #define BGPPEERADMINSTATUS 3 #define BGPPEERNEGOTIATEDVERSION 4 #define BGPPEERLOCALADDR 5 #define BGPPEERLOCALPORT 6 #define BGPPEERREMOTEADDR 7 #define BGPPEERREMOTEPORT 8 #define BGPPEERREMOTEAS 9 #define BGPPEERINUPDATES 10 #define BGPPEEROUTUPDATES 11 #define BGPPEERINTOTALMESSAGES 12 #define BGPPEEROUTTOTALMESSAGES 13 #define BGPPEERLASTERROR 14 #define BGPPEERFSMESTABLISHEDTRANSITIONS 15 #define BGPPEERFSMESTABLISHEDTIME 16 #define BGPPEERCONNECTRETRYINTERVAL 17 #define BGPPEERHOLDTIME 18 #define BGPPEERKEEPALIVE 19 #define BGPPEERHOLDTIMECONFIGURED 20 #define BGPPEERKEEPALIVECONFIGURED 21 #define BGPPEERMINASORIGINATIONINTERVAL 22 #define BGPPEERMINROUTEADVERTISEMENTINTERVAL 23 #define BGPPEERINUPDATEELAPSEDTIME 24 /* BGP MIB bgpIdentifier. */ #define BGPIDENTIFIER 0 /* BGP MIB bgpRcvdPathAttrTable */ #define BGPPATHATTRPEER 1 #define BGPPATHATTRDESTNETWORK 2 #define BGPPATHATTRORIGIN 3 #define BGPPATHATTRASPATH 4 #define BGPPATHATTRNEXTHOP 5 #define BGPPATHATTRINTERASMETRIC 6 /* BGP MIB bgp4PathAttrTable. */ #define BGP4PATHATTRPEER 1 #define BGP4PATHATTRIPADDRPREFIXLEN 2 #define BGP4PATHATTRIPADDRPREFIX 3 #define BGP4PATHATTRORIGIN 4 #define BGP4PATHATTRASPATHSEGMENT 5 #define BGP4PATHATTRNEXTHOP 6 #define BGP4PATHATTRMULTIEXITDISC 7 #define BGP4PATHATTRLOCALPREF 8 #define BGP4PATHATTRATOMICAGGREGATE 9 #define BGP4PATHATTRAGGREGATORAS 10 #define BGP4PATHATTRAGGREGATORADDR 11 #define BGP4PATHATTRCALCLOCALPREF 12 #define BGP4PATHATTRBEST 13 #define BGP4PATHATTRUNKNOWN 14 /* SNMP value hack. */ #define INTEGER ASN_INTEGER #define INTEGER32 ASN_INTEGER #define COUNTER32 ASN_COUNTER #define OCTET_STRING ASN_OCTET_STR #define IPADDRESS ASN_IPADDRESS #define GAUGE32 ASN_UNSIGNED /* Declare static local variables for convenience. */ SNMP_LOCAL_VARIABLES /* BGP-MIB instances. */ oid bgp_oid [] = { BGP4MIB }; oid bgp_trap_oid [] = { BGP4MIB, 0 }; /* IP address 0.0.0.0. */ static struct in_addr bgp_empty_addr = {0}; /* Hook functions. */ static u_char *bgpVersion (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpLocalAs (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpPeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpRcvdPathAttrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgpIdentifier (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *bgp4PathAttrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); /* static u_char *bgpTraps (); */ struct variable bgp_variables[] = { /* BGP version. */ {BGPVERSION, OCTET_STRING, RONLY, bgpVersion, 1, {1}}, /* BGP local AS. */ {BGPLOCALAS, INTEGER, RONLY, bgpLocalAs, 1, {2}}, /* BGP peer table. */ {BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 1}}, {BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 2}}, {BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 3}}, {BGPPEERNEGOTIATEDVERSION, INTEGER32, RONLY, bgpPeerTable, 3, {3, 1, 4}}, {BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 5}}, {BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 6}}, {BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable, 3, {3, 1, 7}}, {BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 8}}, {BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 9}}, {BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 10}}, {BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 11}}, {BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 12}}, {BGPPEEROUTTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 13}}, {BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable, 3, {3, 1, 14}}, {BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable, 3, {3, 1, 15}}, {BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable, 3, {3, 1, 16}}, {BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 17}}, {BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 18}}, {BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable, 3, {3, 1, 19}}, {BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 20}}, {BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 21}}, {BGPPEERMINASORIGINATIONINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 22}}, {BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable, 3, {3, 1, 23}}, {BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable, 3, {3, 1, 24}}, /* BGP identifier. */ {BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier, 1, {4}}, /* BGP received path attribute table. */ {BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 1}}, {BGPPATHATTRDESTNETWORK, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 2}}, {BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 3}}, {BGPPATHATTRASPATH, OCTET_STRING, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 4}}, {BGPPATHATTRNEXTHOP, IPADDRESS, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 5}}, {BGPPATHATTRINTERASMETRIC, INTEGER32, RONLY, bgpRcvdPathAttrTable, 3, {5, 1, 6}}, /* BGP-4 received path attribute table. */ {BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 1}}, {BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 2}}, {BGP4PATHATTRIPADDRPREFIX, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 3}}, {BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 4}}, {BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable, 3, {6, 1, 5}}, {BGP4PATHATTRNEXTHOP, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 6}}, {BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 7}}, {BGP4PATHATTRLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 8}}, {BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 9}}, {BGP4PATHATTRAGGREGATORAS, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 10}}, {BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable, 3, {6, 1, 11}}, {BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 12}}, {BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable, 3, {6, 1, 13}}, {BGP4PATHATTRUNKNOWN, OCTET_STRING, RONLY, bgp4PathAttrTable, 3, {6, 1, 14}}, }; static u_char * bgpVersion (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static u_char version; if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Retrun BGP version. Zebra bgpd only support version 4. */ version = (0x80 >> (BGP_VERSION_4 - 1)); /* Return octet string length 1. */ *var_len = 1; return (u_char *)&version; } static u_char * bgpLocalAs (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct bgp *bgp; if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Get BGP structure. */ bgp = bgp_get_default (); if (! bgp) return NULL; return SNMP_INTEGER (bgp->as); } static struct peer * peer_lookup_addr_ipv4 (struct in_addr *src) { struct bgp *bgp; struct peer *peer; struct listnode *node; struct in_addr addr; int ret; bgp = bgp_get_default (); if (! bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { ret = inet_pton (AF_INET, peer->host, &addr); if (ret > 0) { if (IPV4_ADDR_SAME (&addr, src)) return peer; } } return NULL; } static struct peer * bgp_peer_lookup_next (struct in_addr *src) { struct bgp *bgp; struct peer *peer; struct listnode *node; struct in_addr *p; union sockunion su; int ret; memset (&su, 0, sizeof (union sockunion)); bgp = bgp_get_default (); if (! bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr); if (ret > 0) { p = &su.sin.sin_addr; if (ntohl (p->s_addr) > ntohl (src->s_addr)) { src->s_addr = p->s_addr; return peer; } } } return NULL; } static struct peer * bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { struct peer *peer = NULL; int len; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + v->namelen, IN_ADDR_SIZE, addr); peer = peer_lookup_addr_ipv4 (addr); return peer; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); peer = bgp_peer_lookup_next (addr); if (peer == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); *length = sizeof (struct in_addr) + v->namelen; return peer; } return NULL; } /* BGP write methods. */ static int write_bgpPeerTable (int action, u_char *var_val, u_char var_val_type, size_t var_val_len, u_char *statP, oid *name, size_t length, struct variable *v) { struct in_addr addr; struct peer *peer; long intval; size_t bigsize = SNMP_MAX_LEN; if (var_val_type != ASN_INTEGER) { return SNMP_ERR_WRONGTYPE; } if (var_val_len != sizeof (long)) { return SNMP_ERR_WRONGLENGTH; } if (! asn_parse_int(var_val, &bigsize, &var_val_type, &intval, sizeof(long))) { return SNMP_ERR_WRONGENCODING; } memset (&addr, 0, sizeof (struct in_addr)); peer = bgpPeerTable_lookup (v, name, &length, &addr, 1); if (! peer) return SNMP_ERR_NOSUCHNAME; printf ("val: %ld\n", intval); switch (v->magic) { case BGPPEERADMINSTATUS: #define BGP_PeerAdmin_stop 1 #define BGP_PeerAdmin_start 2 /* When the peer is established, */ if (intval == BGP_PeerAdmin_stop) BGP_EVENT_ADD (peer, BGP_Stop); else if (intval == BGP_PeerAdmin_start) ; /* Do nothing. */ else return SNMP_ERR_NOSUCHNAME; break; case BGPPEERCONNECTRETRYINTERVAL: SET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = intval; peer->v_connect = intval; break; case BGPPEERHOLDTIMECONFIGURED: SET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->holdtime = intval; peer->v_holdtime = intval; break; case BGPPEERKEEPALIVECONFIGURED: SET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->keepalive = intval; peer->v_keepalive = intval; break; case BGPPEERMINASORIGINATIONINTERVAL: peer->v_asorig = intval; break; case BGPPEERMINROUTEADVERTISEMENTINTERVAL: peer->v_routeadv = intval; break; } return SNMP_ERR_NOERROR; } static u_char * bgpPeerTable (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static struct in_addr addr; struct peer *peer; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); peer = bgpPeerTable_lookup (v, name, length, &addr, exact); if (! peer) return NULL; switch (v->magic) { case BGPPEERIDENTIFIER: return SNMP_IPADDRESS (peer->remote_id); break; case BGPPEERSTATE: return SNMP_INTEGER (peer->status); break; case BGPPEERADMINSTATUS: *write_method = write_bgpPeerTable; #define BGP_PeerAdmin_stop 1 #define BGP_PeerAdmin_start 2 if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) return SNMP_INTEGER (BGP_PeerAdmin_stop); else return SNMP_INTEGER (BGP_PeerAdmin_start); break; case BGPPEERNEGOTIATEDVERSION: return SNMP_INTEGER (BGP_VERSION_4); break; case BGPPEERLOCALADDR: if (peer->su_local) return SNMP_IPADDRESS (peer->su_local->sin.sin_addr); else return SNMP_IPADDRESS (bgp_empty_addr); break; case BGPPEERLOCALPORT: if (peer->su_local) return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port)); else return SNMP_INTEGER (0); break; case BGPPEERREMOTEADDR: if (peer->su_remote) return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr); else return SNMP_IPADDRESS (bgp_empty_addr); break; case BGPPEERREMOTEPORT: if (peer->su_remote) return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port)); else return SNMP_INTEGER (0); break; case BGPPEERREMOTEAS: return SNMP_INTEGER (peer->as); break; case BGPPEERINUPDATES: return SNMP_INTEGER (peer->update_in); break; case BGPPEEROUTUPDATES: return SNMP_INTEGER (peer->update_out); break; case BGPPEERINTOTALMESSAGES: return SNMP_INTEGER (peer->open_in + peer->update_in + peer->keepalive_in + peer->notify_in + peer->refresh_in + peer->dynamic_cap_in); break; case BGPPEEROUTTOTALMESSAGES: return SNMP_INTEGER (peer->open_out + peer->update_out + peer->keepalive_out + peer->notify_out + peer->refresh_out + peer->dynamic_cap_out); break; case BGPPEERLASTERROR: { static u_char lasterror[2]; lasterror[0] = peer->notify.code; lasterror[1] = peer->notify.subcode; *var_len = 2; return (u_char *)&lasterror; } break; case BGPPEERFSMESTABLISHEDTRANSITIONS: return SNMP_INTEGER (peer->established); break; case BGPPEERFSMESTABLISHEDTIME: if (peer->uptime == 0) return SNMP_INTEGER (0); else return SNMP_INTEGER (bgp_clock () - peer->uptime); break; case BGPPEERCONNECTRETRYINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_connect); break; case BGPPEERHOLDTIME: return SNMP_INTEGER (peer->v_holdtime); break; case BGPPEERKEEPALIVE: return SNMP_INTEGER (peer->v_keepalive); break; case BGPPEERHOLDTIMECONFIGURED: *write_method = write_bgpPeerTable; if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) return SNMP_INTEGER (peer->holdtime); else return SNMP_INTEGER (peer->v_holdtime); break; case BGPPEERKEEPALIVECONFIGURED: *write_method = write_bgpPeerTable; if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) return SNMP_INTEGER (peer->keepalive); else return SNMP_INTEGER (peer->v_keepalive); break; case BGPPEERMINASORIGINATIONINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_asorig); break; case BGPPEERMINROUTEADVERTISEMENTINTERVAL: *write_method = write_bgpPeerTable; return SNMP_INTEGER (peer->v_routeadv); break; case BGPPEERINUPDATEELAPSEDTIME: if (peer->update_time == 0) return SNMP_INTEGER (0); else return SNMP_INTEGER (bgp_clock () - peer->update_time); break; default: return NULL; break; } return NULL; } static u_char * bgpIdentifier (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct bgp *bgp; if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; bgp = bgp_get_default (); if (!bgp) return NULL; return SNMP_IPADDRESS (bgp->router_id); } static u_char * bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { /* Received Path Attribute Table. This table contains, one entry per path to a network, path attributes received from all peers running BGP version 3 or less. This table is obsolete, having been replaced in functionality with the bgp4PathAttrTable. */ return NULL; } static struct bgp_info * bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length, struct bgp *bgp, struct prefix_ipv4 *addr, int exact) { oid *offset; int offsetlen; struct bgp_info *binfo; struct bgp_info *min; struct bgp_node *rn; union sockunion su; unsigned int len; struct in_addr paddr; #define BGP_PATHATTR_ENTRY_OFFSET \ (IN_ADDR_SIZE + 1 + IN_ADDR_SIZE) if (exact) { if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET) return NULL; /* Set OID offset for prefix. */ offset = name + v->namelen; oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix); offset += IN_ADDR_SIZE; /* Prefix length. */ addr->prefixlen = *offset; offset++; /* Peer address. */ su.sin.sin_family = AF_INET; oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr); /* Lookup node. */ rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST], (struct prefix *) addr); if (rn) { bgp_unlock_node (rn); for (binfo = rn->info; binfo; binfo = binfo->next) if (sockunion_same (&binfo->peer->su, &su)) return binfo; } } else { offset = name + v->namelen; offsetlen = *length - v->namelen; len = offsetlen; if (offsetlen == 0) rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]); else { if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, &addr->prefix); offset += IN_ADDR_SIZE; offsetlen -= IN_ADDR_SIZE; if (offsetlen > 0) addr->prefixlen = *offset; else addr->prefixlen = len * 8; rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST], (struct prefix *) addr); offset++; offsetlen--; } if (offsetlen > 0) { len = offsetlen; if (len > IN_ADDR_SIZE) len = IN_ADDR_SIZE; oid2in_addr (offset, len, &paddr); } else paddr.s_addr = 0; if (! rn) return NULL; do { min = NULL; for (binfo = rn->info; binfo; binfo = binfo->next) { if (binfo->peer->su.sin.sin_family == AF_INET && ntohl (paddr.s_addr) < ntohl (binfo->peer->su.sin.sin_addr.s_addr)) { if (min) { if (ntohl (binfo->peer->su.sin.sin_addr.s_addr) < ntohl (min->peer->su.sin.sin_addr.s_addr)) min = binfo; } else min = binfo; } } if (min) { *length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET; offset = name + v->namelen; oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE); offset += IN_ADDR_SIZE; *offset = rn->p.prefixlen; offset++; oid_copy_addr (offset, &min->peer->su.sin.sin_addr, IN_ADDR_SIZE); addr->prefix = rn->p.u.prefix4; addr->prefixlen = rn->p.prefixlen; bgp_unlock_node (rn); return min; } paddr.s_addr = 0; } while ((rn = bgp_route_next (rn)) != NULL); } return NULL; } static u_char * bgp4PathAttrTable (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct bgp *bgp; struct bgp_info *binfo; struct prefix_ipv4 addr; bgp = bgp_get_default (); if (! bgp) return NULL; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct prefix_ipv4)); binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact); if (! binfo) return NULL; switch (v->magic) { case BGP4PATHATTRPEER: /* 1 */ return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr); break; case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */ return SNMP_INTEGER (addr.prefixlen); break; case BGP4PATHATTRIPADDRPREFIX: /* 3 */ return SNMP_IPADDRESS (addr.prefix); break; case BGP4PATHATTRORIGIN: /* 4 */ return SNMP_INTEGER (binfo->attr->origin); break; case BGP4PATHATTRASPATHSEGMENT: /* 5 */ return aspath_snmp_pathseg (binfo->attr->aspath, var_len); break; case BGP4PATHATTRNEXTHOP: /* 6 */ return SNMP_IPADDRESS (binfo->attr->nexthop); break; case BGP4PATHATTRMULTIEXITDISC: /* 7 */ return SNMP_INTEGER (binfo->attr->med); break; case BGP4PATHATTRLOCALPREF: /* 8 */ return SNMP_INTEGER (binfo->attr->local_pref); break; case BGP4PATHATTRATOMICAGGREGATE: /* 9 */ return SNMP_INTEGER (1); break; case BGP4PATHATTRAGGREGATORAS: /* 10 */ if (binfo->attr->extra) return SNMP_INTEGER (binfo->attr->extra->aggregator_as); else return SNMP_INTEGER (0); break; case BGP4PATHATTRAGGREGATORADDR: /* 11 */ if (binfo->attr->extra) return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr); else return SNMP_INTEGER (0); break; case BGP4PATHATTRCALCLOCALPREF: /* 12 */ return SNMP_INTEGER (-1); break; case BGP4PATHATTRBEST: /* 13 */ #define BGP4_PathAttrBest_false 1 #define BGP4_PathAttrBest_true 2 if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) return SNMP_INTEGER (BGP4_PathAttrBest_true); else return SNMP_INTEGER (BGP4_PathAttrBest_false); break; case BGP4PATHATTRUNKNOWN: /* 14 */ *var_len = 0; return NULL; break; } return NULL; } /* BGP Traps. */ struct trap_object bgpTrapList[] = { {3, {3, 1, BGPPEERLASTERROR}}, {3, {3, 1, BGPPEERSTATE}} }; void bgpTrapEstablished (struct peer *peer) { int ret; struct in_addr addr; oid index[sizeof (oid) * IN_ADDR_SIZE]; ret = inet_aton (peer->host, &addr); if (ret == 0) return; oid_copy_addr (index, &addr, IN_ADDR_SIZE); smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable), bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPESTABLISHED); } void bgpTrapBackwardTransition (struct peer *peer) { int ret; struct in_addr addr; oid index[sizeof (oid) * IN_ADDR_SIZE]; ret = inet_aton (peer->host, &addr); if (ret == 0) return; oid_copy_addr (index, &addr, IN_ADDR_SIZE); smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable), bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid), bgp_oid, sizeof bgp_oid / sizeof (oid), index, IN_ADDR_SIZE, bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object), BGPBACKWARDTRANSITION); } void bgp_snmp_init (void) { smux_init (bm->master); REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); } #endif /* HAVE_SNMP */ quagga-0.99.24.1/bgpd/bgp_dump.c0000644000175000017500000005252012476520570013115 00000000000000/* BGP-4 dump routine Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "stream.h" #include "sockunion.h" #include "command.h" #include "prefix.h" #include "thread.h" #include "linklist.h" #include "bgpd/bgp_table.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_dump.h" enum bgp_dump_type { BGP_DUMP_ALL, BGP_DUMP_UPDATES, BGP_DUMP_ROUTES }; enum MRT_MSG_TYPES { MSG_NULL, MSG_START, /* sender is starting up */ MSG_DIE, /* receiver should shut down */ MSG_I_AM_DEAD, /* sender is shutting down */ MSG_PEER_DOWN, /* sender's peer is down */ MSG_PROTOCOL_BGP, /* msg is a BGP packet */ MSG_PROTOCOL_RIP, /* msg is a RIP packet */ MSG_PROTOCOL_IDRP, /* msg is an IDRP packet */ MSG_PROTOCOL_RIPNG, /* msg is a RIPNG packet */ MSG_PROTOCOL_BGP4PLUS, /* msg is a BGP4+ packet */ MSG_PROTOCOL_BGP4PLUS_01, /* msg is a BGP4+ (draft 01) packet */ MSG_PROTOCOL_OSPF, /* msg is an OSPF packet */ MSG_TABLE_DUMP, /* routing table dump */ MSG_TABLE_DUMP_V2 /* routing table dump, version 2 */ }; static int bgp_dump_interval_func (struct thread *); struct bgp_dump { enum bgp_dump_type type; char *filename; FILE *fp; unsigned int interval; char *interval_str; struct thread *t_interval; }; /* BGP packet dump output buffer. */ struct stream *bgp_dump_obuf; /* BGP dump strucuture for 'dump bgp all' */ struct bgp_dump bgp_dump_all; /* BGP dump structure for 'dump bgp updates' */ struct bgp_dump bgp_dump_updates; /* BGP dump structure for 'dump bgp routes' */ struct bgp_dump bgp_dump_routes; /* Dump whole BGP table is very heavy process. */ struct thread *t_bgp_dump_routes; /* Some define for BGP packet dump. */ static FILE * bgp_dump_open_file (struct bgp_dump *bgp_dump) { int ret; time_t clock; struct tm *tm; char fullpath[MAXPATHLEN]; char realpath[MAXPATHLEN]; mode_t oldumask; time (&clock); tm = localtime (&clock); if (bgp_dump->filename[0] != DIRECTORY_SEP) { sprintf (fullpath, "%s/%s", vty_get_cwd (), bgp_dump->filename); ret = strftime (realpath, MAXPATHLEN, fullpath, tm); } else ret = strftime (realpath, MAXPATHLEN, bgp_dump->filename, tm); if (ret == 0) { zlog_warn ("bgp_dump_open_file: strftime error"); return NULL; } if (bgp_dump->fp) fclose (bgp_dump->fp); oldumask = umask(0777 & ~LOGFILE_MASK); bgp_dump->fp = fopen (realpath, "w"); if (bgp_dump->fp == NULL) { zlog_warn ("bgp_dump_open_file: %s: %s", realpath, strerror (errno)); umask(oldumask); return NULL; } umask(oldumask); return bgp_dump->fp; } static int bgp_dump_interval_add (struct bgp_dump *bgp_dump, int interval) { int secs_into_day; time_t t; struct tm *tm; if (interval > 0) { /* Periodic dump every interval seconds */ if ((interval < 86400) && ((86400 % interval) == 0)) { /* Dump at predictable times: if a day has a whole number of * intervals, dump every interval seconds starting from midnight */ (void) time(&t); tm = localtime(&t); secs_into_day = tm->tm_sec + 60*tm->tm_min + 60*60*tm->tm_hour; interval = interval - secs_into_day % interval; /* always > 0 */ } bgp_dump->t_interval = thread_add_timer (master, bgp_dump_interval_func, bgp_dump, interval); } else { /* One-off dump: execute immediately, don't affect any scheduled dumps */ bgp_dump->t_interval = thread_add_event (master, bgp_dump_interval_func, bgp_dump, 0); } return 0; } /* Dump common header. */ static void bgp_dump_header (struct stream *obuf, int type, int subtype) { time_t now; /* Set header. */ time (&now); /* Put dump packet header. */ stream_putl (obuf, now); stream_putw (obuf, type); stream_putw (obuf, subtype); stream_putl (obuf, 0); /* len */ } static void bgp_dump_set_size (struct stream *s, int type) { stream_putl_at (s, 8, stream_get_endp (s) - BGP_DUMP_HEADER_SIZE); } static void bgp_dump_routes_index_table(struct bgp *bgp) { struct peer *peer; struct listnode *node; uint16_t peerno = 0; struct stream *obuf; obuf = bgp_dump_obuf; stream_reset (obuf); /* MRT header */ bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_PEER_INDEX_TABLE); /* Collector BGP ID */ stream_put_in_addr (obuf, &bgp->router_id); /* View name */ if(bgp->name) { stream_putw (obuf, strlen(bgp->name)); stream_put(obuf, bgp->name, strlen(bgp->name)); } else { stream_putw(obuf, 0); } /* Peer count */ stream_putw (obuf, listcount(bgp->peer)); /* Walk down all peers */ for(ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { /* Peer's type */ if (sockunion_family(&peer->su) == AF_INET) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP); } #ifdef HAVE_IPV6 else if (sockunion_family(&peer->su) == AF_INET6) { stream_putc (obuf, TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4+TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6); } #endif /* HAVE_IPV6 */ /* Peer's BGP ID */ stream_put_in_addr (obuf, &peer->remote_id); /* Peer's IP address */ if (sockunion_family(&peer->su) == AF_INET) { stream_put_in_addr (obuf, &peer->su.sin.sin_addr); } #ifdef HAVE_IPV6 else if (sockunion_family(&peer->su) == AF_INET6) { stream_write (obuf, (u_char *)&peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); } #endif /* HAVE_IPV6 */ /* Peer's AS number. */ /* Note that, as this is an AS4 compliant quagga, the RIB is always AS4 */ stream_putl (obuf, peer->as); /* Store the peer number for this peer */ peer->table_dump_index = peerno; peerno++; } bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); fflush (bgp_dump_routes.fp); } /* Runs under child process. */ static unsigned int bgp_dump_routes_func (int afi, int first_run, unsigned int seq) { struct stream *obuf; struct bgp_info *info; struct bgp_node *rn; struct bgp *bgp; struct bgp_table *table; bgp = bgp_get_default (); if (!bgp) return seq; if (bgp_dump_routes.fp == NULL) return seq; /* Note that bgp_dump_routes_index_table will do ipv4 and ipv6 peers, so this should only be done on the first call to bgp_dump_routes_func. ( this function will be called once for ipv4 and once for ipv6 ) */ if(first_run) bgp_dump_routes_index_table(bgp); obuf = bgp_dump_obuf; stream_reset(obuf); /* Walk down each BGP route. */ table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { if(!rn->info) continue; stream_reset(obuf); /* MRT header */ if (afi == AFI_IP) { bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV4_UNICAST); } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { bgp_dump_header (obuf, MSG_TABLE_DUMP_V2, TABLE_DUMP_V2_RIB_IPV6_UNICAST); } #endif /* HAVE_IPV6 */ /* Sequence number */ stream_putl(obuf, seq); /* Prefix length */ stream_putc (obuf, rn->p.prefixlen); /* Prefix */ if (afi == AFI_IP) { /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write(obuf, (u_char *)&rn->p.u.prefix4, (rn->p.prefixlen+7)/8); } #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { /* We'll dump only the useful bits (those not 0), but have to align on 8 bits */ stream_write (obuf, (u_char *)&rn->p.u.prefix6, (rn->p.prefixlen+7)/8); } #endif /* HAVE_IPV6 */ /* Save where we are now, so we can overwride the entry count later */ int sizep = stream_get_endp(obuf); /* Entry count */ uint16_t entry_count = 0; /* Entry count, note that this is overwritten later */ stream_putw(obuf, 0); for (info = rn->info; info; info = info->next) { entry_count++; /* Peer index */ stream_putw(obuf, info->peer->table_dump_index); /* Originated */ #ifdef HAVE_CLOCK_MONOTONIC stream_putl (obuf, time(NULL) - (bgp_clock() - info->uptime)); #else stream_putl (obuf, info->uptime); #endif /* HAVE_CLOCK_MONOTONIC */ /* Dump attribute. */ /* Skip prefix & AFI/SAFI for MP_NLRI */ bgp_dump_routes_attr (obuf, info->attr, &rn->p); } /* Overwrite the entry count, now that we know the right number */ stream_putw_at (obuf, sizep, entry_count); seq++; bgp_dump_set_size(obuf, MSG_TABLE_DUMP_V2); fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_routes.fp); } fflush (bgp_dump_routes.fp); return seq; } static int bgp_dump_interval_func (struct thread *t) { struct bgp_dump *bgp_dump; bgp_dump = THREAD_ARG (t); bgp_dump->t_interval = NULL; /* Reschedule dump even if file couldn't be opened this time... */ if (bgp_dump_open_file (bgp_dump) != NULL) { /* In case of bgp_dump_routes, we need special route dump function. */ if (bgp_dump->type == BGP_DUMP_ROUTES) { unsigned int seq = bgp_dump_routes_func (AFI_IP, 1, 0); #ifdef HAVE_IPV6 bgp_dump_routes_func (AFI_IP6, 0, seq); #endif /* HAVE_IPV6 */ /* Close the file now. For a RIB dump there's no point in leaving * it open until the next scheduled dump starts. */ fclose(bgp_dump->fp); bgp_dump->fp = NULL; } } /* if interval is set reschedule */ if (bgp_dump->interval > 0) bgp_dump_interval_add (bgp_dump, bgp_dump->interval); return 0; } /* Dump common information. */ static void bgp_dump_common (struct stream *obuf, struct peer *peer, int forceas4) { char empty[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Source AS number and Destination AS number. */ if (forceas4 || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) { stream_putl (obuf, peer->as); stream_putl (obuf, peer->local_as); } else { stream_putw (obuf, peer->as); stream_putw (obuf, peer->local_as); } if (peer->su.sa.sa_family == AF_INET) { stream_putw (obuf, peer->ifindex); stream_putw (obuf, AFI_IP); stream_put (obuf, &peer->su.sin.sin_addr, IPV4_MAX_BYTELEN); if (peer->su_local) stream_put (obuf, &peer->su_local->sin.sin_addr, IPV4_MAX_BYTELEN); else stream_put (obuf, empty, IPV4_MAX_BYTELEN); } #ifdef HAVE_IPV6 else if (peer->su.sa.sa_family == AF_INET6) { /* Interface Index and Address family. */ stream_putw (obuf, peer->ifindex); stream_putw (obuf, AFI_IP6); /* Source IP Address and Destination IP Address. */ stream_put (obuf, &peer->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); if (peer->su_local) stream_put (obuf, &peer->su_local->sin6.sin6_addr, IPV6_MAX_BYTELEN); else stream_put (obuf, empty, IPV6_MAX_BYTELEN); } #endif /* HAVE_IPV6 */ } /* Dump BGP status change. */ void bgp_dump_state (struct peer *peer, int status_old, int status_new) { struct stream *obuf; /* If dump file pointer is disabled return immediately. */ if (bgp_dump_all.fp == NULL) return; /* Make dump stream. */ obuf = bgp_dump_obuf; stream_reset (obuf); bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_STATE_CHANGE_AS4); bgp_dump_common (obuf, peer, 1);/* force this in as4speak*/ stream_putw (obuf, status_old); stream_putw (obuf, status_new); /* Set length. */ bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump_all.fp); fflush (bgp_dump_all.fp); } static void bgp_dump_packet_func (struct bgp_dump *bgp_dump, struct peer *peer, struct stream *packet) { struct stream *obuf; /* If dump file pointer is disabled return immediately. */ if (bgp_dump->fp == NULL) return; /* Make dump stream. */ obuf = bgp_dump_obuf; stream_reset (obuf); /* Dump header and common part. */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) ) { bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE_AS4); } else { bgp_dump_header (obuf, MSG_PROTOCOL_BGP4MP, BGP4MP_MESSAGE); } bgp_dump_common (obuf, peer, 0); /* Packet contents. */ stream_put (obuf, STREAM_DATA (packet), stream_get_endp (packet)); /* Set length. */ bgp_dump_set_size (obuf, MSG_PROTOCOL_BGP4MP); /* Write to the stream. */ fwrite (STREAM_DATA (obuf), stream_get_endp (obuf), 1, bgp_dump->fp); fflush (bgp_dump->fp); } /* Called from bgp_packet.c when BGP packet is received. */ void bgp_dump_packet (struct peer *peer, int type, struct stream *packet) { /* bgp_dump_all. */ bgp_dump_packet_func (&bgp_dump_all, peer, packet); /* bgp_dump_updates. */ if (type == BGP_MSG_UPDATE) bgp_dump_packet_func (&bgp_dump_updates, peer, packet); } static unsigned int bgp_dump_parse_time (const char *str) { int i; int len; int seen_h; int seen_m; int time; unsigned int total; time = 0; total = 0; seen_h = 0; seen_m = 0; len = strlen (str); for (i = 0; i < len; i++) { if (isdigit ((int) str[i])) { time *= 10; time += str[i] - '0'; } else if (str[i] == 'H' || str[i] == 'h') { if (seen_h) return 0; if (seen_m) return 0; total += time * 60 *60; time = 0; seen_h = 1; } else if (str[i] == 'M' || str[i] == 'm') { if (seen_m) return 0; total += time * 60; time = 0; seen_h = 1; } else return 0; } return total + time; } static int bgp_dump_set (struct vty *vty, struct bgp_dump *bgp_dump, enum bgp_dump_type type, const char *path, const char *interval_str) { unsigned int interval; if (interval_str) { /* Check interval string. */ interval = bgp_dump_parse_time (interval_str); if (interval == 0) { vty_out (vty, "Malformed interval string%s", VTY_NEWLINE); return CMD_WARNING; } /* Don't schedule duplicate dumps if the dump command is given twice */ if (interval == bgp_dump->interval && type == bgp_dump->type && path && bgp_dump->filename && !strcmp (path, bgp_dump->filename)) { return CMD_SUCCESS; } /* Set interval. */ bgp_dump->interval = interval; if (bgp_dump->interval_str) free (bgp_dump->interval_str); bgp_dump->interval_str = strdup (interval_str); } else { interval = 0; } /* Create interval thread. */ bgp_dump_interval_add (bgp_dump, interval); /* Set type. */ bgp_dump->type = type; /* Set file name. */ if (bgp_dump->filename) free (bgp_dump->filename); bgp_dump->filename = strdup (path); /* This should be called when interval is expired. */ bgp_dump_open_file (bgp_dump); return CMD_SUCCESS; } static int bgp_dump_unset (struct vty *vty, struct bgp_dump *bgp_dump) { /* Set file name. */ if (bgp_dump->filename) { free (bgp_dump->filename); bgp_dump->filename = NULL; } /* This should be called when interval is expired. */ if (bgp_dump->fp) { fclose (bgp_dump->fp); bgp_dump->fp = NULL; } /* Create interval thread. */ if (bgp_dump->t_interval) { thread_cancel (bgp_dump->t_interval); bgp_dump->t_interval = NULL; } bgp_dump->interval = 0; if (bgp_dump->interval_str) { free (bgp_dump->interval_str); bgp_dump->interval_str = NULL; } return CMD_SUCCESS; } DEFUN (dump_bgp_all, dump_bgp_all_cmd, "dump bgp all PATH", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], NULL); } DEFUN (dump_bgp_all_interval, dump_bgp_all_interval_cmd, "dump bgp all PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_all, BGP_DUMP_ALL, argv[0], argv[1]); } DEFUN (no_dump_bgp_all, no_dump_bgp_all_cmd, "no dump bgp all [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump all BGP packets\n") { return bgp_dump_unset (vty, &bgp_dump_all); } DEFUN (dump_bgp_updates, dump_bgp_updates_cmd, "dump bgp updates PATH", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], NULL); } DEFUN (dump_bgp_updates_interval, dump_bgp_updates_interval_cmd, "dump bgp updates PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_updates, BGP_DUMP_UPDATES, argv[0], argv[1]); } DEFUN (no_dump_bgp_updates, no_dump_bgp_updates_cmd, "no dump bgp updates [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump BGP updates only\n") { return bgp_dump_unset (vty, &bgp_dump_updates); } DEFUN (dump_bgp_routes, dump_bgp_routes_cmd, "dump bgp routes-mrt PATH", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n") { return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], NULL); } DEFUN (dump_bgp_routes_interval, dump_bgp_routes_interval_cmd, "dump bgp routes-mrt PATH INTERVAL", "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n" "Output filename\n" "Interval of output\n") { return bgp_dump_set (vty, &bgp_dump_routes, BGP_DUMP_ROUTES, argv[0], argv[1]); } DEFUN (no_dump_bgp_routes, no_dump_bgp_routes_cmd, "no dump bgp routes-mrt [PATH] [INTERVAL]", NO_STR "Dump packet\n" "BGP packet dump\n" "Dump whole BGP routing table\n") { return bgp_dump_unset (vty, &bgp_dump_routes); } /* BGP node structure. */ static struct cmd_node bgp_dump_node = { DUMP_NODE, "", 1 }; #if 0 char * config_time2str (unsigned int interval) { static char buf[BUFSIZ]; buf[0] = '\0'; if (interval / 3600) { sprintf (buf, "%dh", interval / 3600); interval %= 3600; } if (interval / 60) { sprintf (buf + strlen (buf), "%dm", interval /60); interval %= 60; } if (interval) { sprintf (buf + strlen (buf), "%d", interval); } return buf; } #endif static int config_write_bgp_dump (struct vty *vty) { if (bgp_dump_all.filename) { if (bgp_dump_all.interval_str) vty_out (vty, "dump bgp all %s %s%s", bgp_dump_all.filename, bgp_dump_all.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp all %s%s", bgp_dump_all.filename, VTY_NEWLINE); } if (bgp_dump_updates.filename) { if (bgp_dump_updates.interval_str) vty_out (vty, "dump bgp updates %s %s%s", bgp_dump_updates.filename, bgp_dump_updates.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp updates %s%s", bgp_dump_updates.filename, VTY_NEWLINE); } if (bgp_dump_routes.filename) { if (bgp_dump_routes.interval_str) vty_out (vty, "dump bgp routes-mrt %s %s%s", bgp_dump_routes.filename, bgp_dump_routes.interval_str, VTY_NEWLINE); else vty_out (vty, "dump bgp routes-mrt %s%s", bgp_dump_routes.filename, VTY_NEWLINE); } return 0; } /* Initialize BGP packet dump functionality. */ void bgp_dump_init (void) { memset (&bgp_dump_all, 0, sizeof (struct bgp_dump)); memset (&bgp_dump_updates, 0, sizeof (struct bgp_dump)); memset (&bgp_dump_routes, 0, sizeof (struct bgp_dump)); bgp_dump_obuf = stream_new (BGP_MAX_PACKET_SIZE + BGP_DUMP_MSG_HEADER + BGP_DUMP_HEADER_SIZE); install_node (&bgp_dump_node, config_write_bgp_dump); install_element (CONFIG_NODE, &dump_bgp_all_cmd); install_element (CONFIG_NODE, &dump_bgp_all_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_all_cmd); install_element (CONFIG_NODE, &dump_bgp_updates_cmd); install_element (CONFIG_NODE, &dump_bgp_updates_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_updates_cmd); install_element (CONFIG_NODE, &dump_bgp_routes_cmd); install_element (CONFIG_NODE, &dump_bgp_routes_interval_cmd); install_element (CONFIG_NODE, &no_dump_bgp_routes_cmd); } void bgp_dump_finish (void) { stream_free (bgp_dump_obuf); bgp_dump_obuf = NULL; } quagga-0.99.24.1/bgpd/bgp_clist.c0000644000175000017500000005242212476520570013267 00000000000000/* BGP community-list and extcommunity-list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "prefix.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" /* Lookup master structure for community-list or extcommunity-list. */ struct community_list_master * community_list_master_lookup (struct community_list_handler *ch, int master) { if (ch) switch (master) { case COMMUNITY_LIST_MASTER: return &ch->community_list; case EXTCOMMUNITY_LIST_MASTER: return &ch->extcommunity_list; } return NULL; } /* Allocate a new community list entry. */ static struct community_entry * community_entry_new (void) { return XCALLOC (MTYPE_COMMUNITY_LIST_ENTRY, sizeof (struct community_entry)); } /* Free community list entry. */ static void community_entry_free (struct community_entry *entry) { switch (entry->style) { case COMMUNITY_LIST_STANDARD: if (entry->u.com) community_free (entry->u.com); break; case EXTCOMMUNITY_LIST_STANDARD: /* In case of standard extcommunity-list, configuration string is made by ecommunity_ecom2str(). */ if (entry->config) XFREE (MTYPE_ECOMMUNITY_STR, entry->config); if (entry->u.ecom) ecommunity_free (&entry->u.ecom); break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (entry->config) XFREE (MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) bgp_regex_free (entry->reg); default: break; } XFREE (MTYPE_COMMUNITY_LIST_ENTRY, entry); } /* Allocate a new community-list. */ static struct community_list * community_list_new (void) { return XCALLOC (MTYPE_COMMUNITY_LIST, sizeof (struct community_list)); } /* Free community-list. */ static void community_list_free (struct community_list *list) { if (list->name) XFREE (MTYPE_COMMUNITY_LIST_NAME, list->name); XFREE (MTYPE_COMMUNITY_LIST, list); } static struct community_list * community_list_insert (struct community_list_handler *ch, const char *name, int master) { size_t i; long number; struct community_list *new; struct community_list *point; struct community_list_list *list; struct community_list_master *cm; /* Lookup community-list master. */ cm = community_list_master_lookup (ch, master); if (!cm) return NULL; /* Allocate new community_list and copy given name. */ new = community_list_new (); new->name = XSTRDUP (MTYPE_COMMUNITY_LIST_NAME, name); /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen (name); i++) { if (isdigit ((int) name[i])) number = (number * 10) + (name[i] - '0'); else break; } /* In case of name is all digit character */ if (i == strlen (name)) { new->sort = COMMUNITY_LIST_NUMBER; /* Set access_list to number list. */ list = &cm->num; for (point = list->head; point; point = point->next) if (atol (point->name) >= number) break; } else { new->sort = COMMUNITY_LIST_STRING; /* Set access_list to string list. */ list = &cm->str; /* Set point to insertion point. */ for (point = list->head; point; point = point->next) if (strcmp (point->name, name) >= 0) break; } /* Link to upper list. */ new->parent = list; /* In case of this is the first element of master. */ if (list->head == NULL) { list->head = list->tail = new; return new; } /* In case of insertion is made at the tail of access_list. */ if (point == NULL) { new->prev = list->tail; list->tail->next = new; list->tail = new; return new; } /* In case of insertion is made at the head of access_list. */ if (point == list->head) { new->next = list->head; list->head->prev = new; list->head = new; return new; } /* Insertion is made at middle of the access_list. */ new->next = point; new->prev = point->prev; if (point->prev) point->prev->next = new; point->prev = new; return new; } struct community_list * community_list_lookup (struct community_list_handler *ch, const char *name, int master) { struct community_list *list; struct community_list_master *cm; if (!name) return NULL; cm = community_list_master_lookup (ch, master); if (!cm) return NULL; for (list = cm->num.head; list; list = list->next) if (strcmp (list->name, name) == 0) return list; for (list = cm->str.head; list; list = list->next) if (strcmp (list->name, name) == 0) return list; return NULL; } static struct community_list * community_list_get (struct community_list_handler *ch, const char *name, int master) { struct community_list *list; list = community_list_lookup (ch, name, master); if (!list) list = community_list_insert (ch, name, master); return list; } static void community_list_delete (struct community_list *list) { struct community_list_list *clist; struct community_entry *entry, *next; for (entry = list->head; entry; entry = next) { next = entry->next; community_entry_free (entry); } clist = list->parent; if (list->next) list->next->prev = list->prev; else clist->tail = list->prev; if (list->prev) list->prev->next = list->next; else clist->head = list->next; community_list_free (list); } static int community_list_empty_p (struct community_list *list) { return (list->head == NULL && list->tail == NULL) ? 1 : 0; } /* Add community-list entry to the list. */ static void community_list_entry_add (struct community_list *list, struct community_entry *entry) { entry->next = NULL; entry->prev = list->tail; if (list->tail) list->tail->next = entry; else list->head = entry; list->tail = entry; } /* Delete community-list entry from the list. */ static void community_list_entry_delete (struct community_list *list, struct community_entry *entry, int style) { if (entry->next) entry->next->prev = entry->prev; else list->tail = entry->prev; if (entry->prev) entry->prev->next = entry->next; else list->head = entry->next; community_entry_free (entry); if (community_list_empty_p (list)) community_list_delete (list); } /* Lookup community-list entry from the list. */ static struct community_entry * community_list_entry_lookup (struct community_list *list, const void *arg, int direct) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { switch (entry->style) { case COMMUNITY_LIST_STANDARD: if (community_cmp (entry->u.com, arg)) return entry; break; case EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp (entry->u.ecom, arg)) return entry; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, arg) == 0) return entry; break; default: break; } } return NULL; } /* Internal function to perform regular expression match for community attribute. */ static int community_regexp_match (struct community *com, regex_t * reg) { const char *str; /* When there is no communities attribute it is treated as empty string. */ if (com == NULL || com->size == 0) str = ""; else str = community_str (com); /* Regular expression match. */ if (regexec (reg, str, 0, NULL, 0) == 0) return 1; /* No match. */ return 0; } static int ecommunity_regexp_match (struct ecommunity *ecom, regex_t * reg) { const char *str; /* When there is no communities attribute it is treated as empty string. */ if (ecom == NULL || ecom->size == 0) str = ""; else str = ecommunity_str (ecom); /* Regular expression match. */ if (regexec (reg, str, 0, NULL, 0) == 0) return 1; /* No match. */ return 0; } /* Delete community attribute using regular expression match. Return modified communites attribute. */ static struct community * community_regexp_delete (struct community *com, regex_t * reg) { int i; u_int32_t comval; /* Maximum is "65535:65535" + '\0'. */ char c[12]; const char *str; if (!com) return NULL; i = 0; while (i < com->size) { memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); comval = ntohl (comval); switch (comval) { case COMMUNITY_INTERNET: str = "internet"; break; case COMMUNITY_NO_EXPORT: str = "no-export"; break; case COMMUNITY_NO_ADVERTISE: str = "no-advertise"; break; case COMMUNITY_LOCAL_AS: str = "local-AS"; break; default: sprintf (c, "%d:%d", (comval >> 16) & 0xFFFF, comval & 0xFFFF); str = c; break; } if (regexec (reg, str, 0, NULL, 0) == 0) community_del_val (com, com_nthval (com, i)); else i++; } return com; } /* When given community attribute matches to the community-list return 1 else return 0. */ int community_list_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include (entry->u.com, COMMUNITY_INTERNET)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (community_match (com, entry->u.com)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match (com, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } int ecommunity_list_match (struct ecommunity *ecom, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == EXTCOMMUNITY_LIST_STANDARD) { if (ecommunity_match (ecom, entry->u.ecom)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) { if (ecommunity_regexp_match (ecom, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } /* Perform exact matching. In case of expanded community-list, do same thing as community_list_match(). */ int community_list_exact_match (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (entry->style == COMMUNITY_LIST_STANDARD) { if (community_include (entry->u.com, COMMUNITY_INTERNET)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; if (community_cmp (com, entry->u.com)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } else if (entry->style == COMMUNITY_LIST_EXPANDED) { if (community_regexp_match (com, entry->reg)) return entry->direct == COMMUNITY_PERMIT ? 1 : 0; } } return 0; } /* Delete all permitted communities in the list from com. */ struct community * community_list_match_delete (struct community *com, struct community_list *list) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->any) { if (entry->direct == COMMUNITY_PERMIT) { /* This is a tricky part. Currently only * route_set_community_delete() uses this function. In the * function com->size is zero, it free the community * structure. */ com->size = 0; } return com; } if ((entry->style == COMMUNITY_LIST_STANDARD) && (community_include (entry->u.com, COMMUNITY_INTERNET) || community_match (com, entry->u.com) )) { if (entry->direct == COMMUNITY_PERMIT) community_delete (com, entry->u.com); else break; } else if ((entry->style == COMMUNITY_LIST_EXPANDED) && community_regexp_match (com, entry->reg)) { if (entry->direct == COMMUNITY_PERMIT) community_regexp_delete (com, entry->reg); else break; } } return com; } /* To avoid duplicated entry in the community-list, this function compares specified entry to existing entry. */ static int community_list_dup_check (struct community_list *list, struct community_entry *new) { struct community_entry *entry; for (entry = list->head; entry; entry = entry->next) { if (entry->style != new->style) continue; if (entry->direct != new->direct) continue; if (entry->any != new->any) continue; if (entry->any) return 1; switch (entry->style) { case COMMUNITY_LIST_STANDARD: if (community_cmp (entry->u.com, new->u.com)) return 1; break; case EXTCOMMUNITY_LIST_STANDARD: if (ecommunity_cmp (entry->u.ecom, new->u.ecom)) return 1; break; case COMMUNITY_LIST_EXPANDED: case EXTCOMMUNITY_LIST_EXPANDED: if (strcmp (entry->config, new->config) == 0) return 1; break; default: break; } } return 0; } /* Set community-list. */ int community_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct community *com = NULL; regex_t *regex = NULL; /* Get community list. */ list = community_list_get (ch, name, COMMUNITY_LIST_MASTER); /* When community-list already has entry, new entry should have same style. If you want to have mixed style community-list, you can comment out this check. */ if (!community_list_empty_p (list)) { struct community_entry *first; first = list->head; if (style != first->style) { return (first->style == COMMUNITY_LIST_STANDARD ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); } } if (str) { if (style == COMMUNITY_LIST_STANDARD) com = community_str2com (str); else regex = bgp_regcomp (str); if (! com && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; } entry = community_entry_new (); entry->direct = direct; entry->style = style; entry->any = (str ? 0 : 1); entry->u.com = com; entry->reg = regex; entry->config = (regex ? XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str) : NULL); /* Do not put duplicated community entry. */ if (community_list_dup_check (list, entry)) community_entry_free (entry); else community_list_entry_add (list, entry); return 0; } /* Unset community-list. When str is NULL, delete all of community-list entry belongs to the specified name. */ int community_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct community *com = NULL; regex_t *regex = NULL; /* Lookup community list. */ list = community_list_lookup (ch, name, COMMUNITY_LIST_MASTER); if (list == NULL) return COMMUNITY_LIST_ERR_CANT_FIND_LIST; /* Delete all of entry belongs to this community-list. */ if (!str) { community_list_delete (list); return 0; } if (style == COMMUNITY_LIST_STANDARD) com = community_str2com (str); else regex = bgp_regcomp (str); if (! com && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; if (com) entry = community_list_entry_lookup (list, com, direct); else entry = community_list_entry_lookup (list, str, direct); if (com) community_free (com); if (regex) bgp_regex_free (regex); if (!entry) return COMMUNITY_LIST_ERR_CANT_FIND_LIST; community_list_entry_delete (list, entry, style); return 0; } /* Set extcommunity-list. */ int extcommunity_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct ecommunity *ecom = NULL; regex_t *regex = NULL; entry = NULL; /* Get community list. */ list = community_list_get (ch, name, EXTCOMMUNITY_LIST_MASTER); /* When community-list already has entry, new entry should have same style. If you want to have mixed style community-list, you can comment out this check. */ if (!community_list_empty_p (list)) { struct community_entry *first; first = list->head; if (style != first->style) { return (first->style == EXTCOMMUNITY_LIST_STANDARD ? COMMUNITY_LIST_ERR_STANDARD_CONFLICT : COMMUNITY_LIST_ERR_EXPANDED_CONFLICT); } } if (str) { if (style == EXTCOMMUNITY_LIST_STANDARD) ecom = ecommunity_str2com (str, 0, 1); else regex = bgp_regcomp (str); if (! ecom && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; } if (ecom) ecom->str = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_DISPLAY); entry = community_entry_new (); entry->direct = direct; entry->style = style; entry->any = (str ? 0 : 1); if (ecom) entry->config = ecommunity_ecom2str (ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST); else if (regex) entry->config = XSTRDUP (MTYPE_COMMUNITY_LIST_CONFIG, str); else entry->config = NULL; entry->u.ecom = ecom; entry->reg = regex; /* Do not put duplicated community entry. */ if (community_list_dup_check (list, entry)) community_entry_free (entry); else community_list_entry_add (list, entry); return 0; } /* Unset extcommunity-list. When str is NULL, delete all of extcommunity-list entry belongs to the specified name. */ int extcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style) { struct community_entry *entry = NULL; struct community_list *list; struct ecommunity *ecom = NULL; regex_t *regex = NULL; /* Lookup extcommunity list. */ list = community_list_lookup (ch, name, EXTCOMMUNITY_LIST_MASTER); if (list == NULL) return COMMUNITY_LIST_ERR_CANT_FIND_LIST; /* Delete all of entry belongs to this extcommunity-list. */ if (!str) { community_list_delete (list); return 0; } if (style == EXTCOMMUNITY_LIST_STANDARD) ecom = ecommunity_str2com (str, 0, 1); else regex = bgp_regcomp (str); if (! ecom && ! regex) return COMMUNITY_LIST_ERR_MALFORMED_VAL; if (ecom) entry = community_list_entry_lookup (list, ecom, direct); else entry = community_list_entry_lookup (list, str, direct); if (ecom) ecommunity_free (&ecom); if (regex) bgp_regex_free (regex); if (!entry) return COMMUNITY_LIST_ERR_CANT_FIND_LIST; community_list_entry_delete (list, entry, style); return 0; } /* Initializa community-list. Return community-list handler. */ struct community_list_handler * community_list_init (void) { struct community_list_handler *ch; ch = XCALLOC (MTYPE_COMMUNITY_LIST_HANDLER, sizeof (struct community_list_handler)); return ch; } /* Terminate community-list. */ void community_list_terminate (struct community_list_handler *ch) { struct community_list_master *cm; struct community_list *list; cm = &ch->community_list; while ((list = cm->num.head) != NULL) community_list_delete (list); while ((list = cm->str.head) != NULL) community_list_delete (list); cm = &ch->extcommunity_list; while ((list = cm->num.head) != NULL) community_list_delete (list); while ((list = cm->str.head) != NULL) community_list_delete (list); XFREE (MTYPE_COMMUNITY_LIST_HANDLER, ch); } quagga-0.99.24.1/bgpd/bgp_regex.c0000644000175000017500000000420212476520570013254 00000000000000/* AS regular expression routine Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "log.h" #include "command.h" #include "memory.h" #include "bgpd.h" #include "bgp_aspath.h" #include "bgp_regex.h" /* Character `_' has special mean. It represents [,{}() ] and the beginning of the line(^) and the end of the line ($). (^|[,{}() ]|$) */ regex_t * bgp_regcomp (const char *regstr) { /* Convert _ character to generic regular expression. */ int i, j; int len; int magic = 0; char *magic_str; char magic_regexp[] = "(^|[,{}() ]|$)"; int ret; regex_t *regex; len = strlen (regstr); for (i = 0; i < len; i++) if (regstr[i] == '_') magic++; magic_str = XMALLOC (MTYPE_TMP, len + (14 * magic) + 1); for (i = 0, j = 0; i < len; i++) { if (regstr[i] == '_') { memcpy (magic_str + j, magic_regexp, strlen (magic_regexp)); j += strlen (magic_regexp); } else magic_str[j++] = regstr[i]; } magic_str[j] = '\0'; regex = XMALLOC (MTYPE_BGP_REGEXP, sizeof (regex_t)); ret = regcomp (regex, magic_str, REG_EXTENDED|REG_NOSUB); XFREE (MTYPE_TMP, magic_str); if (ret != 0) { XFREE (MTYPE_BGP_REGEXP, regex); return NULL; } return regex; } int bgp_regexec (regex_t *regex, struct aspath *aspath) { return regexec (regex, aspath->str, 0, NULL, 0); } void bgp_regex_free (regex_t *regex) { regfree (regex); XFREE (MTYPE_BGP_REGEXP, regex); } quagga-0.99.24.1/bgpd/bgp_filter.c0000644000175000017500000004007712476520570013441 00000000000000/* AS path filter list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "log.h" #include "memory.h" #include "buffer.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_filter.h" /* List of AS filter list. */ struct as_list_list { struct as_list *head; struct as_list *tail; }; /* AS path filter master. */ struct as_list_master { /* List of access_list which name is number. */ struct as_list_list num; /* List of access_list which name is string. */ struct as_list_list str; /* Hook function which is executed when new access_list is added. */ void (*add_hook) (void); /* Hook function which is executed when access_list is deleted. */ void (*delete_hook) (void); }; /* Element of AS path filter. */ struct as_filter { struct as_filter *next; struct as_filter *prev; enum as_filter_type type; regex_t *reg; char *reg_str; }; enum as_list_type { ACCESS_TYPE_STRING, ACCESS_TYPE_NUMBER }; /* AS path filter list. */ struct as_list { char *name; enum as_list_type type; struct as_list *next; struct as_list *prev; struct as_filter *head; struct as_filter *tail; }; /* ip as-path access-list 10 permit AS1. */ static struct as_list_master as_list_master = { {NULL, NULL}, {NULL, NULL}, NULL, NULL }; /* Allocate new AS filter. */ static struct as_filter * as_filter_new (void) { return XCALLOC (MTYPE_AS_FILTER, sizeof (struct as_filter)); } /* Free allocated AS filter. */ static void as_filter_free (struct as_filter *asfilter) { if (asfilter->reg) bgp_regex_free (asfilter->reg); if (asfilter->reg_str) XFREE (MTYPE_AS_FILTER_STR, asfilter->reg_str); XFREE (MTYPE_AS_FILTER, asfilter); } /* Make new AS filter. */ static struct as_filter * as_filter_make (regex_t *reg, const char *reg_str, enum as_filter_type type) { struct as_filter *asfilter; asfilter = as_filter_new (); asfilter->reg = reg; asfilter->type = type; asfilter->reg_str = XSTRDUP (MTYPE_AS_FILTER_STR, reg_str); return asfilter; } static struct as_filter * as_filter_lookup (struct as_list *aslist, const char *reg_str, enum as_filter_type type) { struct as_filter *asfilter; for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) if (strcmp (reg_str, asfilter->reg_str) == 0) return asfilter; return NULL; } static void as_list_filter_add (struct as_list *aslist, struct as_filter *asfilter) { asfilter->next = NULL; asfilter->prev = aslist->tail; if (aslist->tail) aslist->tail->next = asfilter; else aslist->head = asfilter; aslist->tail = asfilter; } /* Lookup as_list from list of as_list by name. */ struct as_list * as_list_lookup (const char *name) { struct as_list *aslist; if (name == NULL) return NULL; for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) if (strcmp (aslist->name, name) == 0) return aslist; for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) if (strcmp (aslist->name, name) == 0) return aslist; return NULL; } static struct as_list * as_list_new (void) { return XCALLOC (MTYPE_AS_LIST, sizeof (struct as_list)); } static void as_list_free (struct as_list *aslist) { if (aslist->name) { free (aslist->name); aslist->name = NULL; } XFREE (MTYPE_AS_LIST, aslist); } /* Insert new AS list to list of as_list. Each as_list is sorted by the name. */ static struct as_list * as_list_insert (const char *name) { size_t i; long number; struct as_list *aslist; struct as_list *point; struct as_list_list *list; /* Allocate new access_list and copy given name. */ aslist = as_list_new (); aslist->name = strdup (name); assert (aslist->name); /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen (name); i++) { if (isdigit ((int) name[i])) number = (number * 10) + (name[i] - '0'); else break; } /* In case of name is all digit character */ if (i == strlen (name)) { aslist->type = ACCESS_TYPE_NUMBER; /* Set access_list to number list. */ list = &as_list_master.num; for (point = list->head; point; point = point->next) if (atol (point->name) >= number) break; } else { aslist->type = ACCESS_TYPE_STRING; /* Set access_list to string list. */ list = &as_list_master.str; /* Set point to insertion point. */ for (point = list->head; point; point = point->next) if (strcmp (point->name, name) >= 0) break; } /* In case of this is the first element of master. */ if (list->head == NULL) { list->head = list->tail = aslist; return aslist; } /* In case of insertion is made at the tail of access_list. */ if (point == NULL) { aslist->prev = list->tail; list->tail->next = aslist; list->tail = aslist; return aslist; } /* In case of insertion is made at the head of access_list. */ if (point == list->head) { aslist->next = list->head; list->head->prev = aslist; list->head = aslist; return aslist; } /* Insertion is made at middle of the access_list. */ aslist->next = point; aslist->prev = point->prev; if (point->prev) point->prev->next = aslist; point->prev = aslist; return aslist; } static struct as_list * as_list_get (const char *name) { struct as_list *aslist; aslist = as_list_lookup (name); if (aslist == NULL) { aslist = as_list_insert (name); /* Run hook function. */ if (as_list_master.add_hook) (*as_list_master.add_hook) (); } return aslist; } static const char * filter_type_str (enum as_filter_type type) { switch (type) { case AS_FILTER_PERMIT: return "permit"; case AS_FILTER_DENY: return "deny"; default: return ""; } } static void as_list_delete (struct as_list *aslist) { struct as_list_list *list; struct as_filter *filter, *next; for (filter = aslist->head; filter; filter = next) { next = filter->next; as_filter_free (filter); } if (aslist->type == ACCESS_TYPE_NUMBER) list = &as_list_master.num; else list = &as_list_master.str; if (aslist->next) aslist->next->prev = aslist->prev; else list->tail = aslist->prev; if (aslist->prev) aslist->prev->next = aslist->next; else list->head = aslist->next; as_list_free (aslist); } static int as_list_empty (struct as_list *aslist) { if (aslist->head == NULL && aslist->tail == NULL) return 1; else return 0; } static void as_list_filter_delete (struct as_list *aslist, struct as_filter *asfilter) { if (asfilter->next) asfilter->next->prev = asfilter->prev; else aslist->tail = asfilter->prev; if (asfilter->prev) asfilter->prev->next = asfilter->next; else aslist->head = asfilter->next; as_filter_free (asfilter); /* If access_list becomes empty delete it from access_master. */ if (as_list_empty (aslist)) as_list_delete (aslist); /* Run hook function. */ if (as_list_master.delete_hook) (*as_list_master.delete_hook) (); } static int as_filter_match (struct as_filter *asfilter, struct aspath *aspath) { if (bgp_regexec (asfilter->reg, aspath) != REG_NOMATCH) return 1; return 0; } /* Apply AS path filter to AS. */ enum as_filter_type as_list_apply (struct as_list *aslist, void *object) { struct as_filter *asfilter; struct aspath *aspath; aspath = (struct aspath *) object; if (aslist == NULL) return AS_FILTER_DENY; for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { if (as_filter_match (asfilter, aspath)) return asfilter->type; } return AS_FILTER_DENY; } /* Add hook function. */ void as_list_add_hook (void (*func) (void)) { as_list_master.add_hook = func; } /* Delete hook function. */ void as_list_delete_hook (void (*func) (void)) { as_list_master.delete_hook = func; } static int as_list_dup_check (struct as_list *aslist, struct as_filter *new) { struct as_filter *asfilter; for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { if (asfilter->type == new->type && strcmp (asfilter->reg_str, new->reg_str) == 0) return 1; } return 0; } DEFUN (ip_as_path, ip_as_path_cmd, "ip as-path access-list WORD (deny|permit) .LINE", IP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression to match the BGP AS paths\n") { enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; regex_t *regex; char *regstr; /* Check the filter type. */ if (strncmp (argv[1], "p", 1) == 0) type = AS_FILTER_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) type = AS_FILTER_DENY; else { vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); return CMD_WARNING; } /* Check AS path regex. */ regstr = argv_concat(argv, argc, 2); regex = bgp_regcomp (regstr); if (!regex) { XFREE (MTYPE_TMP, regstr); vty_out (vty, "can't compile regexp %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } asfilter = as_filter_make (regex, regstr, type); XFREE (MTYPE_TMP, regstr); /* Install new filter to the access_list. */ aslist = as_list_get (argv[0]); /* Duplicate insertion check. */; if (as_list_dup_check (aslist, asfilter)) as_filter_free (asfilter); else as_list_filter_add (aslist, asfilter); return CMD_SUCCESS; } DEFUN (no_ip_as_path, no_ip_as_path_cmd, "no ip as-path access-list WORD (deny|permit) .LINE", NO_STR IP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n" "Specify packets to reject\n" "Specify packets to forward\n" "A regular-expression to match the BGP AS paths\n") { enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; char *regstr; regex_t *regex; /* Lookup AS list from AS path list. */ aslist = as_list_lookup (argv[0]); if (aslist == NULL) { vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } /* Check the filter type. */ if (strncmp (argv[1], "p", 1) == 0) type = AS_FILTER_PERMIT; else if (strncmp (argv[1], "d", 1) == 0) type = AS_FILTER_DENY; else { vty_out (vty, "filter type must be [permit|deny]%s", VTY_NEWLINE); return CMD_WARNING; } /* Compile AS path. */ regstr = argv_concat(argv, argc, 2); regex = bgp_regcomp (regstr); if (!regex) { XFREE (MTYPE_TMP, regstr); vty_out (vty, "can't compile regexp %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } /* Lookup asfilter. */ asfilter = as_filter_lookup (aslist, regstr, type); XFREE (MTYPE_TMP, regstr); bgp_regex_free (regex); if (asfilter == NULL) { vty_out (vty, "%s", VTY_NEWLINE); return CMD_WARNING; } as_list_filter_delete (aslist, asfilter); return CMD_SUCCESS; } DEFUN (no_ip_as_path_all, no_ip_as_path_all_cmd, "no ip as-path access-list WORD", NO_STR IP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" "Regular expression access list name\n") { struct as_list *aslist; aslist = as_list_lookup (argv[0]); if (aslist == NULL) { vty_out (vty, "ip as-path access-list %s doesn't exist%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } as_list_delete (aslist); /* Run hook function. */ if (as_list_master.delete_hook) (*as_list_master.delete_hook) (); return CMD_SUCCESS; } static void as_list_show (struct vty *vty, struct as_list *aslist) { struct as_filter *asfilter; vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), asfilter->reg_str, VTY_NEWLINE); } } static void as_list_show_all (struct vty *vty) { struct as_list *aslist; struct as_filter *asfilter; for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) { vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), asfilter->reg_str, VTY_NEWLINE); } } for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) { vty_out (vty, "AS path access list %s%s", aslist->name, VTY_NEWLINE); for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { vty_out (vty, " %s %s%s", filter_type_str (asfilter->type), asfilter->reg_str, VTY_NEWLINE); } } } DEFUN (show_ip_as_path_access_list, show_ip_as_path_access_list_cmd, "show ip as-path-access-list WORD", SHOW_STR IP_STR "List AS path access lists\n" "AS path access list name\n") { struct as_list *aslist; aslist = as_list_lookup (argv[0]); if (aslist) as_list_show (vty, aslist); return CMD_SUCCESS; } DEFUN (show_ip_as_path_access_list_all, show_ip_as_path_access_list_all_cmd, "show ip as-path-access-list", SHOW_STR IP_STR "List AS path access lists\n") { as_list_show_all (vty); return CMD_SUCCESS; } static int config_write_as_list (struct vty *vty) { struct as_list *aslist; struct as_filter *asfilter; int write = 0; for (aslist = as_list_master.num.head; aslist; aslist = aslist->next) for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { vty_out (vty, "ip as-path access-list %s %s %s%s", aslist->name, filter_type_str (asfilter->type), asfilter->reg_str, VTY_NEWLINE); write++; } for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) { vty_out (vty, "ip as-path access-list %s %s %s%s", aslist->name, filter_type_str (asfilter->type), asfilter->reg_str, VTY_NEWLINE); write++; } return write; } static struct cmd_node as_list_node = { AS_LIST_NODE, "", 1 }; /* Register functions. */ void bgp_filter_init (void) { install_node (&as_list_node, config_write_as_list); install_element (CONFIG_NODE, &ip_as_path_cmd); install_element (CONFIG_NODE, &no_ip_as_path_cmd); install_element (CONFIG_NODE, &no_ip_as_path_all_cmd); install_element (VIEW_NODE, &show_ip_as_path_access_list_cmd); install_element (VIEW_NODE, &show_ip_as_path_access_list_all_cmd); install_element (ENABLE_NODE, &show_ip_as_path_access_list_cmd); install_element (ENABLE_NODE, &show_ip_as_path_access_list_all_cmd); } void bgp_filter_reset (void) { struct as_list *aslist; struct as_list *next; for (aslist = as_list_master.num.head; aslist; aslist = next) { next = aslist->next; as_list_delete (aslist); } for (aslist = as_list_master.str.head; aslist; aslist = next) { next = aslist->next; as_list_delete (aslist); } assert (as_list_master.num.head == NULL); assert (as_list_master.num.tail == NULL); assert (as_list_master.str.head == NULL); assert (as_list_master.str.tail == NULL); } quagga-0.99.24.1/bgpd/bgp_network.c0000644000175000017500000003503412476520570013642 00000000000000/* BGP network related fucntions Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "sockunion.h" #include "sockopt.h" #include "memory.h" #include "log.h" #include "if.h" #include "prefix.h" #include "command.h" #include "privs.h" #include "linklist.h" #include "network.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_network.h" extern struct zebra_privs_t bgpd_privs; /* BGP listening socket. */ struct bgp_listener { int fd; union sockunion su; struct thread *thread; }; /* * Set MD5 key for the socket, for the given IPv4 peer address. * If the password is NULL or zero-length, the option will be disabled. */ static int bgp_md5_set_socket (int socket, union sockunion *su, const char *password) { int ret = -1; int en = ENOSYS; assert (socket >= 0); #if HAVE_DECL_TCP_MD5SIG ret = sockopt_tcp_signature (socket, su, password); en = errno; #endif /* HAVE_TCP_MD5SIG */ if (ret < 0) zlog (NULL, LOG_WARNING, "can't set TCP_MD5SIG option on socket %d: %s", socket, safe_strerror (en)); return ret; } /* Helper for bgp_connect */ static int bgp_md5_set_connect (int socket, union sockunion *su, const char *password) { int ret = -1; #if HAVE_DECL_TCP_MD5SIG if ( bgpd_privs.change (ZPRIVS_RAISE) ) { zlog_err ("%s: could not raise privs", __func__); return ret; } ret = bgp_md5_set_socket (socket, su, password); if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("%s: could not lower privs", __func__); #endif /* HAVE_TCP_MD5SIG */ return ret; } int bgp_md5_set (struct peer *peer) { struct listnode *node; int ret = 0; struct bgp_listener *listener; if ( bgpd_privs.change (ZPRIVS_RAISE) ) { zlog_err ("%s: could not raise privs", __func__); return -1; } /* Just set the password on the listen socket(s). Outbound connections * are taken care of in bgp_connect() below. */ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener)) if (listener->su.sa.sa_family == peer->su.sa.sa_family) { ret = bgp_md5_set_socket (listener->fd, &peer->su, peer->password); break; } if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("%s: could not lower privs", __func__); return ret; } /* Update BGP socket send buffer size */ static void bgp_update_sock_send_buffer_size (int fd) { int size = BGP_SOCKET_SNDBUF_SIZE; int optval; socklen_t optlen = sizeof(optval); if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) { zlog_err("getsockopt of SO_SNDBUF failed %s\n", safe_strerror(errno)); return; } if (optval < size) { if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) { zlog_err("Couldn't increase send buffer: %s\n", safe_strerror(errno)); } } } static void bgp_set_socket_ttl (struct peer *peer, int bgp_sock) { char buf[INET_ADDRSTRLEN]; int ret; /* In case of peer is EBGP, we should set TTL for this connection. */ if (!peer->gtsm_hops && (peer_sort (peer) == BGP_PEER_EBGP)) { ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, peer->ttl); if (ret) { zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); } } else if (peer->gtsm_hops) { /* On Linux, setting minttl without setting ttl seems to mess with the outgoing ttl. Therefore setting both. */ ret = sockopt_ttl (peer->su.sa.sa_family, bgp_sock, MAXTTL); if (ret) { zlog_err ("%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); } ret = sockopt_minttl (peer->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer->gtsm_hops); if (ret) { zlog_err ("%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d", __func__, inet_ntop (AF_INET, &peer->remote_id, buf, sizeof(buf)), errno); } } } /* Accept bgp connection. */ static int bgp_accept (struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; /* Register accept thread. */ accept_sock = THREAD_FD (thread); if (accept_sock < 0) { zlog_err ("accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = thread_add_read (master, bgp_accept, listener, accept_sock); /* Accept client connection. */ bgp_sock = sockunion_accept (accept_sock, &su); if (bgp_sock < 0) { zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno)); return -1; } set_nonblocking (bgp_sock); /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(bgp_sock); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); /* Check remote IP address */ peer1 = peer_lookup (NULL, &su); if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) zlog_debug ("[Event] BGP connection IP address %s is not configured", inet_sutop (&su, buf)); else zlog_debug ("[Event] BGP connection IP address %s is Idle state", inet_sutop (&su, buf)); } close (bgp_sock); return -1; } bgp_set_socket_ttl (peer1, bgp_sock); /* Make dummy peer until read Open packet. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] Make dummy peer structure until read Open packet"); { char buf[SU_ADDRSTRLEN]; peer = peer_create_accept (peer1->bgp); SET_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER); peer->su = su; peer->fd = bgp_sock; peer->status = Active; peer->local_id = peer1->local_id; peer->v_holdtime = peer1->v_holdtime; peer->v_keepalive = peer1->v_keepalive; /* Make peer's address string. */ sockunion2str (&su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); } BGP_EVENT_ADD (peer, TCP_connection_open); return 0; } /* BGP socket bind. */ static int bgp_bind (struct peer *peer) { #ifdef SO_BINDTODEVICE int ret; struct ifreq ifreq; if (! peer->ifname) return 0; strncpy ((char *)&ifreq.ifr_name, peer->ifname, sizeof (ifreq.ifr_name)); if ( bgpd_privs.change (ZPRIVS_RAISE) ) zlog_err ("bgp_bind: could not raise privs"); ret = setsockopt (peer->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifreq, sizeof (ifreq)); if (bgpd_privs.change (ZPRIVS_LOWER) ) zlog_err ("bgp_bind: could not lower privs"); if (ret < 0) { zlog (peer->log, LOG_INFO, "bind to interface %s failed", peer->ifname); return ret; } #endif /* SO_BINDTODEVICE */ return 0; } static int bgp_update_address (struct interface *ifp, const union sockunion *dst, union sockunion *addr) { struct prefix *p, *sel, *d; struct connected *connected; struct listnode *node; int common; d = sockunion2hostprefix (dst); sel = NULL; common = -1; for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected)) { p = connected->address; if (p->family != d->family) continue; if (prefix_common_bits (p, d) > common) { sel = p; common = prefix_common_bits (sel, d); } } prefix_free (d); if (!sel) return 1; prefix2sockunion (sel, addr); return 0; } /* Update source selection. */ static void bgp_update_source (struct peer *peer) { struct interface *ifp; union sockunion addr; /* Source is specified with interface name. */ if (peer->update_if) { ifp = if_lookup_by_name (peer->update_if); if (! ifp) return; if (bgp_update_address (ifp, &peer->su, &addr)) return; sockunion_bind (peer->fd, &addr, 0, &addr); } /* Source is specified with IP address. */ if (peer->update_source) sockunion_bind (peer->fd, peer->update_source, 0, peer->update_source); } /* BGP try to connect to the peer. */ int bgp_connect (struct peer *peer) { unsigned int ifindex = 0; /* Make socket for the peer. */ peer->fd = sockunion_socket (&peer->su); if (peer->fd < 0) return -1; set_nonblocking (peer->fd); /* Set socket send buffer size */ bgp_update_sock_send_buffer_size(peer->fd); bgp_set_socket_ttl (peer, peer->fd); sockopt_reuseaddr (peer->fd); sockopt_reuseport (peer->fd); #ifdef IPTOS_PREC_INTERNETCONTROL if (bgpd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs", __func__); if (sockunion_family (&peer->su) == AF_INET) setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); # ifdef HAVE_IPV6 else if (sockunion_family (&peer->su) == AF_INET6) setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); # endif if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); #endif if (peer->password) bgp_md5_set_connect (peer->fd, &peer->su, peer->password); /* Bind socket. */ bgp_bind (peer); /* Update source bind. */ bgp_update_source (peer); #ifdef HAVE_IPV6 if (peer->ifname) ifindex = if_nametoindex (peer->ifname); #endif /* HAVE_IPV6 */ if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect start to %s fd %d", peer->host, peer->host, peer->fd); /* Connect to the remote peer. */ return sockunion_connect (peer->fd, &peer->su, htons (peer->port), ifindex); } /* After TCP connection is established. Get local address and port. */ void bgp_getsockname (struct peer *peer) { if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } peer->su_local = sockunion_getsockname (peer->fd); peer->su_remote = sockunion_getpeername (peer->fd); bgp_nexthop_set (peer->su_local, peer->su_remote, &peer->nexthop, peer); } static int bgp_listener (int sock, struct sockaddr *sa, socklen_t salen) { struct bgp_listener *listener; int ret, en; sockopt_reuseaddr (sock); sockopt_reuseport (sock); if (bgpd_privs.change (ZPRIVS_RAISE)) zlog_err ("%s: could not raise privs", __func__); #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); # ifdef HAVE_IPV6 else if (sa->sa_family == AF_INET6) setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); # endif #endif sockopt_v6only (sa->sa_family, sock); ret = bind (sock, sa, salen); en = errno; if (bgpd_privs.change (ZPRIVS_LOWER)) zlog_err ("%s: could not lower privs", __func__); if (ret < 0) { zlog_err ("bind: %s", safe_strerror (en)); return ret; } ret = listen (sock, 3); if (ret < 0) { zlog_err ("listen: %s", safe_strerror (errno)); return ret; } listener = XMALLOC (MTYPE_BGP_LISTENER, sizeof(*listener)); listener->fd = sock; memcpy(&listener->su, sa, salen); listener->thread = thread_add_read (master, bgp_accept, listener, sock); listnode_add (bm->listen_sockets, listener); return 0; } /* IPv6 supported version of BGP server socket setup. */ #ifdef HAVE_IPV6 int bgp_socket (unsigned short port, const char *address) { struct addrinfo *ainfo; struct addrinfo *ainfo_save; static const struct addrinfo req = { .ai_family = AF_UNSPEC, .ai_flags = AI_PASSIVE, .ai_socktype = SOCK_STREAM, }; int ret, count; char port_str[BUFSIZ]; snprintf (port_str, sizeof(port_str), "%d", port); port_str[sizeof (port_str) - 1] = '\0'; ret = getaddrinfo (address, port_str, &req, &ainfo_save); if (ret != 0) { zlog_err ("getaddrinfo: %s", gai_strerror (ret)); return -1; } count = 0; for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next) { int sock; if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) continue; sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol); if (sock < 0) { zlog_err ("socket: %s", safe_strerror (errno)); continue; } /* if we intend to implement ttl-security, this socket needs ttl=255 */ sockopt_ttl (ainfo->ai_family, sock, MAXTTL); ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen); if (ret == 0) ++count; else close(sock); } freeaddrinfo (ainfo_save); if (count == 0) { zlog_err ("%s: no usable addresses", __func__); return -1; } return 0; } #else /* Traditional IPv4 only version. */ int bgp_socket (unsigned short port, const char *address) { int sock; int socklen; struct sockaddr_in sin; int ret, en; sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zlog_err ("socket: %s", safe_strerror (errno)); return sock; } /* if we intend to implement ttl-security, this socket needs ttl=255 */ sockopt_ttl (AF_INET, sock, MAXTTL); memset (&sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = htons (port); socklen = sizeof (struct sockaddr_in); if (address && ((ret = inet_aton(address, &sin.sin_addr)) < 1)) { zlog_err("bgp_socket: could not parse ip address %s: %s", address, safe_strerror (errno)); return ret; } #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin.sin_len = socklen; #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ ret = bgp_listener (sock, (struct sockaddr *) &sin, socklen); if (ret < 0) { close (sock); return ret; } return sock; } #endif /* HAVE_IPV6 */ void bgp_close (void) { struct listnode *node, *next; struct bgp_listener *listener; for (ALL_LIST_ELEMENTS (bm->listen_sockets, node, next, listener)) { thread_cancel (listener->thread); close (listener->fd); listnode_delete (bm->listen_sockets, listener); XFREE (MTYPE_BGP_LISTENER, listener); } } quagga-0.99.24.1/bgpd/bgp_packet.c0000644000175000017500000021737112476520570013426 00000000000000/* BGP packet management routine. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "thread.h" #include "stream.h" #include "network.h" #include "prefix.h" #include "command.h" #include "log.h" #include "memory.h" #include "sockunion.h" /* for inet_ntop () */ #include "linklist.h" #include "plist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" int stream_put_prefix (struct stream *, struct prefix *); /* Set up BGP packet marker and packet type. */ static int bgp_packet_set_marker (struct stream *s, u_char type) { int i; /* Fill in marker. */ for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (s, 0xff); /* Dummy total length. This field is should be filled in later on. */ stream_putw (s, 0); /* BGP packet type. */ stream_putc (s, type); /* Return current stream size. */ return stream_get_endp (s); } /* Set BGP packet header size entry. If size is zero then use current stream size. */ static int bgp_packet_set_size (struct stream *s) { int cp; /* Preserve current pointer. */ cp = stream_get_endp (s); stream_putw_at (s, BGP_MARKER_SIZE, cp); return cp; } /* Add new packet to the peer. */ static void bgp_packet_add (struct peer *peer, struct stream *s) { /* Add packet to the end of list. */ stream_fifo_push (peer->obuf, s); } /* Free first packet. */ static void bgp_packet_delete (struct peer *peer) { stream_free (stream_fifo_pop (peer->obuf)); } /* Check file descriptor whether connect is established. */ static void bgp_connect_check (struct peer *peer) { int status; socklen_t slen; int ret; /* Anyway I have to reset read and write thread. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Check file descriptor. */ slen = sizeof (status); ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); return; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); } else { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] Connect failed (%s)", peer->host, safe_strerror (errno)); BGP_EVENT_ADD (peer, TCP_connection_open_failed); } } /* Make BGP update packet. */ static struct stream * bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *snlri; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct stream *packet; struct bgp_node *rn = NULL; struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long attrlen_pos = 0; size_t mpattrlen_pos = 0; size_t mpattr_pos = 0; s = peer->work; stream_reset (s); snlri = peer->scratch; stream_reset (snlri); adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); while (adv) { assert (adv->rn); rn = adv->rn; adj = adv->adj; if (adv->binfo) binfo = adv->binfo; /* When remaining space can't include NLRI and it's length. */ if (STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) <= (BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen))) break; /* If packet is empty, set attribute. */ if (stream_empty (s)) { struct peer *from = NULL; if (binfo) from = binfo->peer; /* 1: Write the BGP message header - 16 bytes marker, 2 bytes length, * one byte message type. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* 2: withdrawn routes length */ stream_putw (s, 0); /* 3: total attributes length - attrlen_pos stores the position */ attrlen_pos = stream_get_endp (s); stream_putw (s, 0); /* 4: if there is MP_REACH_NLRI attribute, that should be the first * attribute, according to draft-ietf-idr-error-handling. Save the * position. */ mpattr_pos = stream_get_endp(s); /* 5: Encode all the attributes, except MP_REACH_NLRI attr. */ total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, NULL, afi, safi, from, NULL, NULL); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { /* Encode the prefix in MP_REACH_NLRI attribute */ struct prefix_rd *prd = NULL; u_char *tag = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo && binfo->extra) tag = binfo->extra->tag; if (stream_empty(snlri)) mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi, adv->baa->attr); bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag); } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), rn->p.prefixlen); } /* Synchnorize attribute. */ if (adj->attr) bgp_attr_unintern (&adj->attr); else peer->scount[afi][safi]++; adj->attr = bgp_attr_intern (adv->baa->attr); adv = bgp_advertise_clean (peer, adj, afi, safi); } if (! stream_empty (s)) { if (!stream_empty(snlri)) { bgp_packet_mpattr_end(snlri, mpattrlen_pos); total_attr_len += stream_get_endp(snlri); } /* set the total attribute length correctly */ stream_putw_at (s, attrlen_pos, total_attr_len); if (!stream_empty(snlri)) packet = stream_dupcat(s, snlri, mpattr_pos); else packet = stream_dup (s); bgp_packet_set_size (packet); bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); stream_reset (s); stream_reset (snlri); return packet; } return NULL; } static struct stream * bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *packet; if (DISABLE_BGP_ANNOUNCE) return NULL; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("send End-of-RIB for %s to %s", afi_safi_print (afi, safi), peer->host); s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* Unfeasible Routes Length */ stream_putw (s, 0); if (afi == AFI_IP && safi == SAFI_UNICAST) { /* Total Path Attribute Length */ stream_putw (s, 0); } else { /* Total Path Attribute Length */ stream_putw (s, 6); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); stream_putc (s, 3); stream_putw (s, afi); stream_putc (s, safi); } bgp_packet_set_size (s); packet = stream_dup (s); bgp_packet_add (peer, packet); stream_free (s); return packet; } /* Make BGP withdraw packet. */ /* For ipv4 unicast: 16-octet marker | 2-octet length | 1-octet type | 2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0) */ /* For other afi/safis: 16-octet marker | 2-octet length | 1-octet type | 2-octet withdrawn route length (=0) | 2-octet attrlen | mp_unreach attr type | attr len | afi | safi | withdrawn prefixes */ static struct stream * bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *packet; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; size_t mp_start = 0; size_t attrlen_pos = 0; size_t mplen_pos = 0; u_char first_time = 1; s = peer->work; stream_reset (s); while ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { assert (adv->rn); adj = adv->adj; rn = adv->rn; if (STREAM_REMAIN (s) < (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); /* unfeasible routes length */ } else first_time = 0; if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { struct prefix_rd *prd = NULL; if (rn->prn) prd = (struct prefix_rd *) &rn->prn->p; /* If first time, format the MP_UNREACH header */ if (first_time) { attrlen_pos = stream_get_endp (s); /* total attr length = 0 for now. reevaluate later */ stream_putw (s, 0); mp_start = stream_get_endp (s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); } bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL); } if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ), rn->p.prefixlen); } peer->scount[afi][safi]--; bgp_adj_out_remove (rn, adj, peer, afi, safi); bgp_unlock_node (rn); } if (! stream_empty (s)) { if (afi == AFI_IP && safi == SAFI_UNICAST) { unfeasible_len = stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); stream_putw (s, 0); } else { /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); /* Set total path attribute length. */ total_attr_len = stream_get_endp(s) - mp_start; stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); packet = stream_dup (s); bgp_packet_add (peer, packet); stream_reset (s); return packet; } return NULL; } void bgp_default_update_send (struct peer *peer, struct attr *attr, afi_t afi, safi_t safi, struct peer *from) { struct stream *s; struct stream *packet; struct prefix p; unsigned long pos; bgp_size_t total_attr_len; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) { char attrstr[BUFSIZ]; char buf[INET6_BUFSIZ]; attrstr[0] = '\0'; bgp_dump_attr (peer, attr, attrstr, BUFSIZ); zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d %s", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), p.prefixlen, attrstr); } s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* Unfeasible Routes Length. */ stream_putw (s, 0); /* Make place for total attribute length. */ pos = stream_get_endp (s); stream_putw (s, 0); total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL); /* Set Total Path Attribute Length. */ stream_putw_at (s, pos, total_attr_len); /* NLRI set. */ if (p.family == AF_INET && safi == SAFI_UNICAST) stream_put_prefix (s, &p); /* Set size. */ bgp_packet_set_size (s); packet = stream_dup (s); stream_free (s); /* Dump packet if debug option is set. */ #ifdef DEBUG /* bgp_packet_dump (packet); */ #endif /* DEBUG */ /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } void bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi) { struct stream *s; struct stream *packet; struct prefix p; unsigned long attrlen_pos = 0; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; size_t mp_start = 0; size_t mplen_pos = 0; if (DISABLE_BGP_ANNOUNCE) return; if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 else str2prefix ("::/0", &p); #endif /* HAVE_IPV6 */ total_attr_len = 0; if (BGP_DEBUG (update, UPDATE_OUT)) { char buf[INET6_BUFSIZ]; zlog (peer->log, LOG_DEBUG, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ), p.prefixlen); } s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* Unfeasible Routes Length. */; cp = stream_get_endp (s); stream_putw (s, 0); /* Withdrawn Routes. */ if (p.family == AF_INET && safi == SAFI_UNICAST) { stream_put_prefix (s, &p); unfeasible_len = stream_get_endp (s) - cp - 2; /* Set unfeasible len. */ stream_putw_at (s, cp, unfeasible_len); /* Set total path attribute length. */ stream_putw (s, 0); } else { attrlen_pos = stream_get_endp (s); stream_putw (s, 0); mp_start = stream_get_endp (s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); /* Set total path attribute length. */ total_attr_len = stream_get_endp(s) - mp_start; stream_putw_at (s, attrlen_pos, total_attr_len); } bgp_packet_set_size (s); packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Get next packet to be written. */ static struct stream * bgp_write_packet (struct peer *peer) { afi_t afi; safi_t safi; struct stream *s = NULL; struct bgp_advertise *adv; s = stream_fifo_head (peer->obuf); if (s) return s; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); if (s) return s; } } for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) { if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV) && ! (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_BIT_RCV) && CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_BIT_ADV)) && ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE) && safi != SAFI_MPLS_VPN) { if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi], PEER_STATUS_EOR_RECEIVED)) s = bgp_update_packet (peer, afi, safi); } else s = bgp_update_packet (peer, afi, safi); } if (s) return s; } if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV)) { if (peer->afc_nego[afi][safi] && peer->synctime && ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND) && safi != SAFI_MPLS_VPN) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND); return bgp_update_packet_eor (peer, afi, safi); } } } return NULL; } /* Is there partially written packet or updates we can send right now. */ static int bgp_write_proceed (struct peer *peer) { afi_t afi; safi_t safi; struct bgp_advertise *adv; if (stream_fifo_head (peer->obuf)) return 1; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) return 1; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if ((adv = BGP_ADV_FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) if (adv->binfo->uptime < peer->synctime) return 1; return 0; } /* Write packet to the peer. */ int bgp_write (struct thread *thread) { struct peer *peer; u_char type; struct stream *s; int num; unsigned int count = 0; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_write = NULL; /* For non-blocking IO check. */ if (peer->status == Connect) { bgp_connect_check (peer); return 0; } s = bgp_write_packet (peer); if (!s) return 0; /* nothing to send */ sockopt_cork (peer->fd, 1); /* Nonblocking write until TCP output buffer is full. */ do { int writenum; /* Number of bytes to be sent. */ writenum = stream_get_endp (s) - stream_get_getp (s); /* Call write() system call. */ num = write (peer->fd, STREAM_PNT (s), writenum); if (num < 0) { /* write failed either retry needed or error */ if (ERRNO_IO_RETRY(errno)) break; BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } if (num != writenum) { /* Partial write */ stream_forward_getp (s, num); break; } /* Retrieve BGP packet type. */ stream_set_getp (s, BGP_MARKER_SIZE + 2); type = stream_getc (s); switch (type) { case BGP_MSG_OPEN: peer->open_out++; break; case BGP_MSG_UPDATE: peer->update_out++; break; case BGP_MSG_NOTIFY: peer->notify_out++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); /* Flush any existing events */ BGP_EVENT_ADD (peer, BGP_Stop); goto done; case BGP_MSG_KEEPALIVE: peer->keepalive_out++; break; case BGP_MSG_ROUTE_REFRESH_NEW: case BGP_MSG_ROUTE_REFRESH_OLD: peer->refresh_out++; break; case BGP_MSG_CAPABILITY: peer->dynamic_cap_out++; break; } /* OK we send packet so delete it. */ bgp_packet_delete (peer); } while (++count < BGP_WRITE_PACKET_MAX && (s = bgp_write_packet (peer)) != NULL); if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); done: sockopt_cork (peer->fd, 0); return 0; } /* This is only for sending NOTIFICATION message to neighbor. */ static int bgp_write_notify (struct peer *peer) { int ret, val; u_char type; struct stream *s; /* There should be at least one packet. */ s = stream_fifo_head (peer->obuf); if (!s) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); /* Stop collecting data within the socket */ sockopt_cork (peer->fd, 0); /* socket is in nonblocking mode, if we can't deliver the NOTIFY, well, * we only care about getting a clean shutdown at this point. */ ret = write (peer->fd, STREAM_DATA (s), stream_get_endp (s)); /* only connection reset/close gets counted as TCP_fatal_error, failure * to write the entire NOTIFY doesn't get different FSM treatment */ if (ret <= 0) { BGP_EVENT_ADD (peer, TCP_fatal_error); return 0; } /* Disable Nagle, make NOTIFY packet go out right away */ val = 1; (void) setsockopt (peer->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &val, sizeof (val)); /* Retrieve BGP packet type. */ stream_set_getp (s, BGP_MARKER_SIZE + 2); type = stream_getc (s); assert (type == BGP_MSG_NOTIFY); /* Type should be notify. */ peer->notify_out++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* Make keepalive packet and send it to the peer. */ void bgp_keepalive_send (struct peer *peer) { struct stream *s; int length; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make keepalive packet. */ bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); /* Set packet size. */ length = bgp_packet_set_size (s); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ if (BGP_DEBUG (keepalive, KEEPALIVE)) zlog_debug ("%s sending KEEPALIVE", peer->host); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_KEEPALIVE, length); /* Add packet to the peer. */ bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Make open packet and send it to the peer. */ void bgp_open_send (struct peer *peer) { struct stream *s; int length; u_int16_t send_holdtime; as_t local_as; if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; /* local-as Change */ if (peer->change_local_as) local_as = peer->change_local_as; else local_as = peer->local_as; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make open packet. */ bgp_packet_set_marker (s, BGP_MSG_OPEN); /* Set open packet values. */ stream_putc (s, BGP_VERSION_4); /* BGP version */ stream_putw (s, (local_as <= BGP_AS_MAX) ? (u_int16_t) local_as : BGP_AS_TRANS); stream_putw (s, send_holdtime); /* Hold Time */ stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ /* Set capability code. */ bgp_open_capability (s, peer); /* Set BGP packet length. */ length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s sending OPEN, version %d, my as %u, holdtime %d, id %s", peer->host, BGP_VERSION_4, local_as, send_holdtime, inet_ntoa (peer->local_id)); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_OPEN, length); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ /* Add packet to the peer. */ bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Send BGP notify packet with data potion. */ void bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, u_char *data, size_t datalen) { struct stream *s; int length; /* Allocate new stream. */ s = stream_new (BGP_MAX_PACKET_SIZE); /* Make nitify packet. */ bgp_packet_set_marker (s, BGP_MSG_NOTIFY); /* Set notify packet values. */ stream_putc (s, code); /* BGP notify code */ stream_putc (s, sub_code); /* BGP notify sub_code */ /* If notify data is present. */ if (data) stream_write (s, data, datalen); /* Set BGP packet length. */ length = bgp_packet_set_size (s); /* Add packet to the peer. */ stream_fifo_clean (peer->obuf); bgp_packet_add (peer, s); /* For debug */ { struct bgp_notify bgp_notify; int first = 0; int i; char c[4]; bgp_notify.code = code; bgp_notify.subcode = sub_code; bgp_notify.data = NULL; bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; if (bgp_notify.length) { bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); for (i = 0; i < bgp_notify.length; i++) if (first) { sprintf (c, " %02x", data[i]); strcat (bgp_notify.data, c); } else { first = 1; sprintf (c, "%02x", data[i]); strcpy (bgp_notify.data, c); } } bgp_notify_print (peer, &bgp_notify, "sending"); if (bgp_notify.data) XFREE (MTYPE_TMP, bgp_notify.data); } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_NOTIFY, length); /* peer reset cause */ if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE) { if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) { peer->last_reset = PEER_DOWN_USER_RESET; zlog_info ("Notification sent to neighbor %s: User reset", peer->host); } else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) { peer->last_reset = PEER_DOWN_USER_SHUTDOWN; zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); } else { peer->last_reset = PEER_DOWN_NOTIFY_SEND; zlog_info ("Notification sent to neighbor %s: type %u/%u", peer->host, code, sub_code); } } else zlog_info ("Notification sent to neighbor %s: configuration change", peer->host); /* Call immediately. */ BGP_WRITE_OFF (peer->t_write); bgp_write_notify (peer); } /* Send BGP notify packet. */ void bgp_notify_send (struct peer *peer, u_char code, u_char sub_code) { bgp_notify_send_with_data (peer, code, sub_code, NULL, 0); } /* Send route refresh message to the peer. */ void bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, u_char orf_type, u_char when_to_refresh, int remove) { struct stream *s; struct stream *packet; int length; struct bgp_filter *filter; int orf_refresh = 0; if (DISABLE_BGP_ANNOUNCE) return; filter = &peer->filter[afi][safi]; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW); else bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD); /* Encode Route Refresh message. */ stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) if (remove || filter->plist[FILTER_IN].plist) { u_int16_t orf_len; unsigned long orfp; orf_refresh = 1; stream_putc (s, when_to_refresh); stream_putc (s, orf_type); orfp = stream_get_endp (s); stream_putw (s, 0); if (remove) { UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), afi, safi); } else { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, ORF_COMMON_PART_DENY); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), afi, safi); } /* Total ORF Entry Len. */ orf_len = stream_get_endp (s) - orfp - 2; stream_putw_at (s, orfp, orf_len); } /* Set packet size. */ length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) { if (! orf_refresh) zlog_debug ("%s sending REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ? BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } /* Make real packet. */ packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* Send capability message to the peer. */ void bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action) { struct stream *s; struct stream *packet; int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); /* Encode MP_EXT capability. */ if (capability_code == CAPABILITY_CODE_MP) { stream_putc (s, action); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", afi, safi); } /* Set packet size. */ length = bgp_packet_set_size (s); /* Make real packet. */ packet = stream_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_CAPABILITY, length); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); } /* RFC1771 6.8 Connection collision detection. */ static int bgp_collision_detect (struct peer *new, struct in_addr remote_id) { struct peer *peer; struct listnode *node, *nnode; struct bgp *bgp; bgp = bgp_get_default (); if (! bgp) return 0; /* Upon receipt of an OPEN message, the local system must examine all of its connections that are in the OpenConfirm state. A BGP speaker may also examine connections in an OpenSent state if it knows the BGP Identifier of the peer by means outside of the protocol. If among these connections there is a connection to a remote BGP speaker whose BGP Identifier equals the one in the OPEN message, then the local system performs the following collision resolution procedure: */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { /* Under OpenConfirm status, local peer structure already hold remote router ID. */ if (peer != new && (peer->status == OpenConfirm || peer->status == OpenSent) && sockunion_same (&peer->su, &new->su)) { /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in the OPEN message). */ if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) { /* 2. If the value of the local BGP Identifier is less than the remote one, the local system closes BGP connection that already exists (the one that is already in the OpenConfirm state), and accepts BGP connection initiated by the remote system. */ if (peer->fd >= 0) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return 1; } else { /* 3. Otherwise, the local system closes newly created BGP connection (the one associated with the newly received OPEN message), and continues to use the existing one (the one that is already in the OpenConfirm state). */ if (new->fd >= 0) bgp_notify_send (new, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); return -1; } } } return 0; } static int bgp_open_receive (struct peer *peer, bgp_size_t size) { int ret; u_char version; u_char optlen; u_int16_t holdtime; u_int16_t send_holdtime; as_t remote_as; as_t as4 = 0; struct peer *realpeer; struct in_addr remote_id; int mp_capability; u_int8_t notify_data_remote_as[2]; u_int8_t notify_data_remote_id[4]; realpeer = NULL; /* Parse open packet. */ version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); remote_as = stream_getw (peer->ibuf); holdtime = stream_getw (peer->ibuf); memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); remote_id.s_addr = stream_get_ipv4 (peer->ibuf); /* Receive OPEN message log */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN, version %d, remote-as (in open) %u," " holdtime %d, id %s", peer->host, version, remote_as, holdtime, inet_ntoa (remote_id)); /* BEGIN to read the capability here, but dont do it yet */ mp_capability = 0; optlen = stream_getc (peer->ibuf); if (optlen != 0) { /* We need the as4 capability value *right now* because * if it is there, we have not got the remote_as yet, and without * that we do not know which peer is connecting to us now. */ as4 = peek_for_as4_capability (peer, optlen); } /* Just in case we have a silly peer who sends AS4 capability set to 0 */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && !as4) { zlog_err ("%s bad OPEN, got AS4 capability, but AS4 set to 0", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } if (remote_as == BGP_AS_TRANS) { /* Take the AS4 from the capability. We must have received the * capability now! Otherwise we have a asn16 peer who uses * BGP_AS_TRANS, for some unknown reason. */ if (as4 == BGP_AS_TRANS) { zlog_err ("%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed", peer->host); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } if (!as4 && BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but no AS4." " Odd, but proceeding.", peer->host); else if (as4 < BGP_AS_MAX && BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] OPEN remote_as is AS_TRANS, but AS4 (%u) fits " "in 2-bytes, very odd peer.", peer->host, as4); if (as4) remote_as = as4; } else { /* We may have a partner with AS4 who has an asno < BGP_AS_MAX */ /* If we have got the capability, peer->as4cap must match remote_as */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) && as4 != remote_as) { /* raise error, log this, close session */ zlog_err ("%s bad OPEN, got AS4 capability, but remote_as %u" " mismatch with 16bit 'myasn' %u in open", peer->host, as4, remote_as); bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS); return -1; } } /* Lookup peer from Open packet. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { int as = 0; realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); if (! realpeer) { /* Peer's source IP address is check in bgp_accept(), so this must be AS number mismatch or remote-id configuration mismatch. */ if (as) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); } return -1; } } /* When collision is detected and this peer is closed. Retrun immidiately. */ ret = bgp_collision_detect (peer, remote_id); if (ret < 0) return ret; /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (realpeer->status == Established && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) { realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); } else if (ret == 0 && realpeer->status != Active && realpeer->status != OpenSent && realpeer->status != OpenConfirm && realpeer->status != Connect) { /* XXX: This is an awful problem.. * * According to the RFC we should just let this connection (of the * accepted 'peer') continue on to Established if the other * connection (the 'realpeer' one) is in state Connect, and deal * with the more larval FSM as/when it gets far enough to receive * an Open. We don't do that though, we instead close the (more * developed) accepted connection. * * This means there's a race, which if hit, can loop: * * FSM for A FSM for B * realpeer accept-peer realpeer accept-peer * * Connect Connect * Active * OpenSent OpenSent * * Idle Active * OpenSent OpenSent * * Idle * * Connect Connect * * * If both sides are Quagga, they're almost certain to wait for * the same amount of time of course (which doesn't preclude other * implementations also waiting for same time). The race is * exacerbated by high-latency (in bgpd and/or the network). * * The reason we do this is because our FSM is tied to our peer * structure, which carries our configuration information, etc. * I.e. we can't let the accepted-peer FSM continue on as it is, * cause it's not associated with any actual peer configuration - * it's just a dummy. * * It's possible we could hack-fix this by just bgp_stop'ing the * realpeer and continueing on with the 'transfer FSM' below. * Ideally, we need to seperate FSMs from struct peer. * * Setting one side to passive avoids the race, as a workaround. */ if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s peer status is %s close connection", realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Transfer accept BGP peer to real (state %s)", peer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_stop (realpeer); /* Transfer file descriptor. */ realpeer->fd = peer->fd; peer->fd = -1; /* Transfer input buffer. */ stream_free (realpeer->ibuf); realpeer->ibuf = peer->ibuf; realpeer->packet_size = peer->packet_size; peer->ibuf = NULL; /* Transfer status. */ realpeer->status = peer->status; bgp_stop (peer); /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; bgp_open_send (peer); if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* remote router-id check. */ if (remote_id.s_addr == 0 || IPV4_CLASS_DE (ntohl (remote_id.s_addr)) || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); return -1; } /* Set remote router-id */ peer->remote_id = remote_id; /* Peer BGP version check. */ if (version != BGP_VERSION_4) { u_int16_t maxver = htons(BGP_VERSION_4); /* XXX this reply may not be correct if version < 4 XXX */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); /* Data must be in network byte order here */ bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, (u_int8_t *) &maxver, 2); return -1; } /* Check neighbor as number. */ if (remote_as != peer->as) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s bad OPEN, remote AS is %u, expected %u", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return -1; } /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST calculate the value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time received in the OPEN message. The Hold Time MUST be either zero or at least three seconds. An implementation may reject connections on the basis of the Hold Time. */ if (holdtime < 3 && holdtime != 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return -1; } /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An implementation MAY adjust the rate at which it sends KEEPALIVE messages as a function of the Hold Time interval. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; if (holdtime < send_holdtime) peer->v_holdtime = holdtime; else peer->v_holdtime = send_holdtime; peer->v_keepalive = peer->v_holdtime / 3; /* Open option part parse. */ if (optlen != 0) { if ((ret = bgp_open_option_parse (peer, optlen, &mp_capability)) < 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return ret; } } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ OPTION parameter len: 0", peer->host); } /* * Assume that the peer supports the locally configured set of * AFI/SAFIs if the peer did not send us any Mulitiprotocol * capabilities, or if 'override-capability' is configured. */ if (! mp_capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; } /* Get sockname. */ bgp_getsockname (peer); BGP_EVENT_ADD (peer, Receive_OPEN_message); peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); return 0; } /* Parse BGP Update packet and make attribute object. */ static int bgp_update_receive (struct peer *peer, bgp_size_t size) { int ret; u_char *end; struct stream *s; struct attr attr; struct attr_extra extra; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; struct bgp_nlri update; struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; /* Status must be Established. */ if (peer->status != Established) { zlog_err ("%s [FSM] Update packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } /* Set initial values. */ memset (&attr, 0, sizeof (struct attr)); memset (&extra, 0, sizeof (struct attr_extra)); memset (&update, 0, sizeof (struct bgp_nlri)); memset (&withdraw, 0, sizeof (struct bgp_nlri)); memset (&mp_update, 0, sizeof (struct bgp_nlri)); memset (&mp_withdraw, 0, sizeof (struct bgp_nlri)); attr.extra = &extra; s = peer->ibuf; end = stream_pnt (s) + size; /* RFC1771 6.3 If the Unfeasible Routes Length or Total Attribute Length is too large (i.e., if Unfeasible Routes Length + Total Attribute Length + 23 exceeds the message Length), then the Error Subcode is set to Malformed Attribute List. */ if (stream_pnt (s) + 2 > end) { zlog_err ("%s [Error] Update packet error" " (packet length is short for unfeasible length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Unfeasible Route Length. */ withdraw_len = stream_getw (s); /* Unfeasible Route Length check. */ if (stream_pnt (s) + withdraw_len > end) { zlog_err ("%s [Error] Update packet error" " (packet unfeasible length overflow %d)", peer->host, withdraw_len); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Unfeasible Route packet format check. */ if (withdraw_len > 0) { ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), withdraw_len); if (ret < 0) return -1; if (BGP_DEBUG (packet, PACKET_RECV)) zlog_debug ("%s [Update:RECV] Unfeasible NLRI received", peer->host); withdraw.afi = AFI_IP; withdraw.safi = SAFI_UNICAST; withdraw.nlri = stream_pnt (s); withdraw.length = withdraw_len; stream_forward_getp (s, withdraw_len); } /* Attribute total length check. */ if (stream_pnt (s) + 2 > end) { zlog_warn ("%s [Error] Packet Error" " (update packet is short for attribute length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Fetch attribute total length. */ attribute_len = stream_getw (s); /* Attribute length check. */ if (stream_pnt (s) + attribute_len > end) { zlog_warn ("%s [Error] Packet Error" " (update packet attribute length overflow %d)", peer->host, attribute_len); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return -1; } /* Certain attribute parsing errors should not be considered bad enough * to reset the session for, most particularly any partial/optional * attributes that have 'tunneled' over speakers that don't understand * them. Instead we withdraw only the prefix concerned. * * Complicates the flow a little though.. */ bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; /* This define morphs the update case into a withdraw when lower levels * have signalled an error condition where this is best. */ #define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL) /* Parse attribute when it exists. */ if (attribute_len) { attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len, &mp_update, &mp_withdraw); if (attr_parse_ret == BGP_ATTR_PARSE_ERROR) { bgp_attr_unintern_sub (&attr); return -1; } } /* Logging the attribute. */ if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW || BGP_DEBUG (update, UPDATE_IN)) { char attrstr[BUFSIZ]; attrstr[0] = '\0'; ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) ? LOG_ERR : LOG_DEBUG; if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) zlog (peer->log, LOG_ERR, "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer->host); if (ret) zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s", peer->host, attrstr); } /* Network Layer Reachability Information. */ update_len = end - stream_pnt (s); if (update_len) { /* Check NLRI packet format and prefix length. */ ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len); if (ret < 0) { bgp_attr_unintern_sub (&attr); return -1; } /* Set NLRI portion to structure. */ update.afi = AFI_IP; update.safi = SAFI_UNICAST; update.nlri = stream_pnt (s); update.length = update_len; stream_forward_getp (s, update_len); } /* NLRI is processed only when the peer is configured specific Address Family and Subsequent Address Family. */ if (peer->afc[AFI_IP][SAFI_UNICAST]) { if (withdraw.length) bgp_nlri_parse (peer, NULL, &withdraw); if (update.length) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update); if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! attribute_len && ! withdraw_len) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP][SAFI_UNICAST]) bgp_clear_stale_route (peer, AFI_IP, SAFI_UNICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Unicast from %s", peer->host); } } if (peer->afc[AFI_IP][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MULTICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP][SAFI_MULTICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP][SAFI_MULTICAST]) bgp_clear_stale_route (peer, AFI_IP, SAFI_MULTICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv4 Multicast from %s", peer->host); } } if (peer->afc[AFI_IP6][SAFI_UNICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_UNICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ SET_FLAG (peer->af_sflags[AFI_IP6][SAFI_UNICAST], PEER_STATUS_EOR_RECEIVED); /* NSF delete stale route */ if (peer->nsf[AFI_IP6][SAFI_UNICAST]) bgp_clear_stale_route (peer, AFI_IP6, SAFI_UNICAST); if (BGP_DEBUG (normal, NORMAL)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Unicast from %s", peer->host); } } if (peer->afc[AFI_IP6][SAFI_MULTICAST]) { if (mp_update.length && mp_update.afi == AFI_IP6 && mp_update.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP6 && mp_withdraw.safi == SAFI_MULTICAST && mp_withdraw.length == 0) { /* End-of-RIB received */ /* NSF delete stale route */ if (peer->nsf[AFI_IP6][SAFI_MULTICAST]) bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST); if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for IPv6 Multicast from %s", peer->host); } } if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) { if (mp_update.length && mp_update.afi == AFI_IP && mp_update.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN) bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw); if (! withdraw_len && mp_withdraw.afi == AFI_IP && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN && mp_withdraw.length == 0) { /* End-of-RIB received */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "rcvd End-of-RIB for VPNv4 Unicast from %s", peer->host); } } /* Everything is done. We unintern temporary structures which interned in bgp_attr_parse(). */ bgp_attr_unintern_sub (&attr); /* If peering is stopped due to some reason, do not generate BGP event. */ if (peer->status != Established) return 0; /* Increment packet counter. */ peer->update_in++; peer->update_time = bgp_clock (); /* Rearm holdtime timer */ BGP_TIMER_OFF (peer->t_holdtime); bgp_timer_set (peer); return 0; } /* Notify message treatment function. */ static void bgp_notify_receive (struct peer *peer, bgp_size_t size) { struct bgp_notify bgp_notify; if (peer->notify.data) { XFREE (MTYPE_TMP, peer->notify.data); peer->notify.data = NULL; peer->notify.length = 0; } bgp_notify.code = stream_getc (peer->ibuf); bgp_notify.subcode = stream_getc (peer->ibuf); bgp_notify.length = size - 2; bgp_notify.data = NULL; /* Preserv notify code and sub code. */ peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; /* For further diagnostic record returned Data. */ if (bgp_notify.length) { peer->notify.length = size - 2; peer->notify.data = XMALLOC (MTYPE_TMP, size - 2); memcpy (peer->notify.data, stream_pnt (peer->ibuf), size - 2); } /* For debug */ { int i; int first = 0; char c[4]; if (bgp_notify.length) { bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); for (i = 0; i < bgp_notify.length; i++) if (first) { sprintf (c, " %02x", stream_getc (peer->ibuf)); strcat (bgp_notify.data, c); } else { first = 1; sprintf (c, "%02x", stream_getc (peer->ibuf)); strcpy (bgp_notify.data, c); } } bgp_notify_print(peer, &bgp_notify, "received"); if (bgp_notify.data) XFREE (MTYPE_TMP, bgp_notify.data); } /* peer count update */ peer->notify_in++; if (peer->status == Established) peer->last_reset = PEER_DOWN_NOTIFY_RECEIVED; /* We have to check for Notify with Unsupported Optional Parameter. in that case we fallback to open without the capability option. But this done in bgp_stop. We just mark it here to avoid changing the fsm tables. */ if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM ) UNSET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); BGP_EVENT_ADD (peer, Receive_NOTIFICATION_message); } /* Keepalive treatment function -- get keepalive send keepalive */ static void bgp_keepalive_receive (struct peer *peer, bgp_size_t size) { if (BGP_DEBUG (keepalive, KEEPALIVE)) zlog_debug ("%s KEEPALIVE rcvd", peer->host); BGP_EVENT_ADD (peer, Receive_KEEPALIVE_message); } /* Route refresh message is received. */ static void bgp_route_refresh_receive (struct peer *peer, bgp_size_t size) { afi_t afi; safi_t safi; struct stream *s; /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) { plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return; } /* Status must be Established. */ if (peer->status != Established) { plog_err (peer->log, "%s [Error] Route refresh packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return; } s = peer->ibuf; /* Parse packet. */ afi = stream_getw (s); /* reserved byte */ stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); /* Check AFI and SAFI. */ if ((afi != AFI_IP && afi != AFI_IP6) || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_MPLS_LABELED_VPN)) { if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", peer->host, afi, safi); } return; } /* Adjust safi code. */ if (safi == SAFI_MPLS_LABELED_VPN) safi = SAFI_MPLS_VPN; if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) { u_char *end; u_char when_to_refresh; u_char orf_type; u_int16_t orf_len; if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) { zlog_info ("%s ORF route refresh length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return; } when_to_refresh = stream_getc (s); end = stream_pnt (s) + (size - 5); while ((stream_pnt (s) + 2) < end) { orf_type = stream_getc (s); orf_len = stream_getw (s); /* orf_len in bounds? */ if ((stream_pnt (s) + orf_len) > end) break; /* XXX: Notify instead?? */ if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { uint8_t *p_pnt = stream_pnt (s); uint8_t *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; int psize; char name[BUFSIZ]; int ret; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s rcvd Prefixlist ORF(%d) length %d", peer->host, orf_type, orf_len); } /* we're going to read at least 1 byte of common ORF header, * and 7 bytes of ORF Address-filter entry from the stream */ if (orf_len < 7) break; /* ORF prefix-list name */ sprintf (name, "%s.%d.%d", peer->host, afi, safi); while (p_pnt < p_end) { /* If the ORF entry is malformed, want to read as much of it * as possible without going beyond the bounds of the entry, * to maximise debug information. */ int ok; memset (&orfp, 0, sizeof (struct orf_prefix)); common = *p_pnt++; /* after ++: p_pnt <= p_end */ if (common & ORF_COMMON_PART_REMOVE_ALL) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd Remove-All pfxlist ORF request", peer->host); prefix_bgp_orf_remove_all (name); break; } ok = ((size_t)(p_end - p_pnt) >= sizeof(u_int32_t)) ; if (ok) { memcpy (&seq, p_pnt, sizeof (u_int32_t)); p_pnt += sizeof (u_int32_t); orfp.seq = ntohl (seq); } else p_pnt = p_end ; if ((ok = (p_pnt < p_end))) orfp.ge = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */ if ((ok = (p_pnt < p_end))) orfp.le = *p_pnt++ ; /* value checked in prefix_bgp_orf_set() */ if ((ok = (p_pnt < p_end))) orfp.p.prefixlen = *p_pnt++ ; orfp.p.family = afi2family (afi); /* afi checked already */ psize = PSIZE (orfp.p.prefixlen); /* 0 if not ok */ if (psize > prefix_blen(&orfp.p)) /* valid for family ? */ { ok = 0 ; psize = prefix_blen(&orfp.p) ; } if (psize > (p_end - p_pnt)) /* valid for packet ? */ { ok = 0 ; psize = p_end - p_pnt ; } if (psize > 0) memcpy (&orfp.p.u.prefix, p_pnt, psize); p_pnt += psize; if (BGP_DEBUG (normal, NORMAL)) { char buf[INET6_BUFSIZ]; zlog_debug ("%s rcvd %s %s seq %u %s/%d ge %d le %d%s", peer->host, (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), orfp.seq, inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, INET6_BUFSIZ), orfp.p.prefixlen, orfp.ge, orfp.le, ok ? "" : " MALFORMED"); } if (ok) ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); if (!ok || (ok && ret != CMD_SUCCESS)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Received misformatted prefixlist ORF." " Remove All pfxlist", peer->host); prefix_bgp_orf_remove_all (name); break; } } peer->orf_plist[afi][safi] = prefix_list_lookup (AFI_ORF_PREFIX, name); } stream_forward_getp (s, orf_len); } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd Refresh %s ORF request", peer->host, when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); if (when_to_refresh == REFRESH_DEFER) return; } /* First update is deferred until ORF or ROUTE-REFRESH is received */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); /* Perform route refreshment to the peer */ bgp_announce_route (peer, afi, safi); } static int bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length) { u_char *end; struct capability_mp_data mpc; struct capability_header *hdr; u_char action; afi_t afi; safi_t safi; end = pnt + length; while (pnt < end) { /* We need at least action, capability code and capability length. */ if (pnt + 3 > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } action = *pnt; hdr = (struct capability_header *)(pnt + 1); /* Action value check. */ if (action != CAPABILITY_ACTION_SET && action != CAPABILITY_ACTION_UNSET) { zlog_info ("%s Capability Action Value error %d", peer->host, action); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s CAPABILITY has action: %d, code: %u, length %u", peer->host, action, hdr->code, hdr->length); /* Capability length check. */ if ((pnt + hdr->length + 3) > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* Fetch structure to the byte stream. */ memcpy (&mpc, pnt + 3, sizeof (struct capability_mp_data)); /* We know MP Capability Code. */ if (hdr->code == CAPABILITY_CODE_MP) { afi = ntohs (mpc.afi); safi = mpc.safi; /* Ignore capability when override-capability is set. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) continue; if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Dynamic Capability MP_EXT afi/safi invalid " "(%u/%u)", peer->host, afi, safi); continue; } /* Address family check. */ if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", ntohs(mpc.afi) , mpc.safi); if (action == CAPABILITY_ACTION_SET) { peer->afc_recv[afi][safi] = 1; if (peer->afc[afi][safi]) { peer->afc_nego[afi][safi] = 1; bgp_announce_route (peer, afi, safi); } } else { peer->afc_recv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; if (peer_active_nego (peer)) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); else BGP_EVENT_ADD (peer, BGP_Stop); } } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, hdr->code); } pnt += hdr->length + 3; } return 0; } /* Dynamic Capability is received. * * This is exported for unit-test purposes */ int bgp_capability_receive (struct peer *peer, bgp_size_t size) { u_char *pnt; /* Fetch pointer. */ pnt = stream_pnt (peer->ibuf); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv CAPABILITY", peer->host); /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) { plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return -1; } /* Status must be Established. */ if (peer->status != Established) { plog_err (peer->log, "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return -1; } /* Parse packet. */ return bgp_capability_msg_parse (peer, pnt, size); } /* BGP read utility function. */ static int bgp_read_packet (struct peer *peer) { int nbytes; int readsize; readsize = peer->packet_size - stream_get_endp (peer->ibuf); /* If size is zero then return. */ if (! readsize) return 0; /* Read packet from fd. */ nbytes = stream_read_try (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occured. */ if (nbytes < 0) { /* Transient error should retry */ if (nbytes == -2) return -1; plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", peer->host, safe_strerror (errno)); if (peer->status == Established) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) { peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); } else peer->last_reset = PEER_DOWN_CLOSE_SESSION; } BGP_EVENT_ADD (peer, TCP_fatal_error); return -1; } /* When read byte is zero : clear bgp peer and return */ if (nbytes == 0) { if (BGP_DEBUG (events, EVENTS)) plog_debug (peer->log, "%s [Event] BGP connection closed fd %d", peer->host, peer->fd); if (peer->status == Established) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_MODE)) { peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); } else peer->last_reset = PEER_DOWN_CLOSE_SESSION; } BGP_EVENT_ADD (peer, TCP_connection_closed); return -1; } /* We read partial packet. */ if (stream_get_endp (peer->ibuf) != peer->packet_size) return -1; return 0; } /* Marker check. */ static int bgp_marker_all_one (struct stream *s, int length) { int i; for (i = 0; i < length; i++) if (s->data[i] != 0xff) return 0; return 1; } /* Recent thread time. On same clock base as bgp_clock (MONOTONIC) but can be time of last context switch to bgp_read thread. */ static time_t bgp_recent_clock (void) { return recent_relative_time().tv_sec; } /* Starting point of packet process function. */ int bgp_read (struct thread *thread) { int ret; u_char type = 0; struct peer *peer; bgp_size_t size; char notify_data_length[2]; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_read = NULL; /* For non-blocking IO check. */ if (peer->status == Connect) { bgp_connect_check (peer); goto done; } else { if (peer->fd < 0) { zlog_err ("bgp_read peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* Read packet header to determine type of the packet */ if (peer->packet_size == 0) peer->packet_size = BGP_HEADER_SIZE; if (stream_get_endp (peer->ibuf) < BGP_HEADER_SIZE) { ret = bgp_read_packet (peer); /* Header read error or partial read packet. */ if (ret < 0) goto done; /* Get size and type. */ stream_forward_getp (peer->ibuf, BGP_MARKER_SIZE); memcpy (notify_data_length, stream_pnt (peer->ibuf), 2); size = stream_getw (peer->ibuf); type = stream_getc (peer->ibuf); if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0) zlog_debug ("%s rcv message type %d, length (excl. header) %d", peer->host, type, size - BGP_HEADER_SIZE); /* Marker check */ if (((type == BGP_MSG_OPEN) || (type == BGP_MSG_KEEPALIVE)) && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) { bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_NOT_SYNC); goto done; } /* BGP type check. */ if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE && type != BGP_MSG_ROUTE_REFRESH_NEW && type != BGP_MSG_ROUTE_REFRESH_OLD && type != BGP_MSG_CAPABILITY) { if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s unknown message type 0x%02x", peer->host, type); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE, &type, 1); goto done; } /* Mimimum packet length check. */ if ((size < BGP_HEADER_SIZE) || (size > BGP_MAX_PACKET_SIZE) || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) { if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s bad message length - %d for %s", peer->host, size, type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) type]); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESLEN, (u_char *) notify_data_length, 2); goto done; } /* Adjust size to message length. */ peer->packet_size = size; } ret = bgp_read_packet (peer); if (ret < 0) goto done; /* Get size and type again. */ size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE); type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2); /* BGP packet dump function. */ bgp_dump_packet (peer, type, peer->ibuf); size = (peer->packet_size - BGP_HEADER_SIZE); /* Read rest of the packet and call each sort of packet routine */ switch (type) { case BGP_MSG_OPEN: peer->open_in++; bgp_open_receive (peer, size); /* XXX return value ignored! */ break; case BGP_MSG_UPDATE: peer->readtime = bgp_recent_clock (); bgp_update_receive (peer, size); break; case BGP_MSG_NOTIFY: bgp_notify_receive (peer, size); break; case BGP_MSG_KEEPALIVE: peer->readtime = bgp_recent_clock (); bgp_keepalive_receive (peer, size); break; case BGP_MSG_ROUTE_REFRESH_NEW: case BGP_MSG_ROUTE_REFRESH_OLD: peer->refresh_in++; bgp_route_refresh_receive (peer, size); break; case BGP_MSG_CAPABILITY: peer->dynamic_cap_in++; bgp_capability_receive (peer, size); break; } /* Clear input buffer. */ peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); done: if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s [Event] Accepting BGP peer delete", peer->host); peer_delete (peer); } return 0; } quagga-0.99.24.1/bgpd/bgp_routemap.c0000644000175000017500000031446512476520570014015 00000000000000/* Route map function of bgpd. Copyright (C) 1998, 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "filter.h" #include "routemap.h" #include "command.h" #include "linklist.h" #include "plist.h" #include "memory.h" #include "log.h" #ifdef HAVE_LIBPCREPOSIX # include #else # ifdef HAVE_GNU_REGEX # include # else # include "regex-gnu.h" # endif /* HAVE_GNU_REGEX */ #endif /* HAVE_LIBPCREPOSIX */ #include "buffer.h" #include "sockunion.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_vty.h" /* Memo of route-map commands. o Cisco route-map match as-path : Done community : Done interface : Not yet ip address : Done ip next-hop : Done ip route-source : Done ip prefix-list : Done ipv6 address : Done ipv6 next-hop : Done ipv6 route-source: (This will not be implemented by bgpd) ipv6 prefix-list : Done length : (This will not be implemented by bgpd) metric : Done route-type : (This will not be implemented by bgpd) tag : (This will not be implemented by bgpd) set as-path prepend : Done as-path tag : Not yet automatic-tag : (This will not be implemented by bgpd) community : Done comm-list : Not yet dampning : Not yet default : (This will not be implemented by bgpd) interface : (This will not be implemented by bgpd) ip default : (This will not be implemented by bgpd) ip next-hop : Done ip precedence : (This will not be implemented by bgpd) ip tos : (This will not be implemented by bgpd) level : (This will not be implemented by bgpd) local-preference : Done metric : Done metric-type : Not yet origin : Done tag : (This will not be implemented by bgpd) weight : Done o Local extensions set ipv6 next-hop global: Done set ipv6 next-hop local : Done set as-path exclude : Done */ /* generic as path object to be shared in multiple rules */ static void * route_aspath_compile (const char *arg) { struct aspath *aspath; aspath = aspath_str2aspath (arg); if (! aspath) return NULL; return aspath; } static void route_aspath_free (void *rule) { struct aspath *aspath = rule; aspath_free (aspath); } /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer received in bgp_info->peer. If it is the same, or if the peer structure received is a peer_group containing it, returns RMAP_MATCH. */ static route_map_result_t route_match_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { union sockunion *su; union sockunion su_def = { .sa.sa_family = AF_INET, .sin.sin_addr.s_addr = INADDR_ANY }; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; if (type == RMAP_BGP) { su = rule; peer = ((struct bgp_info *) object)->peer; if ( ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT) && ! CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_EXPORT) ) return RMAP_NOMATCH; /* If su='0.0.0.0' (command 'match peer local'), and it's a NETWORK, REDISTRIBUTE or DEFAULT_GENERATED route => return RMAP_MATCH */ if (sockunion_same (su, &su_def)) { int ret; if ( CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_NETWORK) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_DEFAULT)) ret = RMAP_MATCH; else ret = RMAP_NOMATCH; return ret; } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (sockunion_same (su, &peer->su)) return RMAP_MATCH; return RMAP_NOMATCH; } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (sockunion_same (su, &peer->su)) return RMAP_MATCH; } return RMAP_NOMATCH; } } return RMAP_NOMATCH; } static void * route_match_peer_compile (const char *arg) { union sockunion *su; int ret; su = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union sockunion)); ret = str2sockunion (strcmp(arg, "local") ? arg : "0.0.0.0", su); if (ret < 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, su); return NULL; } return su; } /* Free route map's compiled `ip address' value. */ static void route_match_peer_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_peer_cmd = { "peer", route_match_peer, route_match_peer_compile, route_match_peer_free }; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_address (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; /* struct prefix_ipv4 match; */ if (type == RMAP_BGP) { alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, prefix) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip address' match statement. `arg' should be access-list name. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_ip_address_cmd = { "ip address", route_match_ip_address, route_match_ip_address_compile, route_match_ip_address_free }; /* `match ip next-hop IP_ADDRESS' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; struct bgp_info *bgp_info; struct prefix_ipv4 p; if (type == RMAP_BGP) { bgp_info = object; p.family = AF_INET; p.prefix = bgp_info->attr->nexthop; p.prefixlen = IPV4_MAX_BITLEN; alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip next-hop' match statement. `arg' is access-list name. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip next-hop matching. */ struct route_map_rule_cmd route_match_ip_next_hop_cmd = { "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; /* `match ip route-source ACCESS-LIST' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_route_source (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; struct bgp_info *bgp_info; struct peer *peer; struct prefix_ipv4 p; if (type == RMAP_BGP) { bgp_info = object; peer = bgp_info->peer; if (! peer || sockunion_family (&peer->su) != AF_INET) return RMAP_NOMATCH; p.family = AF_INET; p.prefix = peer->su.sin.sin_addr; p.prefixlen = IPV4_MAX_BITLEN; alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip route-source' match statement. `arg' is access-list name. */ static void * route_match_ip_route_source_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_route_source_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip route-source matching. */ struct route_map_rule_cmd route_match_ip_route_source_cmd = { "ip route-source", route_match_ip_route_source, route_match_ip_route_source_compile, route_match_ip_route_source_free }; /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type == RMAP_BGP) { plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { "ip address prefix-list", route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; struct bgp_info *bgp_info; struct prefix_ipv4 p; if (type == RMAP_BGP) { bgp_info = object; p.family = AF_INET; p.prefix = bgp_info->attr->nexthop; p.prefixlen = IPV4_MAX_BITLEN; plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, &p) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; /* `match ip route-source prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_route_source_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; struct bgp_info *bgp_info; struct peer *peer; struct prefix_ipv4 p; if (type == RMAP_BGP) { bgp_info = object; peer = bgp_info->peer; if (! peer || sockunion_family (&peer->su) != AF_INET) return RMAP_NOMATCH; p.family = AF_INET; p.prefix = peer->su.sin.sin_addr; p.prefixlen = IPV4_MAX_BITLEN; plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, &p) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_route_source_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_route_source_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { "ip route-source prefix-list", route_match_ip_route_source_prefix_list, route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_free }; /* `match metric METRIC' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *med; struct bgp_info *bgp_info; if (type == RMAP_BGP) { med = rule; bgp_info = object; if (bgp_info->attr->med == *med) return RMAP_MATCH; else return RMAP_NOMATCH; } return RMAP_NOMATCH; } /* Route map `match metric' match statement. `arg' is MED value */ static void * route_match_metric_compile (const char *arg) { u_int32_t *med; char *endptr = NULL; unsigned long tmpval; /* Metric value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmpval = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmpval > UINT32_MAX) return NULL; med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (!med) return med; *med = tmpval; return med; } /* Free route map's compiled `match metric' value. */ static void route_match_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for metric matching. */ struct route_map_rule_cmd route_match_metric_cmd = { "metric", route_match_metric, route_match_metric_compile, route_match_metric_free }; /* `match as-path ASPATH' */ /* Match function for as-path match. I assume given object is */ static route_map_result_t route_match_aspath (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct as_list *as_list; struct bgp_info *bgp_info; if (type == RMAP_BGP) { as_list = as_list_lookup ((char *) rule); if (as_list == NULL) return RMAP_NOMATCH; bgp_info = object; /* Perform match. */ return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Compile function for as-path match. */ static void * route_match_aspath_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Compile function for as-path match. */ static void route_match_aspath_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for aspath matching. */ struct route_map_rule_cmd route_match_aspath_cmd = { "as-path", route_match_aspath, route_match_aspath_compile, route_match_aspath_free }; /* `match community COMMUNIY' */ struct rmap_community { char *name; int exact; }; /* Match function for community match. */ static route_map_result_t route_match_community (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct community_list *list; struct bgp_info *bgp_info; struct rmap_community *rcom; if (type == RMAP_BGP) { bgp_info = object; rcom = rule; list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_MASTER); if (! list) return RMAP_NOMATCH; if (rcom->exact) { if (community_list_exact_match (bgp_info->attr->community, list)) return RMAP_MATCH; } else { if (community_list_match (bgp_info->attr->community, list)) return RMAP_MATCH; } } return RMAP_NOMATCH; } /* Compile function for community match. */ static void * route_match_community_compile (const char *arg) { struct rmap_community *rcom; int len; char *p; rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community)); p = strchr (arg, ' '); if (p) { len = p - arg; rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy (rcom->name, arg, len); rcom->exact = 1; } else { rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); rcom->exact = 0; } return rcom; } /* Compile function for community match. */ static void route_match_community_free (void *rule) { struct rmap_community *rcom = rule; XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name); XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom); } /* Route map commands for community matching. */ struct route_map_rule_cmd route_match_community_cmd = { "community", route_match_community, route_match_community_compile, route_match_community_free }; /* Match function for extcommunity match. */ static route_map_result_t route_match_ecommunity (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct community_list *list; struct bgp_info *bgp_info; if (type == RMAP_BGP) { bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; list = community_list_lookup (bgp_clist, (char *) rule, EXTCOMMUNITY_LIST_MASTER); if (! list) return RMAP_NOMATCH; if (ecommunity_list_match (bgp_info->attr->extra->ecommunity, list)) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Compile function for extcommunity match. */ static void * route_match_ecommunity_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Compile function for extcommunity match. */ static void route_match_ecommunity_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for community matching. */ struct route_map_rule_cmd route_match_ecommunity_cmd = { "extcommunity", route_match_ecommunity, route_match_ecommunity_compile, route_match_ecommunity_free }; /* `match nlri` and `set nlri` are replaced by `address-family ipv4` and `address-family vpnv4'. */ /* `match origin' */ static route_map_result_t route_match_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_char *origin; struct bgp_info *bgp_info; if (type == RMAP_BGP) { origin = rule; bgp_info = object; if (bgp_info->attr->origin == *origin) return RMAP_MATCH; } return RMAP_NOMATCH; } static void * route_match_origin_compile (const char *arg) { u_char *origin; origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); if (strcmp (arg, "igp") == 0) *origin = 0; else if (strcmp (arg, "egp") == 0) *origin = 1; else *origin = 2; return origin; } /* Free route map's compiled `ip address' value. */ static void route_match_origin_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for origin matching. */ struct route_map_rule_cmd route_match_origin_cmd = { "origin", route_match_origin, route_match_origin_compile, route_match_origin_free }; /* match probability { */ static route_map_result_t route_match_probability (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { long r; #if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 r = random(); #else r = (long) rand(); #endif switch (*(unsigned *) rule) { case 0: break; case RAND_MAX: return RMAP_MATCH; default: if (r < *(unsigned *) rule) { return RMAP_MATCH; } } return RMAP_NOMATCH; } static void * route_match_probability_compile (const char *arg) { unsigned *lobule; unsigned perc; #if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 srandom (time (NULL)); #else srand (time (NULL)); #endif perc = atoi (arg); lobule = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); switch (perc) { case 0: *lobule = 0; break; case 100: *lobule = RAND_MAX; break; default: *lobule = RAND_MAX / 100 * perc; } return lobule; } static void route_match_probability_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_probability_cmd = { "probability", route_match_probability, route_match_probability_compile, route_match_probability_free }; /* } */ /* `set ip next-hop IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ struct rmap_ip_nexthop_set { struct in_addr *address; int peer_address; }; static route_map_result_t route_set_ip_nexthop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_ip_nexthop_set *rins = rule; struct bgp_info *bgp_info; struct peer *peer; if (type == RMAP_BGP) { bgp_info = object; peer = bgp_info->peer; if (rins->peer_address) { if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET) { bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_remote); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); } else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) && peer->su_local && sockunion_family (peer->su_local) == AF_INET) { bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_local); bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); } } else { /* Set next hop value. */ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); bgp_info->attr->nexthop = *rins->address; } } return RMAP_OKAY; } /* Route map `ip nexthop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ip_nexthop_compile (const char *arg) { struct rmap_ip_nexthop_set *rins; struct in_addr *address = NULL; int peer_address = 0; int ret; if (strcmp (arg, "peer-address") == 0) peer_address = 1; else { address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); ret = inet_aton (arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } } rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_ip_nexthop_set)); rins->address = address; rins->peer_address = peer_address; return rins; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_ip_nexthop_free (void *rule) { struct rmap_ip_nexthop_set *rins = rule; if (rins->address) XFREE (MTYPE_ROUTE_MAP_COMPILED, rins->address); XFREE (MTYPE_ROUTE_MAP_COMPILED, rins); } /* Route map commands for ip nexthop set. */ struct route_map_rule_cmd route_set_ip_nexthop_cmd = { "ip next-hop", route_set_ip_nexthop, route_set_ip_nexthop_compile, route_set_ip_nexthop_free }; /* `set local-preference LOCAL_PREF' */ /* Set local preference. */ static route_map_result_t route_set_local_pref (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *local_pref; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ local_pref = rule; bgp_info = object; /* Set local preference value. */ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); bgp_info->attr->local_pref = *local_pref; } return RMAP_OKAY; } /* set local preference compilation. */ static void * route_set_local_pref_compile (const char *arg) { unsigned long tmp; u_int32_t *local_pref; char *endptr = NULL; /* Local preference value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmp = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (!local_pref) return local_pref; *local_pref = tmp; return local_pref; } /* Free route map's local preference value. */ static void route_set_local_pref_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_local_pref_cmd = { "local-preference", route_set_local_pref, route_set_local_pref_compile, route_set_local_pref_free, }; /* `set weight WEIGHT' */ /* Set weight. */ static route_map_result_t route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_int32_t *weight; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ weight = rule; bgp_info = object; /* Set weight value. */ if (*weight) (bgp_attr_extra_get (bgp_info->attr))->weight = *weight; else if (bgp_info->attr->extra) bgp_info->attr->extra->weight = 0; } return RMAP_OKAY; } /* set local preference compilation. */ static void * route_set_weight_compile (const char *arg) { unsigned long tmp; u_int32_t *weight; char *endptr = NULL; /* Local preference value shoud be integer. */ if (! all_digit (arg)) return NULL; errno = 0; tmp = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || tmp > UINT32_MAX) return NULL; weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); if (weight == NULL) return weight; *weight = tmp; return weight; } /* Free route map's local preference value. */ static void route_set_weight_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set local preference rule structure. */ struct route_map_rule_cmd route_set_weight_cmd = { "weight", route_set_weight, route_set_weight_compile, route_set_weight_free, }; /* `set metric METRIC' */ /* Set metric to attribute. */ static route_map_result_t route_set_metric (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { char *metric; u_int32_t metric_val; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ metric = rule; bgp_info = object; if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) bgp_info->attr->med = 0; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (all_digit (metric)) { metric_val = strtoul (metric, (char **)NULL, 10); bgp_info->attr->med = metric_val; } else { metric_val = strtoul (metric+1, (char **)NULL, 10); if (strncmp (metric, "+", 1) == 0) { if (bgp_info->attr->med/2 + metric_val/2 > BGP_MED_MAX/2) bgp_info->attr->med = BGP_MED_MAX - 1; else bgp_info->attr->med += metric_val; } else if (strncmp (metric, "-", 1) == 0) { if (bgp_info->attr->med <= metric_val) bgp_info->attr->med = 0; else bgp_info->attr->med -= metric_val; } } } return RMAP_OKAY; } /* set metric compilation. */ static void * route_set_metric_compile (const char *arg) { unsigned long larg; char *endptr = NULL; if (all_digit (arg)) { /* set metric value check*/ errno = 0; larg = strtoul (arg, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; } else { /* set metric +/-value check */ if ((strncmp (arg, "+", 1) != 0 && strncmp (arg, "-", 1) != 0) || (! all_digit (arg+1))) return NULL; errno = 0; larg = strtoul (arg+1, &endptr, 10); if (*endptr != '\0' || errno || larg > UINT32_MAX) return NULL; } return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `set metric' value. */ static void route_set_metric_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set metric rule structure. */ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_set_metric_compile, route_set_metric_free, }; /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ static route_map_result_t route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct aspath *aspath; struct aspath *new; struct bgp_info *binfo; if (type == RMAP_BGP) { binfo = object; if (binfo->attr->aspath->refcnt) new = aspath_dup (binfo->attr->aspath); else new = binfo->attr->aspath; if ((uintptr_t)rule > 10) { aspath = rule; aspath_prepend (aspath, new); } else { as_t as = aspath_leftmost(new); if (!as) as = binfo->peer->as; new = aspath_add_seq_n (new, as, (uintptr_t) rule); } binfo->attr->aspath = new; } return RMAP_OKAY; } static void * route_set_aspath_prepend_compile (const char *arg) { unsigned int num; if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) return (void*)(uintptr_t)num; return route_aspath_compile(arg); } static void route_set_aspath_prepend_free (void *rule) { if ((uintptr_t)rule > 10) route_aspath_free(rule); } /* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", route_set_aspath_prepend, route_set_aspath_prepend_compile, route_set_aspath_prepend_free, }; /* `set as-path exclude ASn' */ /* For ASN exclude mechanism. * Iterate over ASns requested and filter them from the given AS_PATH one by one. * Make a deep copy of existing AS_PATH, but for the first ASn only. */ static route_map_result_t route_set_aspath_exclude (void *rule, struct prefix *dummy, route_map_object_t type, void *object) { struct aspath * new_path, * exclude_path; struct bgp_info *binfo; if (type == RMAP_BGP) { exclude_path = rule; binfo = object; if (binfo->attr->aspath->refcnt) new_path = aspath_dup (binfo->attr->aspath); else new_path = binfo->attr->aspath; binfo->attr->aspath = aspath_filter_exclude (new_path, exclude_path); } return RMAP_OKAY; } /* Set ASn exlude rule structure. */ struct route_map_rule_cmd route_set_aspath_exclude_cmd = { "as-path exclude", route_set_aspath_exclude, route_aspath_compile, route_aspath_free, }; /* `set community COMMUNITY' */ struct rmap_com_set { struct community *com; int additive; int none; }; /* For community set mechanism. */ static route_map_result_t route_set_community (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct rmap_com_set *rcs; struct bgp_info *binfo; struct attr *attr; struct community *new = NULL; struct community *old; struct community *merge; if (type == RMAP_BGP) { rcs = rule; binfo = object; attr = binfo->attr; old = attr->community; /* "none" case. */ if (rcs->none) { attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); attr->community = NULL; /* See the longer comment down below. */ if (old && old->refcnt == 0) community_free(old); return RMAP_OKAY; } /* "additive" case. */ if (rcs->additive && old) { merge = community_merge (community_dup (old), rcs->com); /* HACK: if the old community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) community_free (old); new = community_uniq_sort (merge); community_free (merge); } else new = community_dup (rcs->com); /* will be interned by caller if required */ attr->community = new; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_community_compile (const char *arg) { struct rmap_com_set *rcs; struct community *com = NULL; char *sp; int additive = 0; int none = 0; if (strcmp (arg, "none") == 0) none = 1; else { sp = strstr (arg, "additive"); if (sp && sp > arg) { /* "additive" keyworkd is included. */ additive = 1; *(sp - 1) = '\0'; } com = community_str2com (arg); if (additive) *(sp - 1) = ' '; if (! com) return NULL; } rcs = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set)); rcs->com = com; rcs->additive = additive; rcs->none = none; return rcs; } /* Free function for set community. */ static void route_set_community_free (void *rule) { struct rmap_com_set *rcs = rule; if (rcs->com) community_free (rcs->com); XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_community_cmd = { "community", route_set_community, route_set_community_compile, route_set_community_free, }; /* `set comm-list (<1-99>|<100-500>|WORD) delete' */ /* For community set mechanism. */ static route_map_result_t route_set_community_delete (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct community_list *list; struct community *merge; struct community *new; struct community *old; struct bgp_info *binfo; if (type == RMAP_BGP) { if (! rule) return RMAP_OKAY; binfo = object; list = community_list_lookup (bgp_clist, rule, COMMUNITY_LIST_MASTER); old = binfo->attr->community; if (list && old) { merge = community_list_match_delete (community_dup (old), list); new = community_uniq_sort (merge); community_free (merge); /* HACK: if the old community is not intern'd, * we should free it here, or all reference to it may be lost. * Really need to cleanup attribute caching sometime. */ if (old->refcnt == 0) community_free (old); if (new->size == 0) { binfo->attr->community = NULL; binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); community_free (new); } else { binfo->attr->community = new; binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } } } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_community_delete_compile (const char *arg) { char *p; char *str; int len; p = strchr (arg, ' '); if (p) { len = p - arg; str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy (str, arg, len); } else str = NULL; return str; } /* Free function for set community. */ static void route_set_community_delete_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_community_delete_cmd = { "comm-list", route_set_community_delete, route_set_community_delete_compile, route_set_community_delete_free, }; /* `set extcommunity rt COMMUNITY' */ /* For community set mechanism. Used by _rt and _soo. */ static route_map_result_t route_set_ecommunity (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct ecommunity *ecom; struct ecommunity *new_ecom; struct ecommunity *old_ecom; struct bgp_info *bgp_info; if (type == RMAP_BGP) { ecom = rule; bgp_info = object; if (! ecom) return RMAP_OKAY; /* We assume additive for Extended Community. */ old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; if (old_ecom) { new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); /* old_ecom->refcnt = 1 => owned elsewhere, e.g. bgp_update_receive() * ->refcnt = 0 => set by a previous route-map statement */ if (!old_ecom->refcnt) ecommunity_free (&old_ecom); } else new_ecom = ecommunity_dup (ecom); /* will be intern()'d or attr_flush()'d by bgp_update_main() */ bgp_info->attr->extra->ecommunity = new_ecom; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); } return RMAP_OKAY; } /* Compile function for set community. */ static void * route_set_ecommunity_rt_compile (const char *arg) { struct ecommunity *ecom; ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0); if (! ecom) return NULL; return ecommunity_intern (ecom); } /* Free function for set community. Used by _rt and _soo */ static void route_set_ecommunity_free (void *rule) { struct ecommunity *ecom = rule; ecommunity_unintern (&ecom); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_rt_cmd = { "extcommunity rt", route_set_ecommunity, route_set_ecommunity_rt_compile, route_set_ecommunity_free, }; /* `set extcommunity soo COMMUNITY' */ /* Compile function for set community. */ static void * route_set_ecommunity_soo_compile (const char *arg) { struct ecommunity *ecom; ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0); if (! ecom) return NULL; return ecommunity_intern (ecom); } /* Set community rule structure. */ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = { "extcommunity soo", route_set_ecommunity, route_set_ecommunity_soo_compile, route_set_ecommunity_free, }; /* `set origin ORIGIN' */ /* For origin set. */ static route_map_result_t route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { u_char *origin; struct bgp_info *bgp_info; if (type == RMAP_BGP) { origin = rule; bgp_info = object; bgp_info->attr->origin = *origin; } return RMAP_OKAY; } /* Compile function for origin set. */ static void * route_set_origin_compile (const char *arg) { u_char *origin; origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char)); if (strcmp (arg, "igp") == 0) *origin = 0; else if (strcmp (arg, "egp") == 0) *origin = 1; else *origin = 2; return origin; } /* Compile function for origin set. */ static void route_set_origin_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set origin rule structure. */ struct route_map_rule_cmd route_set_origin_cmd = { "origin", route_set_origin, route_set_origin_compile, route_set_origin_free, }; /* `set atomic-aggregate' */ /* For atomic aggregate set. */ static route_map_result_t route_set_atomic_aggregate (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct bgp_info *bgp_info; if (type == RMAP_BGP) { bgp_info = object; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); } return RMAP_OKAY; } /* Compile function for atomic aggregate. */ static void * route_set_atomic_aggregate_compile (const char *arg) { return (void *)1; } /* Compile function for atomic aggregate. */ static void route_set_atomic_aggregate_free (void *rule) { return; } /* Set atomic aggregate rule structure. */ struct route_map_rule_cmd route_set_atomic_aggregate_cmd = { "atomic-aggregate", route_set_atomic_aggregate, route_set_atomic_aggregate_compile, route_set_atomic_aggregate_free, }; /* `set aggregator as AS A.B.C.D' */ struct aggregator { as_t as; struct in_addr address; }; static route_map_result_t route_set_aggregator_as (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct bgp_info *bgp_info; struct aggregator *aggregator; struct attr_extra *ae; if (type == RMAP_BGP) { bgp_info = object; aggregator = rule; ae = bgp_attr_extra_get (bgp_info->attr); ae->aggregator_as = aggregator->as; ae->aggregator_addr = aggregator->address; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); } return RMAP_OKAY; } static void * route_set_aggregator_as_compile (const char *arg) { struct aggregator *aggregator; char as[10]; char address[20]; aggregator = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator)); sscanf (arg, "%s %s", as, address); aggregator->as = strtoul (as, NULL, 10); inet_aton (address, &aggregator->address); return aggregator; } static void route_set_aggregator_as_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_set_aggregator_as_cmd = { "aggregator as", route_set_aggregator_as, route_set_aggregator_as_compile, route_set_aggregator_as_free, }; #ifdef HAVE_IPV6 /* `match ipv6 address IP_ACCESS_LIST' */ static route_map_result_t route_match_ipv6_address (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; if (type == RMAP_BGP) { alist = access_list_lookup (AFI_IP6, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, prefix) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ipv6_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ipv6_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ struct route_map_rule_cmd route_match_ipv6_address_cmd = { "ipv6 address", route_match_ipv6_address, route_match_ipv6_address_compile, route_match_ipv6_address_free }; /* `match ipv6 next-hop IP_ADDRESS' */ static route_map_result_t route_match_ipv6_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr *addr = rule; struct bgp_info *bgp_info; if (type == RMAP_BGP) { bgp_info = object; if (!bgp_info->attr->extra) return RMAP_NOMATCH; if (IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_global, addr)) return RMAP_MATCH; if (bgp_info->attr->extra->mp_nexthop_len == 32 && IPV6_ADDR_SAME (&bgp_info->attr->extra->mp_nexthop_local, addr)) return RMAP_MATCH; return RMAP_NOMATCH; } return RMAP_NOMATCH; } static void * route_match_ipv6_next_hop_compile (const char *arg) { struct in6_addr *address; int ret; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); ret = inet_pton (AF_INET6, arg, address); if (!ret) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } static void route_match_ipv6_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { "ipv6 next-hop", route_match_ipv6_next_hop, route_match_ipv6_next_hop_compile, route_match_ipv6_next_hop_free }; /* `match ipv6 address prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type == RMAP_BGP) { plist = prefix_list_lookup (AFI_IP6, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ipv6_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ipv6_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = { "ipv6 address prefix-list", route_match_ipv6_address_prefix_list, route_match_ipv6_address_prefix_list_compile, route_match_ipv6_address_prefix_list_free }; /* `set ipv6 nexthop global IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr *address; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ address = rule; bgp_info = object; /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = *address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len == 0) bgp_info->attr->extra->mp_nexthop_len = 16; } return RMAP_OKAY; } /* Route map `ip next-hop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_global_compile (const char *arg) { int ret; struct in6_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); ret = inet_pton (AF_INET6, arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } /* Free route map's compiled `ip next-hop' value. */ static void route_set_ipv6_nexthop_global_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = { "ipv6 next-hop global", route_set_ipv6_nexthop_global, route_set_ipv6_nexthop_global_compile, route_set_ipv6_nexthop_global_free }; /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr *address; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ address = rule; bgp_info = object; /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = *address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len != 32) bgp_info->attr->extra->mp_nexthop_len = 32; } return RMAP_OKAY; } /* Route map `ip nexthop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_local_compile (const char *arg) { int ret; struct in6_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr)); ret = inet_pton (AF_INET6, arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } /* Free route map's compiled `ip nexthop' value. */ static void route_set_ipv6_nexthop_local_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = { "ipv6 next-hop local", route_set_ipv6_nexthop_local, route_set_ipv6_nexthop_local_compile, route_set_ipv6_nexthop_local_free }; /* `set ipv6 nexthop peer-address' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ static route_map_result_t route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in6_addr peer_address; struct bgp_info *bgp_info; struct peer *peer; char peer_addr_buf[INET6_ADDRSTRLEN]; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ bgp_info = object; peer = bgp_info->peer; if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) && peer->su_remote && sockunion_family (peer->su_remote) == AF_INET6) { inet_pton (AF_INET6, sockunion2str (peer->su_remote, peer_addr_buf, INET6_ADDRSTRLEN), &peer_address); } else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT) && peer->su_local && sockunion_family (peer->su_local) == AF_INET6) { inet_pton (AF_INET, sockunion2str (peer->su_local, peer_addr_buf, INET6_ADDRSTRLEN), &peer_address); } if (IN6_IS_ADDR_LINKLOCAL(&peer_address)) { /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len != 32) bgp_info->attr->extra->mp_nexthop_len = 32; } else { /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address; /* Set nexthop length. */ if (bgp_info->attr->extra->mp_nexthop_len == 0) bgp_info->attr->extra->mp_nexthop_len = 16; } } return RMAP_OKAY; } /* Route map `ip next-hop' compile function. Given string is converted to struct in_addr structure. */ static void * route_set_ipv6_nexthop_peer_compile (const char *arg) { int *rins = NULL; rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); *rins = 1; return rins; } /* Free route map's compiled `ip next-hop' value. */ static void route_set_ipv6_nexthop_peer_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = { "ipv6 next-hop peer-address", route_set_ipv6_nexthop_peer, route_set_ipv6_nexthop_peer_compile, route_set_ipv6_nexthop_peer_free }; #endif /* HAVE_IPV6 */ /* `set vpnv4 nexthop A.B.C.D' */ static route_map_result_t route_set_vpnv4_nexthop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in_addr *address; struct bgp_info *bgp_info; if (type == RMAP_BGP) { /* Fetch routemap's rule information. */ address = rule; bgp_info = object; /* Set next hop value. */ (bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global_in = *address; } return RMAP_OKAY; } static void * route_set_vpnv4_nexthop_compile (const char *arg) { int ret; struct in_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); ret = inet_aton (arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } static void route_set_vpnv4_nexthop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip nexthop set. */ struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd = { "vpnv4 next-hop", route_set_vpnv4_nexthop, route_set_vpnv4_nexthop_compile, route_set_vpnv4_nexthop_free }; /* `set originator-id' */ /* For origin set. */ static route_map_result_t route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct in_addr *address; struct bgp_info *bgp_info; if (type == RMAP_BGP) { address = rule; bgp_info = object; bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); (bgp_attr_extra_get (bgp_info->attr))->originator_id = *address; } return RMAP_OKAY; } /* Compile function for originator-id set. */ static void * route_set_originator_id_compile (const char *arg) { int ret; struct in_addr *address; address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr)); ret = inet_aton (arg, address); if (ret == 0) { XFREE (MTYPE_ROUTE_MAP_COMPILED, address); return NULL; } return address; } /* Compile function for originator_id set. */ static void route_set_originator_id_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set originator-id rule structure. */ struct route_map_rule_cmd route_set_originator_id_cmd = { "originator-id", route_set_originator_id, route_set_originator_id_compile, route_set_originator_id_free, }; /* Add bgp route map rule. */ static int bgp_route_match_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete bgp route map rule. */ static int bgp_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add bgp route map rule. */ static int bgp_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete bgp route map rule. */ static int bgp_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Hook function for updating route_map assignment. */ static void bgp_route_map_update (const char *unused) { int i; afi_t afi; safi_t safi; int direct; struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; struct bgp_node *bn; struct bgp_static *bgp_static; /* For neighbor route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (direct = RMAP_IN; direct < RMAP_MAX; direct++) { if (filter->map[direct].name) filter->map[direct].map = route_map_lookup_by_name (filter->map[direct].name); else filter->map[direct].map = NULL; } if (filter->usmap.name) filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); else filter->usmap.map = NULL; } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &group->conf->filter[afi][safi]; for (direct = RMAP_IN; direct < RMAP_MAX; direct++) { if (filter->map[direct].name) filter->map[direct].map = route_map_lookup_by_name (filter->map[direct].name); else filter->map[direct].map = NULL; } if (filter->usmap.name) filter->usmap.map = route_map_lookup_by_name (filter->usmap.name); else filter->usmap.map = NULL; } } } /* For default-originate route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (peer->default_rmap[afi][safi].name) peer->default_rmap[afi][safi].map = route_map_lookup_by_name (peer->default_rmap[afi][safi].name); else peer->default_rmap[afi][safi].map = NULL; } } } /* For network route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (bn = bgp_table_top (bgp->route[afi][safi]); bn; bn = bgp_route_next (bn)) if ((bgp_static = bn->info) != NULL) { if (bgp_static->rmap.name) bgp_static->rmap.map = route_map_lookup_by_name (bgp_static->rmap.name); else bgp_static->rmap.map = NULL; } } /* For redistribute route-map updates. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name) bgp->rmap[ZEBRA_FAMILY_IPV4][i].map = route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name); #ifdef HAVE_IPV6 if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name) bgp->rmap[ZEBRA_FAMILY_IPV6][i].map = route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name); #endif /* HAVE_IPV6 */ } } } DEFUN (match_peer, match_peer_cmd, "match peer (A.B.C.D|X:X::X:X)", MATCH_STR "Match peer address\n" "IPv6 address of peer\n" "IP address of peer\n") { return bgp_route_match_add (vty, vty->index, "peer", argv[0]); } DEFUN (match_peer_local, match_peer_local_cmd, "match peer local", MATCH_STR "Match peer address\n" "Static or Redistributed routes\n") { return bgp_route_match_add (vty, vty->index, "peer", "local"); } DEFUN (no_match_peer, no_match_peer_cmd, "no match peer", NO_STR MATCH_STR "Match peer address\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "peer", NULL); return bgp_route_match_delete (vty, vty->index, "peer", argv[0]); } ALIAS (no_match_peer, no_match_peer_val_cmd, "no match peer (A.B.C.D|X:X::X:X)", NO_STR MATCH_STR "Match peer address\n" "IPv6 address of peer\n" "IP address of peer\n") ALIAS (no_match_peer, no_match_peer_local_cmd, "no match peer local", NO_STR MATCH_STR "Match peer address\n" "Static or Redistributed routes\n") DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return bgp_route_match_add (vty, vty->index, "ip address", argv[0]); } DEFUN (no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip address", NULL); return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]); } ALIAS (no_match_ip_address, no_match_ip_address_val_cmd, "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_match_ip_next_hop, no_match_ip_next_hop_cmd, "no match ip next-hop", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL); return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") /* match probability { */ DEFUN (match_probability, match_probability_cmd, "match probability <0-100>", MATCH_STR "Match portion of routes defined by percentage value\n" "Percentage of routes\n") { return bgp_route_match_add (vty, vty->index, "probability", argv[0]); } DEFUN (no_match_probability, no_match_probability_cmd, "no match probability", NO_STR MATCH_STR "Match portion of routes defined by percentage value\n") { return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL); } ALIAS (no_match_probability, no_match_probability_val_cmd, "no match probability <1-99>", NO_STR MATCH_STR "Match portion of routes defined by percentage value\n" "Percentage of routes\n") /* } */ DEFUN (match_ip_route_source, match_ip_route_source_cmd, "match ip route-source (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match advertising source address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP standard access-list name\n") { return bgp_route_match_add (vty, vty->index, "ip route-source", argv[0]); } DEFUN (no_match_ip_route_source, no_match_ip_route_source_cmd, "no match ip route-source", NO_STR MATCH_STR IP_STR "Match advertising source address of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip route-source", NULL); return bgp_route_match_delete (vty, vty->index, "ip route-source", argv[0]); } ALIAS (no_match_ip_route_source, no_match_ip_route_source_val_cmd, "no match ip route-source (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match advertising source address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP standard access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD", MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); } DEFUN (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); } ALIAS (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD", MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); } DEFUN (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); } ALIAS (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_route_source_prefix_list, match_ip_route_source_prefix_list_cmd, "match ip route-source prefix-list WORD", MATCH_STR IP_STR "Match advertising source address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_add (vty, vty->index, "ip route-source prefix-list", argv[0]); } DEFUN (no_match_ip_route_source_prefix_list, no_match_ip_route_source_prefix_list_cmd, "no match ip route-source prefix-list", NO_STR MATCH_STR IP_STR "Match advertising source address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", NULL); return bgp_route_match_delete (vty, vty->index, "ip route-source prefix-list", argv[0]); } ALIAS (no_match_ip_route_source_prefix_list, no_match_ip_route_source_prefix_list_val_cmd, "no match ip route-source prefix-list WORD", NO_STR MATCH_STR IP_STR "Match advertising source address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_metric, match_metric_cmd, "match metric <0-4294967295>", MATCH_STR "Match metric of route\n" "Metric value\n") { return bgp_route_match_add (vty, vty->index, "metric", argv[0]); } DEFUN (no_match_metric, no_match_metric_cmd, "no match metric", NO_STR MATCH_STR "Match metric of route\n") { if (argc == 0) return bgp_route_match_delete (vty, vty->index, "metric", NULL); return bgp_route_match_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_match_metric, no_match_metric_val_cmd, "no match metric <0-4294967295>", NO_STR MATCH_STR "Match metric of route\n" "Metric value\n") DEFUN (match_community, match_community_cmd, "match community (<1-99>|<100-500>|WORD)", MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") { return bgp_route_match_add (vty, vty->index, "community", argv[0]); } DEFUN (match_community_exact, match_community_exact_cmd, "match community (<1-99>|<100-500>|WORD) exact-match", MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") { int ret; char *argstr; argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, strlen (argv[0]) + strlen ("exact-match") + 2); sprintf (argstr, "%s exact-match", argv[0]); ret = bgp_route_match_add (vty, vty->index, "community", argstr); XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); return ret; } DEFUN (no_match_community, no_match_community_cmd, "no match community", NO_STR MATCH_STR "Match BGP community list\n") { return bgp_route_match_delete (vty, vty->index, "community", NULL); } ALIAS (no_match_community, no_match_community_val_cmd, "no match community (<1-99>|<100-500>|WORD)", NO_STR MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n") ALIAS (no_match_community, no_match_community_exact_cmd, "no match community (<1-99>|<100-500>|WORD) exact-match", NO_STR MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" "Community-list number (expanded)\n" "Community-list name\n" "Do exact matching of communities\n") DEFUN (match_ecommunity, match_ecommunity_cmd, "match extcommunity (<1-99>|<100-500>|WORD)", MATCH_STR "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") { return bgp_route_match_add (vty, vty->index, "extcommunity", argv[0]); } DEFUN (no_match_ecommunity, no_match_ecommunity_cmd, "no match extcommunity", NO_STR MATCH_STR "Match BGP/VPN extended community list\n") { return bgp_route_match_delete (vty, vty->index, "extcommunity", NULL); } ALIAS (no_match_ecommunity, no_match_ecommunity_val_cmd, "no match extcommunity (<1-99>|<100-500>|WORD)", NO_STR MATCH_STR "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" "Extended community-list number (expanded)\n" "Extended community-list name\n") DEFUN (match_aspath, match_aspath_cmd, "match as-path WORD", MATCH_STR "Match BGP AS path list\n" "AS path access-list name\n") { return bgp_route_match_add (vty, vty->index, "as-path", argv[0]); } DEFUN (no_match_aspath, no_match_aspath_cmd, "no match as-path", NO_STR MATCH_STR "Match BGP AS path list\n") { return bgp_route_match_delete (vty, vty->index, "as-path", NULL); } ALIAS (no_match_aspath, no_match_aspath_val_cmd, "no match as-path WORD", NO_STR MATCH_STR "Match BGP AS path list\n" "AS path access-list name\n") DEFUN (match_origin, match_origin_cmd, "match origin (egp|igp|incomplete)", MATCH_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") { if (strncmp (argv[0], "igp", 2) == 0) return bgp_route_match_add (vty, vty->index, "origin", "igp"); if (strncmp (argv[0], "egp", 1) == 0) return bgp_route_match_add (vty, vty->index, "origin", "egp"); if (strncmp (argv[0], "incomplete", 2) == 0) return bgp_route_match_add (vty, vty->index, "origin", "incomplete"); return CMD_WARNING; } DEFUN (no_match_origin, no_match_origin_cmd, "no match origin", NO_STR MATCH_STR "BGP origin code\n") { return bgp_route_match_delete (vty, vty->index, "origin", NULL); } ALIAS (no_match_origin, no_match_origin_val_cmd, "no match origin (egp|igp|incomplete)", NO_STR MATCH_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFUN (set_ip_nexthop, set_ip_nexthop_cmd, "set ip next-hop A.B.C.D", SET_STR IP_STR "Next hop address\n" "IP address of next hop\n") { union sockunion su; int ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (set_ip_nexthop_peer, set_ip_nexthop_peer_cmd, "set ip next-hop peer-address", SET_STR IP_STR "Next hop address\n" "Use peer address (for BGP only)\n") { return bgp_route_set_add (vty, vty->index, "ip next-hop", "peer-address"); } DEFUN_DEPRECATED (no_set_ip_nexthop_peer, no_set_ip_nexthop_peer_cmd, "no set ip next-hop peer-address", NO_STR SET_STR IP_STR "Next hop address\n" "Use peer address (for BGP only)\n") { return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); } DEFUN (no_set_ip_nexthop, no_set_ip_nexthop_cmd, "no set ip next-hop", NO_STR SET_STR "Next hop address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL); return bgp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_set_ip_nexthop, no_set_ip_nexthop_val_cmd, "no set ip next-hop A.B.C.D", NO_STR SET_STR IP_STR "Next hop address\n" "IP address of next hop\n") DEFUN (set_metric, set_metric_cmd, "set metric <0-4294967295>", SET_STR "Metric value for destination routing protocol\n" "Metric value\n") { return bgp_route_set_add (vty, vty->index, "metric", argv[0]); } ALIAS (set_metric, set_metric_addsub_cmd, "set metric <+/-metric>", SET_STR "Metric value for destination routing protocol\n" "Add or subtract metric\n") DEFUN (no_set_metric, no_set_metric_cmd, "no set metric", NO_STR SET_STR "Metric value for destination routing protocol\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "metric", NULL); return bgp_route_set_delete (vty, vty->index, "metric", argv[0]); } ALIAS (no_set_metric, no_set_metric_val_cmd, "no set metric <0-4294967295>", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n") DEFUN (set_local_pref, set_local_pref_cmd, "set local-preference <0-4294967295>", SET_STR "BGP local preference path attribute\n" "Preference value\n") { return bgp_route_set_add (vty, vty->index, "local-preference", argv[0]); } DEFUN (no_set_local_pref, no_set_local_pref_cmd, "no set local-preference", NO_STR SET_STR "BGP local preference path attribute\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "local-preference", NULL); return bgp_route_set_delete (vty, vty->index, "local-preference", argv[0]); } ALIAS (no_set_local_pref, no_set_local_pref_val_cmd, "no set local-preference <0-4294967295>", NO_STR SET_STR "BGP local preference path attribute\n" "Preference value\n") DEFUN (set_weight, set_weight_cmd, "set weight <0-4294967295>", SET_STR "BGP weight for routing table\n" "Weight value\n") { return bgp_route_set_add (vty, vty->index, "weight", argv[0]); } DEFUN (no_set_weight, no_set_weight_cmd, "no set weight", NO_STR SET_STR "BGP weight for routing table\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "weight", NULL); return bgp_route_set_delete (vty, vty->index, "weight", argv[0]); } ALIAS (no_set_weight, no_set_weight_val_cmd, "no set weight <0-4294967295>", NO_STR SET_STR "BGP weight for routing table\n" "Weight value\n") DEFUN (set_aspath_prepend, set_aspath_prepend_cmd, "set as-path prepend ." CMD_AS_RANGE, SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "as-path prepend", str); XFREE (MTYPE_TMP, str); return ret; } ALIAS (set_aspath_prepend, set_aspath_prepend_lastas_cmd, "set as-path prepend (last-as) <1-10>", SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "Use the peer's AS-number\n" "Number of times to insert"); DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n") { int ret; char *str; if (argc == 0) return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL); str = argv_concat (argv, argc, 0); ret = bgp_route_set_delete (vty, vty->index, "as-path prepend", str); XFREE (MTYPE_TMP, str); return ret; } ALIAS (no_set_aspath_prepend, no_set_aspath_prepend_val_cmd, "no set as-path prepend ." CMD_AS_RANGE, NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") DEFUN (set_aspath_exclude, set_aspath_exclude_cmd, "set as-path exclude ." CMD_AS_RANGE, SET_STR "Transform BGP AS-path attribute\n" "Exclude from the as-path\n" "AS number\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "as-path exclude", str); XFREE (MTYPE_TMP, str); return ret; } DEFUN (no_set_aspath_exclude, no_set_aspath_exclude_cmd, "no set as-path exclude", NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n") { int ret; char *str; if (argc == 0) return bgp_route_set_delete (vty, vty->index, "as-path exclude", NULL); str = argv_concat (argv, argc, 0); ret = bgp_route_set_delete (vty, vty->index, "as-path exclude", str); XFREE (MTYPE_TMP, str); return ret; } ALIAS (no_set_aspath_exclude, no_set_aspath_exclude_val_cmd, "no set as-path exclude ." CMD_AS_RANGE, NO_STR SET_STR "Transform BGP AS_PATH attribute\n" "Exclude from the as-path\n" "AS number\n") DEFUN (set_community, set_community_cmd, "set community .AA:NN", SET_STR "BGP community attribute\n" "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") { int i; int first = 0; int additive = 0; struct buffer *b; struct community *com = NULL; char *str; char *argstr; int ret; b = buffer_new (1024); for (i = 0; i < argc; i++) { if (strncmp (argv[i], "additive", strlen (argv[i])) == 0) { additive = 1; continue; } if (first) buffer_putc (b, ' '); else first = 1; if (strncmp (argv[i], "internet", strlen (argv[i])) == 0) { buffer_putstr (b, "internet"); continue; } if (strncmp (argv[i], "local-AS", strlen (argv[i])) == 0) { buffer_putstr (b, "local-AS"); continue; } if (strncmp (argv[i], "no-a", strlen ("no-a")) == 0 && strncmp (argv[i], "no-advertise", strlen (argv[i])) == 0) { buffer_putstr (b, "no-advertise"); continue; } if (strncmp (argv[i], "no-e", strlen ("no-e"))== 0 && strncmp (argv[i], "no-export", strlen (argv[i])) == 0) { buffer_putstr (b, "no-export"); continue; } buffer_putstr (b, argv[i]); } buffer_putc (b, '\0'); /* Fetch result string then compile it to communities attribute. */ str = buffer_getstr (b); buffer_free (b); if (str) { com = community_str2com (str); XFREE (MTYPE_TMP, str); } /* Can't compile user input into communities attribute. */ if (! com) { vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE); return CMD_WARNING; } /* Set communites attribute string. */ str = community_str (com); if (additive) { argstr = XCALLOC (MTYPE_TMP, strlen (str) + strlen (" additive") + 1); strcpy (argstr, str); strcpy (argstr + strlen (str), " additive"); ret = bgp_route_set_add (vty, vty->index, "community", argstr); XFREE (MTYPE_TMP, argstr); } else ret = bgp_route_set_add (vty, vty->index, "community", str); community_free (com); return ret; } DEFUN (set_community_none, set_community_none_cmd, "set community none", SET_STR "BGP community attribute\n" "No community attribute\n") { return bgp_route_set_add (vty, vty->index, "community", "none"); } DEFUN (no_set_community, no_set_community_cmd, "no set community", NO_STR SET_STR "BGP community attribute\n") { return bgp_route_set_delete (vty, vty->index, "community", NULL); } ALIAS (no_set_community, no_set_community_val_cmd, "no set community .AA:NN", NO_STR SET_STR "BGP community attribute\n" "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n") ALIAS (no_set_community, no_set_community_none_cmd, "no set community none", NO_STR SET_STR "BGP community attribute\n" "No community attribute\n") DEFUN (set_community_delete, set_community_delete_cmd, "set comm-list (<1-99>|<100-500>|WORD) delete", SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") { char *str; str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1); strcpy (str, argv[0]); strcpy (str + strlen (argv[0]), " delete"); bgp_route_set_add (vty, vty->index, "comm-list", str); XFREE (MTYPE_TMP, str); return CMD_SUCCESS; } DEFUN (no_set_community_delete, no_set_community_delete_cmd, "no set comm-list", NO_STR SET_STR "set BGP community list (for deletion)\n") { return bgp_route_set_delete (vty, vty->index, "comm-list", NULL); } ALIAS (no_set_community_delete, no_set_community_delete_val_cmd, "no set comm-list (<1-99>|<100-500>|WORD) delete", NO_STR SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" "Communitly-list number (expanded)\n" "Community-list name\n" "Delete matching communities\n") DEFUN (set_ecommunity_rt, set_ecommunity_rt_cmd, "set extcommunity rt .ASN:nn_or_IP-address:nn", SET_STR "BGP extended community attribute\n" "Route Target extended community\n" "VPN extended community\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", str); XFREE (MTYPE_TMP, str); return ret; } DEFUN (no_set_ecommunity_rt, no_set_ecommunity_rt_cmd, "no set extcommunity rt", NO_STR SET_STR "BGP extended community attribute\n" "Route Target extended community\n") { return bgp_route_set_delete (vty, vty->index, "extcommunity rt", NULL); } ALIAS (no_set_ecommunity_rt, no_set_ecommunity_rt_val_cmd, "no set extcommunity rt .ASN:nn_or_IP-address:nn", NO_STR SET_STR "BGP extended community attribute\n" "Route Target extended community\n" "VPN extended community\n") DEFUN (set_ecommunity_soo, set_ecommunity_soo_cmd, "set extcommunity soo .ASN:nn_or_IP-address:nn", SET_STR "BGP extended community attribute\n" "Site-of-Origin extended community\n" "VPN extended community\n") { int ret; char *str; str = argv_concat (argv, argc, 0); ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", str); XFREE (MTYPE_TMP, str); return ret; } DEFUN (no_set_ecommunity_soo, no_set_ecommunity_soo_cmd, "no set extcommunity soo", NO_STR SET_STR "BGP extended community attribute\n" "Site-of-Origin extended community\n") { return bgp_route_set_delete (vty, vty->index, "extcommunity soo", NULL); } ALIAS (no_set_ecommunity_soo, no_set_ecommunity_soo_val_cmd, "no set extcommunity soo .ASN:nn_or_IP-address:nn", NO_STR SET_STR "BGP extended community attribute\n" "Site-of-Origin extended community\n" "VPN extended community\n") DEFUN (set_origin, set_origin_cmd, "set origin (egp|igp|incomplete)", SET_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") { if (strncmp (argv[0], "igp", 2) == 0) return bgp_route_set_add (vty, vty->index, "origin", "igp"); if (strncmp (argv[0], "egp", 1) == 0) return bgp_route_set_add (vty, vty->index, "origin", "egp"); if (strncmp (argv[0], "incomplete", 2) == 0) return bgp_route_set_add (vty, vty->index, "origin", "incomplete"); return CMD_WARNING; } DEFUN (no_set_origin, no_set_origin_cmd, "no set origin", NO_STR SET_STR "BGP origin code\n") { return bgp_route_set_delete (vty, vty->index, "origin", NULL); } ALIAS (no_set_origin, no_set_origin_val_cmd, "no set origin (egp|igp|incomplete)", NO_STR SET_STR "BGP origin code\n" "remote EGP\n" "local IGP\n" "unknown heritage\n") DEFUN (set_atomic_aggregate, set_atomic_aggregate_cmd, "set atomic-aggregate", SET_STR "BGP atomic aggregate attribute\n" ) { return bgp_route_set_add (vty, vty->index, "atomic-aggregate", NULL); } DEFUN (no_set_atomic_aggregate, no_set_atomic_aggregate_cmd, "no set atomic-aggregate", NO_STR SET_STR "BGP atomic aggregate attribute\n" ) { return bgp_route_set_delete (vty, vty->index, "atomic-aggregate", NULL); } DEFUN (set_aggregator_as, set_aggregator_as_cmd, "set aggregator as " CMD_AS_RANGE " A.B.C.D", SET_STR "BGP aggregator attribute\n" "AS number of aggregator\n" "AS number\n" "IP address of aggregator\n") { int ret; as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); ret = inet_aton (argv[1], &address); if (ret == 0) { vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); return CMD_WARNING; } argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, strlen (argv[0]) + strlen (argv[1]) + 2); sprintf (argstr, "%s %s", argv[0], argv[1]); ret = bgp_route_set_add (vty, vty->index, "aggregator as", argstr); XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); return ret; } DEFUN (no_set_aggregator_as, no_set_aggregator_as_cmd, "no set aggregator as", NO_STR SET_STR "BGP aggregator attribute\n" "AS number of aggregator\n") { int ret; as_t as __attribute__((unused)); /* dummy for VTY_GET_INTEGER_RANGE */ struct in_addr address; char *argstr; if (argv == 0) return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL); VTY_GET_INTEGER_RANGE ("AS", as, argv[0], 1, BGP_AS4_MAX); ret = inet_aton (argv[1], &address); if (ret == 0) { vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE); return CMD_WARNING; } argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, strlen (argv[0]) + strlen (argv[1]) + 2); sprintf (argstr, "%s %s", argv[0], argv[1]); ret = bgp_route_set_delete (vty, vty->index, "aggregator as", argstr); XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr); return ret; } ALIAS (no_set_aggregator_as, no_set_aggregator_as_val_cmd, "no set aggregator as " CMD_AS_RANGE " A.B.C.D", NO_STR SET_STR "BGP aggregator attribute\n" "AS number of aggregator\n" "AS number\n" "IP address of aggregator\n") #ifdef HAVE_IPV6 DEFUN (match_ipv6_address, match_ipv6_address_cmd, "match ipv6 address WORD", MATCH_STR IPV6_STR "Match IPv6 address of route\n" "IPv6 access-list name\n") { return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]); } DEFUN (no_match_ipv6_address, no_match_ipv6_address_cmd, "no match ipv6 address WORD", NO_STR MATCH_STR IPV6_STR "Match IPv6 address of route\n" "IPv6 access-list name\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]); } DEFUN (match_ipv6_next_hop, match_ipv6_next_hop_cmd, "match ipv6 next-hop X:X::X:X", MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") { return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]); } DEFUN (no_match_ipv6_next_hop, no_match_ipv6_next_hop_cmd, "no match ipv6 next-hop X:X::X:X", NO_STR MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]); } DEFUN (match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, "match ipv6 address prefix-list WORD", MATCH_STR IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]); } DEFUN (no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, "no match ipv6 address prefix-list WORD", NO_STR MATCH_STR IPV6_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]); } DEFUN (set_ipv6_nexthop_peer, set_ipv6_nexthop_peer_cmd, "set ipv6 next-hop peer-address", SET_STR IPV6_STR "Next hop address\n" "Use peer address (for BGP only)\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop peer-address", NULL); } DEFUN (no_set_ipv6_nexthop_peer, no_set_ipv6_nexthop_peer_cmd, "no set ipv6 next-hop peer-address", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" ) { return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop", argv[0]); } DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]); } DEFUN (no_set_ipv6_nexthop_global, no_set_ipv6_nexthop_global_cmd, "no set ipv6 next-hop global", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL); return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]); } ALIAS (no_set_ipv6_nexthop_global, no_set_ipv6_nexthop_global_val_cmd, "no set ipv6 next-hop global X:X::X:X", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 global address\n" "IPv6 address of next hop\n") DEFUN (set_ipv6_nexthop_local, set_ipv6_nexthop_local_cmd, "set ipv6 next-hop local X:X::X:X", SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") { return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]); } DEFUN (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_cmd, "no set ipv6 next-hop local", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL); return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]); } ALIAS (no_set_ipv6_nexthop_local, no_set_ipv6_nexthop_local_val_cmd, "no set ipv6 next-hop local X:X::X:X", NO_STR SET_STR IPV6_STR "IPv6 next-hop address\n" "IPv6 local address\n" "IPv6 address of next hop\n") #endif /* HAVE_IPV6 */ DEFUN (set_vpnv4_nexthop, set_vpnv4_nexthop_cmd, "set vpnv4 next-hop A.B.C.D", SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") { return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]); } DEFUN (no_set_vpnv4_nexthop, no_set_vpnv4_nexthop_cmd, "no set vpnv4 next-hop", NO_STR SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL); return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]); } ALIAS (no_set_vpnv4_nexthop, no_set_vpnv4_nexthop_val_cmd, "no set vpnv4 next-hop A.B.C.D", NO_STR SET_STR "VPNv4 information\n" "VPNv4 next-hop address\n" "IP address of next hop\n") DEFUN (set_originator_id, set_originator_id_cmd, "set originator-id A.B.C.D", SET_STR "BGP originator ID attribute\n" "IP address of originator\n") { return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]); } DEFUN (no_set_originator_id, no_set_originator_id_cmd, "no set originator-id", NO_STR SET_STR "BGP originator ID attribute\n") { if (argc == 0) return bgp_route_set_delete (vty, vty->index, "originator-id", NULL); return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]); } ALIAS (no_set_originator_id, no_set_originator_id_val_cmd, "no set originator-id A.B.C.D", NO_STR SET_STR "BGP originator ID attribute\n" "IP address of originator\n") DEFUN_DEPRECATED (set_pathlimit_ttl, set_pathlimit_ttl_cmd, "set pathlimit ttl <1-255>", SET_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_set_pathlimit_ttl, no_set_pathlimit_ttl_cmd, "no set pathlimit ttl", NO_STR SET_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") { return CMD_SUCCESS; } ALIAS (no_set_pathlimit_ttl, no_set_pathlimit_ttl_val_cmd, "no set pathlimit ttl <1-255>", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Set AS-Path Hop-count TTL\n") DEFUN_DEPRECATED (match_pathlimit_as, match_pathlimit_as_cmd, "match pathlimit as <1-65535>", MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit AS number\n") { return CMD_SUCCESS; } DEFUN_DEPRECATED (no_match_pathlimit_as, no_match_pathlimit_as_cmd, "no match pathlimit as", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit AS number\n") { return CMD_SUCCESS; } ALIAS (no_match_pathlimit_as, no_match_pathlimit_as_val_cmd, "no match pathlimit as <1-65535>", NO_STR MATCH_STR "BGP AS-Pathlimit attribute\n" "Match Pathlimit ASN\n") /* Initialization of route map. */ void bgp_route_map_init (void) { route_map_init (); route_map_init_vty (); route_map_add_hook (bgp_route_map_update); route_map_delete_hook (bgp_route_map_update); route_map_install_match (&route_match_peer_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_route_source_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_route_source_prefix_list_cmd); route_map_install_match (&route_match_aspath_cmd); route_map_install_match (&route_match_community_cmd); route_map_install_match (&route_match_ecommunity_cmd); route_map_install_match (&route_match_metric_cmd); route_map_install_match (&route_match_origin_cmd); route_map_install_match (&route_match_probability_cmd); route_map_install_set (&route_set_ip_nexthop_cmd); route_map_install_set (&route_set_local_pref_cmd); route_map_install_set (&route_set_weight_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_aspath_prepend_cmd); route_map_install_set (&route_set_aspath_exclude_cmd); route_map_install_set (&route_set_origin_cmd); route_map_install_set (&route_set_atomic_aggregate_cmd); route_map_install_set (&route_set_aggregator_as_cmd); route_map_install_set (&route_set_community_cmd); route_map_install_set (&route_set_community_delete_cmd); route_map_install_set (&route_set_vpnv4_nexthop_cmd); route_map_install_set (&route_set_originator_id_cmd); route_map_install_set (&route_set_ecommunity_rt_cmd); route_map_install_set (&route_set_ecommunity_soo_cmd); install_element (RMAP_NODE, &match_peer_cmd); install_element (RMAP_NODE, &match_peer_local_cmd); install_element (RMAP_NODE, &no_match_peer_cmd); install_element (RMAP_NODE, &no_match_peer_val_cmd); install_element (RMAP_NODE, &no_match_peer_local_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); install_element (RMAP_NODE, &match_ip_route_source_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_route_source_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_route_source_prefix_list_val_cmd); install_element (RMAP_NODE, &match_aspath_cmd); install_element (RMAP_NODE, &no_match_aspath_cmd); install_element (RMAP_NODE, &no_match_aspath_val_cmd); install_element (RMAP_NODE, &match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_cmd); install_element (RMAP_NODE, &no_match_metric_val_cmd); install_element (RMAP_NODE, &match_community_cmd); install_element (RMAP_NODE, &match_community_exact_cmd); install_element (RMAP_NODE, &no_match_community_cmd); install_element (RMAP_NODE, &no_match_community_val_cmd); install_element (RMAP_NODE, &no_match_community_exact_cmd); install_element (RMAP_NODE, &match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_cmd); install_element (RMAP_NODE, &no_match_ecommunity_val_cmd); install_element (RMAP_NODE, &match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_cmd); install_element (RMAP_NODE, &no_match_origin_val_cmd); install_element (RMAP_NODE, &match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_cmd); install_element (RMAP_NODE, &no_match_probability_val_cmd); install_element (RMAP_NODE, &set_ip_nexthop_cmd); install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_cmd); install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd); install_element (RMAP_NODE, &set_local_pref_cmd); install_element (RMAP_NODE, &no_set_local_pref_cmd); install_element (RMAP_NODE, &no_set_local_pref_val_cmd); install_element (RMAP_NODE, &set_weight_cmd); install_element (RMAP_NODE, &no_set_weight_cmd); install_element (RMAP_NODE, &no_set_weight_val_cmd); install_element (RMAP_NODE, &set_metric_cmd); install_element (RMAP_NODE, &set_metric_addsub_cmd); install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_aspath_prepend_cmd); install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd); install_element (RMAP_NODE, &set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); install_element (RMAP_NODE, &no_set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_exclude_val_cmd); install_element (RMAP_NODE, &set_origin_cmd); install_element (RMAP_NODE, &no_set_origin_cmd); install_element (RMAP_NODE, &no_set_origin_val_cmd); install_element (RMAP_NODE, &set_atomic_aggregate_cmd); install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd); install_element (RMAP_NODE, &set_aggregator_as_cmd); install_element (RMAP_NODE, &no_set_aggregator_as_cmd); install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd); install_element (RMAP_NODE, &set_community_cmd); install_element (RMAP_NODE, &set_community_none_cmd); install_element (RMAP_NODE, &no_set_community_cmd); install_element (RMAP_NODE, &no_set_community_val_cmd); install_element (RMAP_NODE, &no_set_community_none_cmd); install_element (RMAP_NODE, &set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_cmd); install_element (RMAP_NODE, &no_set_community_delete_val_cmd); install_element (RMAP_NODE, &set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd); install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd); install_element (RMAP_NODE, &set_ecommunity_soo_cmd); install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd); install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd); install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd); install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd); install_element (RMAP_NODE, &set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_cmd); install_element (RMAP_NODE, &no_set_originator_id_val_cmd); #ifdef HAVE_IPV6 route_map_install_match (&route_match_ipv6_address_cmd); route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); route_map_install_set (&route_set_ipv6_nexthop_peer_cmd); install_element (RMAP_NODE, &match_ipv6_address_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_cmd); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd); install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_peer_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd); #endif /* HAVE_IPV6 */ /* AS-Pathlimit: functionality removed, commands kept for * compatibility. */ install_element (RMAP_NODE, &set_pathlimit_ttl_cmd); install_element (RMAP_NODE, &no_set_pathlimit_ttl_cmd); install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd); install_element (RMAP_NODE, &match_pathlimit_as_cmd); install_element (RMAP_NODE, &no_match_pathlimit_as_cmd); install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd); } quagga-0.99.24.1/bgpd/bgp_open.c0000644000175000017500000007714312476520570013121 00000000000000/* BGP open message handling Copyright (C) 1998, 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "stream.h" #include "thread.h" #include "log.h" #include "command.h" #include "memory.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_vty.h" /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can negotiate remote peer supports extentions or not. But if remote-peer doesn't supports negotiation process itself. We would like to do manual configuration. So there is many configurable point. First of all we want set each peer whether we send capability negotiation to the peer or not. Next, if we send capability to the peer we want to set my capabilty inforation at each peer. */ void bgp_capability_vty_out (struct vty *vty, struct peer *peer) { char *pnt; char *end; struct capability_mp_data mpc; struct capability_header *hdr; pnt = peer->notify.data; end = pnt + peer->notify.length; while (pnt < end) { if (pnt + sizeof (struct capability_mp_data) + 2 > end) return; hdr = (struct capability_header *)pnt; if (pnt + hdr->length + 2 > end) return; memcpy (&mpc, pnt + 2, sizeof(struct capability_mp_data)); if (hdr->code == CAPABILITY_CODE_MP) { vty_out (vty, " Capability error for: Multi protocol "); switch (ntohs (mpc.afi)) { case AFI_IP: vty_out (vty, "AFI IPv4, "); break; case AFI_IP6: vty_out (vty, "AFI IPv6, "); break; default: vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi)); break; } switch (mpc.safi) { case SAFI_UNICAST: vty_out (vty, "SAFI Unicast"); break; case SAFI_MULTICAST: vty_out (vty, "SAFI Multicast"); break; case SAFI_MPLS_LABELED_VPN: vty_out (vty, "SAFI MPLS-labeled VPN"); break; default: vty_out (vty, "SAFI Unknown %d ", mpc.safi); break; } vty_out (vty, "%s", VTY_NEWLINE); } else if (hdr->code >= 128) vty_out (vty, " Capability error: vendor specific capability code %d", hdr->code); else vty_out (vty, " Capability error: unknown capability code %d", hdr->code); pnt += hdr->length + 2; } } static void bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc) { mpc->afi = stream_getw (s); mpc->reserved = stream_getc (s); mpc->safi = stream_getc (s); } int bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi) { switch (afi) { case AFI_IP: #ifdef HAVE_IPV6 case AFI_IP6: #endif switch (*safi) { /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ case SAFI_MPLS_LABELED_VPN: *safi = SAFI_MPLS_VPN; case SAFI_UNICAST: case SAFI_MULTICAST: case SAFI_MPLS_VPN: return 1; } } zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); return 0; } /* Set negotiated capability value. */ static int bgp_capability_mp (struct peer *peer, struct capability_header *hdr) { struct capability_mp_data mpc; struct stream *s = BGP_INPUT (peer); bgp_capability_mp_data (s, &mpc); if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has MP_EXT CAP for afi/safi: %u/%u", peer->host, mpc.afi, mpc.safi); if (!bgp_afi_safi_valid_indices (mpc.afi, &mpc.safi)) return -1; /* Now safi remapped, and afi/safi are valid array indices */ peer->afc_recv[mpc.afi][mpc.safi] = 1; if (peer->afc[mpc.afi][mpc.safi]) peer->afc_nego[mpc.afi][mpc.safi] = 1; else return -1; return 0; } static void bgp_capability_orf_not_support (struct peer *peer, afi_t afi, safi_t safi, u_char type, u_char mode) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d has ORF type/mode %d/%d not supported", peer->host, afi, safi, type, mode); } static const struct message orf_type_str[] = { { ORF_TYPE_PREFIX, "Prefixlist" }, { ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" }, }; static const int orf_type_str_max = array_size(orf_type_str); static const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" }, { ORF_MODE_SEND, "Send" }, { ORF_MODE_BOTH, "Both" }, }; static const int orf_mode_str_max = array_size(orf_mode_str); static int bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT (peer); struct capability_orf_entry entry; afi_t afi; safi_t safi; u_char type; u_char mode; u_int16_t sm_cap = 0; /* capability send-mode receive */ u_int16_t rm_cap = 0; /* capability receive-mode receive */ int i; /* ORF Entry header */ bgp_capability_mp_data (s, &entry.mpc); entry.num = stream_getc (s); afi = entry.mpc.afi; safi = entry.mpc.safi; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s ORF Cap entry for afi/safi: %u/%u", peer->host, entry.mpc.afi, entry.mpc.safi); /* Check AFI and SAFI. */ if (!bgp_afi_safi_valid_indices (entry.mpc.afi, &safi)) { zlog_info ("%s Addr-family %d/%d not supported." " Ignoring the ORF capability", peer->host, entry.mpc.afi, entry.mpc.safi); return 0; } /* validate number field */ if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) { zlog_info ("%s ORF Capability entry length error," " Cap length %u, num %u", peer->host, hdr->length, entry.num); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } for (i = 0 ; i < entry.num ; i++) { type = stream_getc(s); mode = stream_getc(s); /* ORF Mode error check */ switch (mode) { case ORF_MODE_BOTH: case ORF_MODE_SEND: case ORF_MODE_RECEIVE: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* ORF Type and afi/safi error checks */ /* capcode versus type */ switch (hdr->code) { case CAPABILITY_CODE_ORF: switch (type) { case ORF_TYPE_PREFIX: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; case CAPABILITY_CODE_ORF_OLD: switch (type) { case ORF_TYPE_PREFIX_OLD: break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } break; default: bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } /* AFI vs SAFI */ if (!((afi == AFI_IP && safi == SAFI_UNICAST) || (afi == AFI_IP && safi == SAFI_MULTICAST) || (afi == AFI_IP6 && safi == SAFI_UNICAST))) { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s ORF capability" " as %s for afi/safi: %d/%d", peer->host, LOOKUP (orf_type_str, type), LOOKUP (orf_mode_str, mode), entry.mpc.afi, safi); if (hdr->code == CAPABILITY_CODE_ORF) { sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; } else if (hdr->code == CAPABILITY_CODE_ORF_OLD) { sm_cap = PEER_CAP_ORF_PREFIX_SM_OLD_RCV; rm_cap = PEER_CAP_ORF_PREFIX_RM_OLD_RCV; } else { bgp_capability_orf_not_support (peer, afi, safi, type, mode); continue; } switch (mode) { case ORF_MODE_BOTH: SET_FLAG (peer->af_cap[afi][safi], sm_cap); SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; case ORF_MODE_SEND: SET_FLAG (peer->af_cap[afi][safi], sm_cap); break; case ORF_MODE_RECEIVE: SET_FLAG (peer->af_cap[afi][safi], rm_cap); break; } } return 0; } static int bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) { struct stream *s = BGP_INPUT (peer); u_int16_t restart_flag_time; size_t end = stream_get_getp (s) + caphdr->length; SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); UNSET_FLAG (restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; if (BGP_DEBUG (normal, NORMAL)) { zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); zlog_debug ("%s Peer has%srestarted. Restart Time : %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV) ? " " : " not ", peer->v_gr_restart); } while (stream_get_getp (s) + 4 <= end) { afi_t afi = stream_getw (s); safi_t safi = stream_getc (s); u_char flag = stream_getc (s); if (!bgp_afi_safi_valid_indices (afi, &safi)) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else if (!peer->afc[afi][safi]) { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled." " Ignore the Graceful Restart capability", peer->host, afi, safi); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Address family %s is%spreserved", peer->host, afi_safi_print (afi, safi), CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV) ? " " : " not "); SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); if (CHECK_FLAG (flag, RESTART_F_BIT)) SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV); } } return 0; } static as_t bgp_capability_as4 (struct peer *peer, struct capability_header *hdr) { SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); if (hdr->length != CAPABILITY_CODE_AS4_LEN) { zlog_err ("%s AS4 capability has incorrect data length %d", peer->host, hdr->length); return 0; } as_t as4 = stream_getl (BGP_INPUT(peer)); if (BGP_DEBUG (as4, AS4)) zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", peer->host, as4); return as4; } static const struct message capcode_str[] = { { CAPABILITY_CODE_MP, "MultiProtocol Extensions" }, { CAPABILITY_CODE_REFRESH, "Route Refresh" }, { CAPABILITY_CODE_ORF, "Cooperative Route Filtering" }, { CAPABILITY_CODE_RESTART, "Graceful Restart" }, { CAPABILITY_CODE_AS4, "4-octet AS number" }, { CAPABILITY_CODE_DYNAMIC, "Dynamic" }, { CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, { CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, }; static const int capcode_str_max = array_size(capcode_str); /* Minimum sizes for length field of each cap (so not inc. the header) */ static const size_t cap_minsizes[] = { [CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data), [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry), [CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr), [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, [CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), }; /** * Parse given capability. * XXX: This is reading into a stream, but not using stream API * * @param[out] mp_capability Set to 1 on return iff one or more Multiprotocol * capabilities were encountered. */ static int bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability, u_char **error) { int ret; struct stream *s = BGP_INPUT (peer); size_t end = stream_get_getp (s) + length; assert (STREAM_READABLE (s) >= length); while (stream_get_getp (s) < end) { size_t start; u_char *sp = stream_pnt (s); struct capability_header caphdr; /* We need at least capability code and capability length. */ if (stream_get_getp(s) + 2 > end) { zlog_info ("%s Capability length error (< header)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } caphdr.code = stream_getc (s); caphdr.length = stream_getc (s); start = stream_get_getp (s); /* Capability length check sanity check. */ if (start + caphdr.length > end) { zlog_info ("%s Capability length error (< length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s OPEN has %s capability (%u), length %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.code, caphdr.length); /* Length sanity check, type-specific, for known capabilities */ switch (caphdr.code) { case CAPABILITY_CODE_MP: case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: case CAPABILITY_CODE_RESTART: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info ("%s %s Capability length error: got %u," " expected at least %u", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length, (unsigned) cap_minsizes[caphdr.code]); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* we deliberately ignore unknown codes, see below */ default: break; } switch (caphdr.code) { case CAPABILITY_CODE_MP: { *mp_capability = 1; /* Ignore capability when override-capability is set. */ if (! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { /* Set negotiated value. */ ret = bgp_capability_mp (peer, &caphdr); /* Unsupported Capability. */ if (ret < 0) { /* Store return data. */ memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } } break; case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH_OLD: { /* BGP refresh capability */ if (caphdr.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } break; case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF_OLD: if (bgp_capability_orf_entry (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_RESTART: if (bgp_capability_restart (peer, &caphdr)) return -1; break; case CAPABILITY_CODE_DYNAMIC: SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV); break; case CAPABILITY_CODE_AS4: /* Already handled as a special-case parsing of the capabilities * at the beginning of OPEN processing. So we care not a jot * for the value really, only error case. */ if (!bgp_capability_as4 (peer, &caphdr)) return -1; break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor specific capabilities. It seems reasonable for now... */ zlog_warn ("%s Vendor specific capability %d", peer->host, caphdr.code); } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, caphdr.code); memcpy (*error, sp, caphdr.length + 2); *error += caphdr.length + 2; } } if (stream_get_getp(s) != (start + caphdr.length)) { if (stream_get_getp(s) > (start + caphdr.length)) zlog_warn ("%s Cap-parser for %s read past cap-length, %u!", peer->host, LOOKUP (capcode_str, caphdr.code), caphdr.length); stream_set_getp (s, start + caphdr.length); } } return 0; } static int bgp_auth_parse (struct peer *peer, size_t length) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_AUTH_FAILURE); return -1; } static int strict_capability_same (struct peer *peer) { int i, j; for (i = AFI_IP; i < AFI_MAX; i++) for (j = SAFI_UNICAST; j < SAFI_MAX; j++) if (peer->afc[i][j] != peer->afc_nego[i][j]) return 0; return 1; } /* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ as_t peek_for_as4_capability (struct peer *peer, u_char length) { struct stream *s = BGP_INPUT (peer); size_t orig_getp = stream_get_getp (s); size_t end = orig_getp + length; as_t as4 = 0; /* The full capability parser will better flag the error.. */ if (STREAM_READABLE(s) < length) return 0; if (BGP_DEBUG (as4, AS4)) zlog_info ("%s [AS4] rcv OPEN w/ OPTION parameter len: %u," " peeking for as4", peer->host, length); /* the error cases we DONT handle, we ONLY try to read as4 out of * correctly formatted options. */ while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Check the length. */ if (stream_get_getp (s) + 2 > end) goto end; /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (stream_get_getp (s) + opt_length > end) goto end; if (opt_type == BGP_OPEN_OPT_CAP) { unsigned long capd_start = stream_get_getp (s); unsigned long capd_end = capd_start + opt_length; assert (capd_end <= end); while (stream_get_getp (s) < capd_end) { struct capability_header hdr; if (stream_get_getp (s) + 2 > capd_end) goto end; hdr.code = stream_getc (s); hdr.length = stream_getc (s); if ((stream_get_getp(s) + hdr.length) > capd_end) goto end; if (hdr.code == CAPABILITY_CODE_AS4) { if (BGP_DEBUG (as4, AS4)) zlog_info ("[AS4] found AS4 capability, about to parse"); as4 = bgp_capability_as4 (peer, &hdr); goto end; } stream_forward_getp (s, hdr.length); } } } end: stream_set_getp (s, orig_getp); return as4; } /** * Parse open option. * * @param[out] mp_capability @see bgp_capability_parse() for semantics. */ int bgp_open_option_parse (struct peer *peer, u_char length, int *mp_capability) { int ret; u_char *error; u_char error_data[BGP_MAX_PACKET_SIZE]; struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp (s) + length; ret = 0; error = error_data; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcv OPEN w/ OPTION parameter len: %u", peer->host, length); while (stream_get_getp(s) < end) { u_char opt_type; u_char opt_length; /* Must have at least an OPEN option header */ if (STREAM_READABLE(s) < 2) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* Fetch option type and length. */ opt_type = stream_getc (s); opt_length = stream_getc (s); /* Option length check. */ if (STREAM_READABLE (s) < opt_length) { zlog_info ("%s Option length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s rcvd OPEN w/ optional parameter type %u (%s) len %u", peer->host, opt_type, opt_type == BGP_OPEN_OPT_AUTH ? "Authentication" : opt_type == BGP_OPEN_OPT_CAP ? "Capability" : "Unknown", opt_length); switch (opt_type) { case BGP_OPEN_OPT_AUTH: ret = bgp_auth_parse (peer, opt_length); break; case BGP_OPEN_OPT_CAP: ret = bgp_capability_parse (peer, opt_length, mp_capability, &error); break; default: bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_PARAM); ret = -1; break; } /* Parse error. To accumulate all unsupported capability codes, bgp_capability_parse does not return -1 when encounter unsupported capability code. To detect that, please check error and erro_data pointer, like below. */ if (ret < 0) return -1; } /* All OPEN option is parsed. Check capability when strict compare flag is enabled.*/ if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { /* If Unsupported Capability exists. */ if (error != error_data) { bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); return -1; } /* Check local capability does not negotiated with remote peer. */ if (! strict_capability_same (peer)) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } /* Check there are no common AFI/SAFIs and send Unsupported Capability error. */ if (*mp_capability && ! CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] && ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] && ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) { plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " "overlap with received MP capabilities", peer->host); if (error != error_data) bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, error_data, error - error_data); else bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL); return -1; } } return 0; } static void bgp_open_capability_orf (struct stream *s, struct peer *peer, afi_t afi, safi_t safi, u_char code) { u_char cap_len; u_char orf_len; unsigned long capp; unsigned long orfp; unsigned long numberp; int number_of_orfs = 0; if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ stream_putc (s, 0); /* Capability Length */ stream_putc (s, code); /* Capability Code */ orfp = stream_get_endp (s); /* Set ORF Len Pointer */ stream_putc (s, 0); /* ORF Length */ stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); numberp = stream_get_endp (s); /* Set Number Pointer */ stream_putc (s, 0); /* Number of ORFs */ /* Address Prefix ORF */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { stream_putc (s, (code == CAPABILITY_CODE_ORF ? ORF_TYPE_PREFIX : ORF_TYPE_PREFIX_OLD)); if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); stream_putc (s, ORF_MODE_BOTH); } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) { SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV); stream_putc (s, ORF_MODE_SEND); } else { SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV); stream_putc (s, ORF_MODE_RECEIVE); } number_of_orfs++; } /* Total Number of ORFs. */ stream_putc_at (s, numberp, number_of_orfs); /* Total ORF Len. */ orf_len = stream_get_endp (s) - orfp - 1; stream_putc_at (s, orfp, orf_len); /* Total Capability Len. */ cap_len = stream_get_endp (s) - capp - 1; stream_putc_at (s, capp, cap_len); } /* Fill in capability open option to the packet. */ void bgp_open_capability (struct stream *s, struct peer *peer) { u_char len; unsigned long cp, capp, rcapp; afi_t afi; safi_t safi; as_t local_as; u_int32_t restart_time; /* Remember current pointer for Opt Parm Len. */ cp = stream_get_endp (s); /* Opt Parm Len. */ stream_putc (s, 0); /* Do not send capability. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN) || CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) return; /* IPv4 unicast. */ if (peer->afc[AFI_IP][SAFI_UNICAST]) { peer->afc_adv[AFI_IP][SAFI_UNICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP); stream_putc (s, 0); stream_putc (s, SAFI_UNICAST); } /* IPv4 multicast. */ if (peer->afc[AFI_IP][SAFI_MULTICAST]) { peer->afc_adv[AFI_IP][SAFI_MULTICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP); stream_putc (s, 0); stream_putc (s, SAFI_MULTICAST); } /* IPv4 VPN */ if (peer->afc[AFI_IP][SAFI_MPLS_VPN]) { peer->afc_adv[AFI_IP][SAFI_MPLS_VPN] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP); stream_putc (s, 0); stream_putc (s, SAFI_MPLS_LABELED_VPN); } #ifdef HAVE_IPV6 /* IPv6 unicast. */ if (peer->afc[AFI_IP6][SAFI_UNICAST]) { peer->afc_adv[AFI_IP6][SAFI_UNICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP6); stream_putc (s, 0); stream_putc (s, SAFI_UNICAST); } /* IPv6 multicast. */ if (peer->afc[AFI_IP6][SAFI_MULTICAST]) { peer->afc_adv[AFI_IP6][SAFI_MULTICAST] = 1; stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, AFI_IP6); stream_putc (s, 0); stream_putc (s, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ /* Route refresh. */ SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc (s, CAPABILITY_CODE_REFRESH); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); /* AS4 */ SET_FLAG (peer->cap, PEER_CAP_AS4_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_AS4_LEN + 2); stream_putc (s, CAPABILITY_CODE_AS4); stream_putc (s, CAPABILITY_CODE_AS4_LEN); if ( peer->change_local_as ) local_as = peer->change_local_as; else local_as = peer->local_as; stream_putl (s, local_as ); /* ORF capability. */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF_OLD); bgp_open_capability_orf (s, peer, afi, safi, CAPABILITY_CODE_ORF); } /* Dynamic capability. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) { SET_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN + 2); stream_putc (s, CAPABILITY_CODE_DYNAMIC); stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); } /* Sending base graceful-restart capability irrespective of the config */ SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); stream_putc (s, BGP_OPEN_OPT_CAP); capp = stream_get_endp (s); /* Set Capability Len Pointer */ stream_putc (s, 0); /* Capability Length */ stream_putc (s, CAPABILITY_CODE_RESTART); rcapp = stream_get_endp (s); /* Set Restart Capability Len Pointer */ stream_putc (s, 0); restart_time = peer->bgp->restart_time; if (peer->bgp->t_startup) { SET_FLAG (restart_time, RESTART_R_BIT); SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_ADV); } stream_putw (s, restart_time); /* Send address-family specific graceful-restart capability only when GR config is present */ if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) { for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (peer->afc[afi][safi]) { stream_putw (s, afi); stream_putc (s, safi); stream_putc (s, 0); //Forwarding is not retained as of now. } } /* Total Graceful restart capability Len. */ len = stream_get_endp (s) - rcapp - 1; stream_putc_at (s, rcapp, len); /* Total Capability Len. */ len = stream_get_endp (s) - capp - 1; stream_putc_at (s, capp, len); /* Total Opt Parm Len. */ len = stream_get_endp (s) - cp - 1; stream_putc_at (s, cp, len); } quagga-0.99.24.1/bgpd/bgp_zebra.c0000644000175000017500000006654212476520570013264 00000000000000/* zebra client Copyright (C) 1997, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "command.h" #include "stream.h" #include "network.h" #include "prefix.h" #include "log.h" #include "sockunion.h" #include "zclient.h" #include "routemap.h" #include "thread.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_mpath.h" /* All information about zebra. */ struct zclient *zclient = NULL; struct in_addr router_id_zebra; /* Growable buffer for nexthops sent to zebra */ struct stream *bgp_nexthop_buf = NULL; /* Router-id update message from zebra. */ static int bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length) { struct prefix router_id; struct listnode *node, *nnode; struct bgp *bgp; zebra_router_id_update_read(zclient->ibuf,&router_id); if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(&router_id, buf, sizeof(buf)); zlog_debug("Zebra rcvd: router id update %s", buf); } router_id_zebra = router_id.u.prefix4; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { if (!bgp->router_id_static.s_addr) bgp_router_id_set (bgp, &router_id.u.prefix4); } return 0; } /* Inteface addition message from zebra. */ static int bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length) { struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (BGP_DEBUG(zebra, ZEBRA) && ifp) zlog_debug("Zebra rcvd: interface add %s", ifp->name); return 0; } static int bgp_interface_delete (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; s = zclient->ibuf; ifp = zebra_interface_state_read (s); ifp->ifindex = IFINDEX_INTERNAL; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface delete %s", ifp->name); return 0; } static int bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s up", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_add (c); return 0; } static int bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct interface *ifp; struct connected *c; struct listnode *node, *nnode; s = zclient->ibuf; ifp = zebra_interface_state_read (s); if (! ifp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra rcvd: interface %s down", ifp->name); for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c)) bgp_connected_delete (c); /* Fast external-failover */ { struct listnode *mnode; struct bgp *bgp; struct peer *peer; for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp)) { if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) continue; for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) continue; if (ifp == peer->nexthop.ifp) BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } static int bgp_interface_address_add (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf); if (ifc == NULL) return 0; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(ifc->address, buf, sizeof(buf)); zlog_debug("Zebra rcvd: interface %s address add %s", ifc->ifp->name, buf); } if (if_is_operative (ifc->ifp)) bgp_connected_add (ifc); return 0; } static int bgp_interface_address_delete (int command, struct zclient *zclient, zebra_size_t length) { struct connected *ifc; ifc = zebra_interface_address_read (command, zclient->ibuf); if (ifc == NULL) return 0; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[128]; prefix2str(ifc->address, buf, sizeof(buf)); zlog_debug("Zebra rcvd: interface %s address delete %s", ifc->ifp->name, buf); } if (if_is_operative (ifc->ifp)) bgp_connected_delete (ifc); connected_free (ifc); return 0; } /* Zebra route add and delete treatment. */ static int zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv4 api; struct in_addr nexthop; struct prefix_ipv4 p; s = zclient->ibuf; nexthop.s_addr = 0; /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv4 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); nexthop.s_addr = stream_get_ipv4 (s); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; if (command == ZEBRA_IPV4_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, api.metric, api.type); } else { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d " "nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_delete((struct prefix *)&p, api.type); } return 0; } #ifdef HAVE_IPV6 /* Zebra route add and delete treatment. */ static int zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length) { struct stream *s; struct zapi_ipv6 api; struct in6_addr nexthop; struct prefix_ipv6 p; s = zclient->ibuf; memset (&nexthop, 0, sizeof (struct in6_addr)); /* Type, flags, message. */ api.type = stream_getc (s); api.flags = stream_getc (s); api.message = stream_getc (s); /* IPv6 prefix. */ memset (&p, 0, sizeof (struct prefix_ipv6)); p.family = AF_INET6; p.prefixlen = stream_getc (s); stream_get (&p.prefix, s, PSIZE (p.prefixlen)); /* Nexthop, ifindex, distance, metric. */ if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { api.nexthop_num = stream_getc (s); stream_get (&nexthop, s, 16); } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { api.ifindex_num = stream_getc (s); stream_getl (s); /* ifindex, unused */ } if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) api.distance = stream_getc (s); else api.distance = 0; if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) api.metric = stream_getl (s); else api.metric = 0; /* Simply ignore link-local address. */ if (IN6_IS_ADDR_LINKLOCAL (&p.prefix)) return 0; if (command == ZEBRA_IPV6_ROUTE_ADD) { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, api.metric, api.type); } else { if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " "nexthop %s metric %u", zebra_route_string(api.type), inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), p.prefixlen, inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), api.metric); } bgp_redistribute_delete ((struct prefix *) &p, api.type); } return 0; } #endif /* HAVE_IPV6 */ struct interface * if_lookup_by_ipv4 (struct in_addr *addr) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv4 p; struct prefix *cp; p.family = AF_INET; p.prefix = *addr; p.prefixlen = IPV4_MAX_BITLEN; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET) if (prefix_match (cp, (struct prefix *)&p)) return ifp; } } return NULL; } struct interface * if_lookup_by_ipv4_exact (struct in_addr *addr) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET) if (IPV4_ADDR_SAME (&cp->u.prefix4, addr)) return ifp; } } return NULL; } #ifdef HAVE_IPV6 struct interface * if_lookup_by_ipv6 (struct in6_addr *addr) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv6 p; struct prefix *cp; p.family = AF_INET6; p.prefix = *addr; p.prefixlen = IPV6_MAX_BITLEN; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET6) if (prefix_match (cp, (struct prefix *)&p)) return ifp; } } return NULL; } struct interface * if_lookup_by_ipv6_exact (struct in6_addr *addr) { struct listnode *ifnode; struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp)) { for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET6) if (IPV6_ADDR_SAME (&cp->u.prefix6, addr)) return ifp; } } return NULL; } static int if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET6) if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) { memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); return 1; } } return 0; } static int if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if (cp->family == AF_INET6) if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6)) { memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN); return 1; } } return 0; } #endif /* HAVE_IPV6 */ static int if_get_ipv4_address (struct interface *ifp, struct in_addr *addr) { struct listnode *cnode; struct connected *connected; struct prefix *cp; for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected)) { cp = connected->address; if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) { *addr = cp->u.prefix4; return 1; } } return 0; } int bgp_nexthop_set (union sockunion *local, union sockunion *remote, struct bgp_nexthop *nexthop, struct peer *peer) { int ret = 0; struct interface *ifp = NULL; memset (nexthop, 0, sizeof (struct bgp_nexthop)); if (!local) return -1; if (!remote) return -1; if (local->sa.sa_family == AF_INET) { nexthop->v4 = local->sin.sin_addr; ifp = if_lookup_by_ipv4 (&local->sin.sin_addr); } #ifdef HAVE_IPV6 if (local->sa.sa_family == AF_INET6) { if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { if (peer->ifname) ifp = if_lookup_by_index (if_nametoindex (peer->ifname)); } else ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr); } #endif /* HAVE_IPV6 */ if (!ifp) return -1; nexthop->ifp = ifp; /* IPv4 connection. */ if (local->sa.sa_family == AF_INET) { #ifdef HAVE_IPV6 /* IPv6 nexthop*/ ret = if_get_ipv6_global (ifp, &nexthop->v6_global); /* There is no global nexthop. */ if (!ret) if_get_ipv6_local (ifp, &nexthop->v6_global); else if_get_ipv6_local (ifp, &nexthop->v6_local); #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 /* IPv6 connection. */ if (local->sa.sa_family == AF_INET6) { struct interface *direct = NULL; /* IPv4 nexthop. */ ret = if_get_ipv4_address(ifp, &nexthop->v4); if (!ret && peer->local_id.s_addr) nexthop->v4 = peer->local_id; /* Global address*/ if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr)) { memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); /* If directory connected set link-local address. */ direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr); if (direct) if_get_ipv6_local (ifp, &nexthop->v6_local); } else /* Link-local address. */ { ret = if_get_ipv6_global (ifp, &nexthop->v6_global); /* If there is no global address. Set link-local address as global. I know this break RFC specification... */ if (!ret) memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); else memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, IPV6_MAX_BYTELEN); } } if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) || if_lookup_by_ipv6 (&remote->sin6.sin6_addr)) peer->shared_network = 1; else peer->shared_network = 0; /* KAME stack specific treatment. */ #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global) && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global)) { SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0); } if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local) && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local)) { SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0); } #endif /* KAME */ #endif /* HAVE_IPV6 */ return ret; } void bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi) { int flags; u_char distance; struct peer *peer; struct bgp_info *mpinfo; size_t oldsize, newsize; if (zclient->sock < 0) return; if (! zclient->redist[ZEBRA_ROUTE_BGP]) return; flags = 0; peer = info->peer; if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { SET_FLAG (flags, ZEBRA_FLAG_IBGP); SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); /* resize nexthop buffer size if necessary */ if ((oldsize = stream_get_size (bgp_nexthop_buf)) < (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1))) { newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)); newsize = stream_resize (bgp_nexthop_buf, newsize); if (newsize == oldsize) { zlog_err ("can't resize nexthop buffer"); return; } } stream_reset (bgp_nexthop_buf); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; api.flags = flags; nexthop = &info->attr->nexthop; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); for (mpinfo = bgp_info_mpath_first (info); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { nexthop = &mpinfo->attr->nexthop; stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *)); } api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1 + bgp_info_mpath_count (info); api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf); api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; distance = bgp_distance_apply (p, info, bgp); if (distance) { SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; } if (BGP_DEBUG(zebra, ZEBRA)) { int i; char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u" " count %d", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])), api.metric, api.nexthop_num); for (i = 1; i < api.nexthop_num; i++) zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s", i, inet_ntop(AF_INET, api.nexthop[i], buf[1], sizeof(buf[1]))); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { unsigned int ifindex; struct in6_addr *nexthop; struct zapi_ipv6 api; ifindex = 0; nexthop = NULL; assert (info->attr->extra); /* Only global address nexthop exists. */ if (info->attr->extra->mp_nexthop_len == 16) nexthop = &info->attr->extra->mp_nexthop_global; /* If both global and link-local address present. */ if (info->attr->extra->mp_nexthop_len == 32) { /* Workaround for Cisco's nexthop bug. */ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) && peer->su_remote->sa.sa_family == AF_INET6) nexthop = &peer->su_remote->sin6.sin6_addr; else nexthop = &info->attr->extra->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) { if (info->peer->ifname) ifindex = if_nametoindex (info->peer->ifname); else if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } /* Make Zebra API structure. */ api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), api.metric); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, (struct prefix_ipv6 *) p, &api); } #endif /* HAVE_IPV6 */ } void bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi) { int flags; struct peer *peer; if (zclient->sock < 0) return; if (! zclient->redist[ZEBRA_ROUTE_BGP]) return; peer = info->peer; flags = 0; if (peer->sort == BGP_PEER_IBGP) { SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); SET_FLAG (flags, ZEBRA_FLAG_IBGP); } if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) SET_FLAG (flags, ZEBRA_FLAG_INTERNAL); if (p->family == AF_INET) { struct zapi_ipv4 api; struct in_addr *nexthop; api.flags = flags; nexthop = &info->attr->nexthop; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; api.ifindex_num = 0; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET_ADDRSTRLEN]; zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u", inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])), api.metric); } zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, (struct prefix_ipv4 *) p, &api); } #ifdef HAVE_IPV6 /* We have to think about a IPv6 link-local address curse. */ if (p->family == AF_INET6) { struct zapi_ipv6 api; unsigned int ifindex; struct in6_addr *nexthop; assert (info->attr->extra); ifindex = 0; nexthop = NULL; /* Only global address nexthop exists. */ if (info->attr->extra->mp_nexthop_len == 16) nexthop = &info->attr->extra->mp_nexthop_global; /* If both global and link-local address present. */ if (info->attr->extra->mp_nexthop_len == 32) { nexthop = &info->attr->extra->mp_nexthop_local; if (info->peer->nexthop.ifp) ifindex = info->peer->nexthop.ifp->ifindex; } if (nexthop == NULL) return; if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex) if (info->peer->ifname) ifindex = if_nametoindex (info->peer->ifname); api.flags = flags; api.type = ZEBRA_ROUTE_BGP; api.message = 0; api.safi = safi; SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop; SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX); api.ifindex_num = 1; api.ifindex = &ifindex; SET_FLAG (api.message, ZAPI_MESSAGE_METRIC); api.metric = info->attr->med; if (BGP_DEBUG(zebra, ZEBRA)) { char buf[2][INET6_ADDRSTRLEN]; zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u", inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])), p->prefixlen, inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])), api.metric); } zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, (struct prefix_ipv6 *) p, &api); } #endif /* HAVE_IPV6 */ } /* Other routes redistribution into BGP. */ int bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type) { /* Set flag to BGP instance. */ bgp->redist[afi][type] = 1; /* Return if already redistribute flag is set. */ if (zclient->redist[type]) return CMD_WARNING; zclient->redist[type] = 1; /* Return if zebra connection is not established. */ if (zclient->sock < 0) return CMD_WARNING; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type)); /* Send distribute add message to zebra. */ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type); return CMD_SUCCESS; } /* Redistribute with route-map specification. */ int bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, const char *name) { if (bgp->rmap[afi][type].name && (strcmp (bgp->rmap[afi][type].name, name) == 0)) return 0; if (bgp->rmap[afi][type].name) free (bgp->rmap[afi][type].name); bgp->rmap[afi][type].name = strdup (name); bgp->rmap[afi][type].map = route_map_lookup_by_name (name); return 1; } /* Redistribute with metric specification. */ int bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type, u_int32_t metric) { if (bgp->redist_metric_flag[afi][type] && bgp->redist_metric[afi][type] == metric) return 0; bgp->redist_metric_flag[afi][type] = 1; bgp->redist_metric[afi][type] = metric; return 1; } /* Unset redistribution. */ int bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type) { /* Unset flag from BGP instance. */ bgp->redist[afi][type] = 0; /* Unset route-map. */ if (bgp->rmap[afi][type].name) free (bgp->rmap[afi][type].name); bgp->rmap[afi][type].name = NULL; bgp->rmap[afi][type].map = NULL; /* Unset metric. */ bgp->redist_metric_flag[afi][type] = 0; bgp->redist_metric[afi][type] = 0; /* Return if zebra connection is disabled. */ if (! zclient->redist[type]) return CMD_WARNING; zclient->redist[type] = 0; if (bgp->redist[AFI_IP][type] == 0 && bgp->redist[AFI_IP6][type] == 0 && zclient->sock >= 0) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Zebra send: redistribute delete %s", zebra_route_string(type)); zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); } /* Withdraw redistributed routes from current BGP's routing table. */ bgp_redistribute_withdraw (bgp, afi, type); return CMD_SUCCESS; } /* Unset redistribution route-map configuration. */ int bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type) { if (! bgp->rmap[afi][type].name) return 0; /* Unset route-map. */ free (bgp->rmap[afi][type].name); bgp->rmap[afi][type].name = NULL; bgp->rmap[afi][type].map = NULL; return 1; } /* Unset redistribution metric configuration. */ int bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type) { if (! bgp->redist_metric_flag[afi][type]) return 0; /* Unset metric. */ bgp->redist_metric_flag[afi][type] = 0; bgp->redist_metric[afi][type] = 0; return 1; } void bgp_zclient_reset (void) { zclient_reset (zclient); } void bgp_zebra_init (void) { /* Set default values. */ zclient = zclient_new (); zclient_init (zclient, ZEBRA_ROUTE_BGP); zclient->router_id_update = bgp_router_id_update; zclient->interface_add = bgp_interface_add; zclient->interface_delete = bgp_interface_delete; zclient->interface_address_add = bgp_interface_address_add; zclient->interface_address_delete = bgp_interface_address_delete; zclient->ipv4_route_add = zebra_read_ipv4; zclient->ipv4_route_delete = zebra_read_ipv4; zclient->interface_up = bgp_interface_up; zclient->interface_down = bgp_interface_down; #ifdef HAVE_IPV6 zclient->ipv6_route_add = zebra_read_ipv6; zclient->ipv6_route_delete = zebra_read_ipv6; #endif /* HAVE_IPV6 */ /* Interface related init. */ if_init (); bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE); } quagga-0.99.24.1/bgpd/bgp_route.c0000644000175000017500000144640412476520570013317 00000000000000/* BGP routing information Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "linklist.h" #include "memory.h" #include "command.h" #include "stream.h" #include "filter.h" #include "str.h" #include "log.h" #include "routemap.h" #include "buffer.h" #include "sockunion.h" #include "plist.h" #include "thread.h" #include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; static struct bgp_node * bgp_afi_node_get (struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_node *prn = NULL; assert (table); if (!table) return NULL; if (safi == SAFI_MPLS_VPN) { prn = bgp_node_get (table, (struct prefix *) prd); if (prn->info == NULL) prn->info = bgp_table_init (afi, safi); else bgp_unlock_node (prn); table = prn->info; } rn = bgp_node_get (table, p); if (safi == SAFI_MPLS_VPN) rn->prn = prn; return rn; } /* Allocate bgp_info_extra */ static struct bgp_info_extra * bgp_info_extra_new (void) { struct bgp_info_extra *new; new = XCALLOC (MTYPE_BGP_ROUTE_EXTRA, sizeof (struct bgp_info_extra)); return new; } static void bgp_info_extra_free (struct bgp_info_extra **extra) { if (extra && *extra) { if ((*extra)->damp_info) bgp_damp_info_free ((*extra)->damp_info, 0); (*extra)->damp_info = NULL; XFREE (MTYPE_BGP_ROUTE_EXTRA, *extra); *extra = NULL; } } /* Get bgp_info extra information for the given bgp_info, lazy allocated * if required. */ struct bgp_info_extra * bgp_info_extra_get (struct bgp_info *ri) { if (!ri->extra) ri->extra = bgp_info_extra_new(); return ri->extra; } /* Allocate new bgp info structure. */ static struct bgp_info * bgp_info_new (void) { return XCALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info)); } /* Free bgp route information. */ static void bgp_info_free (struct bgp_info *binfo) { if (binfo->attr) bgp_attr_unintern (&binfo->attr); bgp_info_extra_free (&binfo->extra); bgp_info_mpath_free (&binfo->mpath); peer_unlock (binfo->peer); /* bgp_info peer reference */ XFREE (MTYPE_BGP_ROUTE, binfo); } struct bgp_info * bgp_info_lock (struct bgp_info *binfo) { binfo->lock++; return binfo; } struct bgp_info * bgp_info_unlock (struct bgp_info *binfo) { assert (binfo && binfo->lock > 0); binfo->lock--; if (binfo->lock == 0) { #if 0 zlog_debug ("%s: unlocked and freeing", __func__); zlog_backtrace (LOG_DEBUG); #endif bgp_info_free (binfo); return NULL; } #if 0 if (binfo->lock == 1) { zlog_debug ("%s: unlocked to 1", __func__); zlog_backtrace (LOG_DEBUG); } #endif return binfo; } void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri) { struct bgp_info *top; top = rn->info; ri->next = rn->info; ri->prev = NULL; if (top) top->prev = ri; rn->info = ri; bgp_info_lock (ri); bgp_lock_node (rn); peer_lock (ri->peer); /* bgp_info peer reference */ } /* Do the actual removal of info from RIB, for use by bgp_process completion callback *only* */ static void bgp_info_reap (struct bgp_node *rn, struct bgp_info *ri) { if (ri->next) ri->next->prev = ri->prev; if (ri->prev) ri->prev->next = ri->next; else rn->info = ri->next; bgp_info_mpath_dequeue (ri); bgp_info_unlock (ri); bgp_unlock_node (rn); } void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri) { bgp_info_set_flag (rn, ri, BGP_INFO_REMOVED); /* set of previous already took care of pcount */ UNSET_FLAG (ri->flags, BGP_INFO_VALID); } /* undo the effects of a previous call to bgp_info_delete; typically called when a route is deleted and then quickly re-added before the deletion has been processed */ static void bgp_info_restore (struct bgp_node *rn, struct bgp_info *ri) { bgp_info_unset_flag (rn, ri, BGP_INFO_REMOVED); /* unset of previous already took care of pcount */ SET_FLAG (ri->flags, BGP_INFO_VALID); } /* Adjust pcount as required */ static void bgp_pcount_adjust (struct bgp_node *rn, struct bgp_info *ri) { struct bgp_table *table; assert (rn && bgp_node_table (rn)); assert (ri && ri->peer && ri->peer->bgp); table = bgp_node_table (rn); /* Ignore 'pcount' for RS-client tables */ if (table->type != BGP_TABLE_MAIN || ri->peer == ri->peer->bgp->peer_self) return; if (BGP_INFO_HOLDDOWN (ri) && CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { UNSET_FLAG (ri->flags, BGP_INFO_COUNTED); /* slight hack, but more robust against errors. */ if (ri->peer->pcount[table->afi][table->safi]) ri->peer->pcount[table->afi][table->safi]--; else { zlog_warn ("%s: Asked to decrement 0 prefix count for peer %s", __func__, ri->peer->host); zlog_backtrace (LOG_WARNING); zlog_warn ("%s: Please report to Quagga bugzilla", __func__); } } else if (!BGP_INFO_HOLDDOWN (ri) && !CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { SET_FLAG (ri->flags, BGP_INFO_COUNTED); ri->peer->pcount[table->afi][table->safi]++; } } /* Set/unset bgp_info flags, adjusting any other state as needed. * This is here primarily to keep prefix-count in check. */ void bgp_info_set_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { SET_FLAG (ri->flags, flag); /* early bath if we know it's not a flag that changes useability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) return; bgp_pcount_adjust (rn, ri); } void bgp_info_unset_flag (struct bgp_node *rn, struct bgp_info *ri, u_int32_t flag) { UNSET_FLAG (ri->flags, flag); /* early bath if we know it's not a flag that changes useability state */ if (!CHECK_FLAG (flag, BGP_INFO_VALID|BGP_INFO_UNUSEABLE)) return; bgp_pcount_adjust (rn, ri); } /* Get MED value. If MED value is missing and "bgp bestpath missing-as-worst" is specified, treat it as the worst value. */ static u_int32_t bgp_med_value (struct attr *attr, struct bgp *bgp) { if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) return attr->med; else { if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) return BGP_MED_MAX; else return 0; } } /* Compare two bgp route entity. br is preferable then return 1. */ static int bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, int *paths_eq) { struct attr *newattr, *existattr; struct attr_extra *newattre, *existattre; bgp_peer_sort_t new_sort; bgp_peer_sort_t exist_sort; u_int32_t new_pref; u_int32_t exist_pref; u_int32_t new_med; u_int32_t exist_med; u_int32_t new_weight; u_int32_t exist_weight; uint32_t newm, existm; struct in_addr new_id; struct in_addr exist_id; int new_cluster; int exist_cluster; int internal_as_route; int confed_as_route; int ret; *paths_eq = 0; /* 0. Null check. */ if (new == NULL) return 0; if (exist == NULL) return 1; newattr = new->attr; existattr = exist->attr; newattre = newattr->extra; existattre = existattr->extra; /* 1. Weight check. */ new_weight = exist_weight = 0; if (newattre) new_weight = newattre->weight; if (existattre) exist_weight = existattre->weight; if (new_weight > exist_weight) return 1; if (new_weight < exist_weight) return 0; /* 2. Local preference check. */ new_pref = exist_pref = bgp->default_local_pref; if (newattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) new_pref = newattr->local_pref; if (existattr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) exist_pref = existattr->local_pref; if (new_pref > exist_pref) return 1; if (new_pref < exist_pref) return 0; /* 3. Local route check. We prefer: * - BGP_ROUTE_STATIC * - BGP_ROUTE_AGGREGATE * - BGP_ROUTE_REDISTRIBUTE */ if (! (new->sub_type == BGP_ROUTE_NORMAL)) return 1; if (! (exist->sub_type == BGP_ROUTE_NORMAL)) return 0; /* 4. AS path length check. */ if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) { int exist_hops = aspath_count_hops (existattr->aspath); int exist_confeds = aspath_count_confeds (existattr->aspath); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) { int aspath_hops; aspath_hops = aspath_count_hops (newattr->aspath); aspath_hops += aspath_count_confeds (newattr->aspath); if ( aspath_hops < (exist_hops + exist_confeds)) return 1; if ( aspath_hops > (exist_hops + exist_confeds)) return 0; } else { int newhops = aspath_count_hops (newattr->aspath); if (newhops < exist_hops) return 1; if (newhops > exist_hops) return 0; } } /* 5. Origin check. */ if (newattr->origin < existattr->origin) return 1; if (newattr->origin > existattr->origin) return 0; /* 6. MED check. */ internal_as_route = (aspath_count_hops (newattr->aspath) == 0 && aspath_count_hops (existattr->aspath) == 0); confed_as_route = (aspath_count_confeds (newattr->aspath) > 0 && aspath_count_confeds (existattr->aspath) > 0 && aspath_count_hops (newattr->aspath) == 0 && aspath_count_hops (existattr->aspath) == 0); if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED) || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) && confed_as_route) || aspath_cmp_left (newattr->aspath, existattr->aspath) || aspath_cmp_left_confed (newattr->aspath, existattr->aspath) || internal_as_route) { new_med = bgp_med_value (new->attr, bgp); exist_med = bgp_med_value (exist->attr, bgp); if (new_med < exist_med) return 1; if (new_med > exist_med) return 0; } /* 7. Peer type check. */ new_sort = new->peer->sort; exist_sort = exist->peer->sort; if (new_sort == BGP_PEER_EBGP && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) return 1; if (exist_sort == BGP_PEER_EBGP && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) return 0; /* 8. IGP metric check. */ newm = existm = 0; if (new->extra) newm = new->extra->igpmetric; if (exist->extra) existm = exist->extra->igpmetric; if (newm < existm) ret = 1; if (newm > existm) ret = 0; /* 9. Maximum path check. */ if (newm == existm) { if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { /* * For the two paths, all comparison steps till IGP metric * have succeeded - including AS_PATH hop count. Since 'bgp * bestpath as-path multipath-relax' knob is on, we don't need * an exact match of AS_PATH. Thus, mark the paths are equal. * That will trigger both these paths to get into the multipath * array. */ *paths_eq = 1; } else if (new->peer->sort == BGP_PEER_IBGP) { if (aspath_cmp (new->attr->aspath, exist->attr->aspath)) *paths_eq = 1; } else if (new->peer->as == exist->peer->as) *paths_eq = 1; } else { /* * TODO: If unequal cost ibgp multipath is enabled we can * mark the paths as equal here instead of returning */ return ret; } /* 10. If both paths are external, prefer the path that was received first (the oldest one). This step minimizes route-flap, since a newer path won't displace an older one, even if it was the preferred route based on the additional decision criteria below. */ if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID) && new_sort == BGP_PEER_EBGP && exist_sort == BGP_PEER_EBGP) { if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED)) return 1; if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED)) return 0; } /* 11. Rourter-ID comparision. */ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) new_id.s_addr = newattre->originator_id.s_addr; else new_id.s_addr = new->peer->remote_id.s_addr; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) exist_id.s_addr = existattre->originator_id.s_addr; else exist_id.s_addr = exist->peer->remote_id.s_addr; if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr)) return 1; if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr)) return 0; /* 12. Cluster length comparision. */ new_cluster = exist_cluster = 0; if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) new_cluster = newattre->cluster->length; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) exist_cluster = existattre->cluster->length; if (new_cluster < exist_cluster) return 1; if (new_cluster > exist_cluster) return 0; /* 13. Neighbor address comparision. */ ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote); if (ret == 1) return 0; if (ret == -1) return 1; return 1; } static enum filter_type bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; filter = &peer->filter[afi][safi]; #define FILTER_EXIST_WARN(F,f,filter) \ if (BGP_DEBUG (update, UPDATE_IN) \ && !(F ## _IN (filter))) \ plog_warn (peer->log, "%s: Could not find configured input %s-list %s!", \ peer->host, #f, F ## _IN_NAME(filter)); if (DISTRIBUTE_IN_NAME (filter)) { FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter); if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY) return FILTER_DENY; } if (PREFIX_LIST_IN_NAME (filter)) { FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter); if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY) return FILTER_DENY; } if (FILTER_LIST_IN_NAME (filter)) { FILTER_EXIST_WARN(FILTER_LIST, as, filter); if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY) return FILTER_DENY; } return FILTER_PERMIT; #undef FILTER_EXIST_WARN } static enum filter_type bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; filter = &peer->filter[afi][safi]; #define FILTER_EXIST_WARN(F,f,filter) \ if (BGP_DEBUG (update, UPDATE_OUT) \ && !(F ## _OUT (filter))) \ plog_warn (peer->log, "%s: Could not find configured output %s-list %s!", \ peer->host, #f, F ## _OUT_NAME(filter)); if (DISTRIBUTE_OUT_NAME (filter)) { FILTER_EXIST_WARN(DISTRIBUTE, distribute, filter); if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY) return FILTER_DENY; } if (PREFIX_LIST_OUT_NAME (filter)) { FILTER_EXIST_WARN(PREFIX_LIST, prefix, filter); if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY) return FILTER_DENY; } if (FILTER_LIST_OUT_NAME (filter)) { FILTER_EXIST_WARN(FILTER_LIST, as, filter); if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY) return FILTER_DENY; } return FILTER_PERMIT; #undef FILTER_EXIST_WARN } /* If community attribute includes no_export then return 1. */ static int bgp_community_filter (struct peer *peer, struct attr *attr) { if (attr->community) { /* NO_ADVERTISE check. */ if (community_include (attr->community, COMMUNITY_NO_ADVERTISE)) return 1; /* NO_EXPORT check. */ if (peer->sort == BGP_PEER_EBGP && community_include (attr->community, COMMUNITY_NO_EXPORT)) return 1; /* NO_EXPORT_SUBCONFED check. */ if (peer->sort == BGP_PEER_EBGP || peer->sort == BGP_PEER_CONFED) if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED)) return 1; } return 0; } /* Route reflection loop check. */ static int bgp_cluster_filter (struct peer *peer, struct attr *attr) { struct in_addr cluster_id; if (attr->extra && attr->extra->cluster) { if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID) cluster_id = peer->bgp->cluster_id; else cluster_id = peer->bgp->router_id; if (cluster_loop_check (attr->extra->cluster, cluster_id)) return 1; } return 0; } static int bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; struct bgp_info info; route_map_result_t ret; filter = &peer->filter[afi][safi]; /* Apply default weight value. */ if (peer->weight) (bgp_attr_extra_get (attr))->weight = peer->weight; /* Route map apply. */ if (ROUTE_MAP_IN_NAME (filter)) { /* Duplicate current value to new strucutre for modification. */ info.peer = peer; info.attr = attr; SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN); /* Apply BGP route map to the attribute. */ ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info); peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) /* caller has multiple error paths with bgp_attr_flush() */ return RMAP_DENY; } return RMAP_PERMIT; } static int bgp_export_modifier (struct peer *rsclient, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; struct bgp_info info; route_map_result_t ret; filter = &peer->filter[afi][safi]; /* Route map apply. */ if (ROUTE_MAP_EXPORT_NAME (filter)) { /* Duplicate current value to new strucutre for modification. */ info.peer = rsclient; info.attr = attr; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); /* Apply BGP route map to the attribute. */ ret = route_map_apply (ROUTE_MAP_EXPORT (filter), p, RMAP_BGP, &info); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free newly generated AS path and community by route-map. */ bgp_attr_flush (attr); return RMAP_DENY; } } return RMAP_PERMIT; } static int bgp_import_modifier (struct peer *rsclient, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { struct bgp_filter *filter; struct bgp_info info; route_map_result_t ret; filter = &rsclient->filter[afi][safi]; /* Apply default weight value. */ if (peer->weight) (bgp_attr_extra_get (attr))->weight = peer->weight; /* Route map apply. */ if (ROUTE_MAP_IMPORT_NAME (filter)) { /* Duplicate current value to new strucutre for modification. */ info.peer = peer; info.attr = attr; SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT); /* Apply BGP route map to the attribute. */ ret = route_map_apply (ROUTE_MAP_IMPORT (filter), p, RMAP_BGP, &info); peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free newly generated AS path and community by route-map. */ bgp_attr_flush (attr); return RMAP_DENY; } } return RMAP_PERMIT; } static int bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { int ret; char buf[SU_ADDRSTRLEN]; struct bgp_filter *filter; struct peer *from; struct bgp *bgp; int transparent; int reflect; struct attr *riattr; from = ri->peer; filter = &peer->filter[afi][safi]; bgp = peer->bgp; riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; /* Do not send announces to RS-clients from the 'normal' bgp_table. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) return 0; /* Do not send back route to sender. */ if (from == peer) return 0; /* Aggregate-address suppress check. */ if (ri->extra && ri->extra->suppress) if (! UNSUPPRESS_MAP_NAME (filter)) return 0; /* Default route check. */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) return 0; #ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; #endif /* HAVE_IPV6 */ } /* Transparency check. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) transparent = 1; else transparent = 0; /* If community is not disabled check the no-export and local. */ if (! transparent && bgp_community_filter (peer, riattr)) return 0; /* If the attribute has originator-id and it is same as remote peer's id. */ if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] %s/%d originator-id is same as remote router-id", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; } } /* ORF prefix-list filter check */ if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) if (peer->orf_plist[afi][safi]) { if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY) return 0; } /* Output filter check. */ if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] %s/%d is filtered", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; } #ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ if (aspath_loop_check (riattr->aspath, peer->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, peer->as); return 0; } #endif /* BGP_SEND_ASPATH_CHECK */ /* If we're a CONFED we need to loop check the CONFED ID too */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { if (aspath_loop_check(riattr->aspath, bgp->confed_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (peer->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", peer->host, bgp->confed_id); return 0; } } /* Route-Reflect check. */ if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) reflect = 1; else reflect = 0; /* IBGP reflection check. */ if (reflect) { /* A route from a Client peer. */ if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) { /* Reflect to all the Non-Client peers and also to the Client peers other than the originator. Originator check is already done. So there is noting to do. */ /* no bgp client-to-client reflection check. */ if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) return 0; } else { /* A route from a Non-client peer. Reflect to all other clients. */ if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) return 0; } } /* For modify attribute, copy it to temporary structure. */ bgp_attr_dup (attr, riattr); /* If local-preference is not set. */ if ((peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))) { attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); attr->local_pref = bgp->default_local_pref; } /* If originator-id is not set and the route is to be reflected, set the originator id */ if (peer && from && peer->sort == BGP_PEER_IBGP && from->sort == BGP_PEER_IBGP && (! (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)))) { attr->extra = bgp_attr_extra_get(attr); IPV4_ADDR_COPY(&(attr->extra->originator_id), &(from->remote_id)); SET_FLAG(attr->flag, BGP_ATTR_ORIGINATOR_ID); } /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ if (peer->sort == BGP_PEER_EBGP && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) { if (ri->peer != bgp->peer_self && ! transparent && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)); } /* next-hop-set */ if (transparent || (reflect && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF_ALL)) || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && ((p->family == AF_INET && attr->nexthop.s_addr) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && ! IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ))) { /* NEXT-HOP Unchanged. */ } else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF) || (p->family == AF_INET && attr->nexthop.s_addr == 0) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ || (peer->sort == BGP_PEER_EBGP && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0)) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) memcpy (&attr->extra->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); } #ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ if (p->family == AF_INET6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &peer->nexthop.v6_global, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) { if ( IN6_IS_ADDR_LINKLOCAL (&attr->extra->mp_nexthop_local) ) attr->extra->mp_nexthop_len=32; else attr->extra->mp_nexthop_len=16; } /* Default nexthop_local treatment for non-RS-Clients */ else { /* Link-local address should not be transit to different peer. */ attr->extra->mp_nexthop_len = 16; /* Set link-local address for shared network peer. */ if (peer->shared_network && ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) { memcpy (&attr->extra->mp_nexthop_local, &peer->nexthop.v6_local, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 32; } /* If bgpd act as BGP-4+ route-reflector, do not send link-local address.*/ if (reflect) attr->extra->mp_nexthop_len = 16; /* If BGP-4+ link-local nexthop is not link-local nexthop. */ if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local)) attr->extra->mp_nexthop_len = 16; } } #endif /* HAVE_IPV6 */ /* If this is EBGP peer and remove-private-AS is set. */ if (peer->sort == BGP_PEER_EBGP && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && aspath_private_as_check (attr->aspath)) attr->aspath = aspath_empty_get (); /* Route map & unsuppress-map apply. */ if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) ) { struct bgp_info info; struct attr dummy_attr; struct attr_extra dummy_extra; dummy_attr.extra = &dummy_extra; info.peer = peer; info.attr = attr; /* The route reflector is not allowed to modify the attributes of the reflected IBGP routes. */ if (from->sort == BGP_PEER_IBGP && peer->sort == BGP_PEER_IBGP) { bgp_attr_dup (&dummy_attr, attr); info.attr = &dummy_attr; } SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->suppress) ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); else ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); peer->rmap_type = 0; if (ret == RMAP_DENYMATCH) { bgp_attr_flush (attr); return 0; } } return 1; } static int bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi) { int ret; char buf[SU_ADDRSTRLEN]; struct bgp_filter *filter; struct bgp_info info; struct peer *from; struct attr *riattr; from = ri->peer; filter = &rsclient->filter[afi][safi]; riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr; if (DISABLE_BGP_ANNOUNCE) return 0; /* Do not send back route to sender. */ if (from == rsclient) return 0; /* Aggregate-address suppress check. */ if (ri->extra && ri->extra->suppress) if (! UNSUPPRESS_MAP_NAME (filter)) return 0; /* Default route check. */ if (CHECK_FLAG (rsclient->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) return 0; #ifdef HAVE_IPV6 else if (p->family == AF_INET6 && p->prefixlen == 0) return 0; #endif /* HAVE_IPV6 */ } /* If the attribute has originator-id and it is same as remote peer's id. */ if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)) { if (IPV4_ADDR_SAME (&rsclient->remote_id, &riattr->extra->originator_id)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] %s/%d originator-id is same as remote router-id", rsclient->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; } } /* ORF prefix-list filter check */ if (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV) && (CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (rsclient->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))) if (rsclient->orf_plist[afi][safi]) { if (prefix_list_apply (rsclient->orf_plist[afi][safi], p) == PREFIX_DENY) return 0; } /* Output filter check. */ if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] %s/%d is filtered", rsclient->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); return 0; } #ifdef BGP_SEND_ASPATH_CHECK /* AS path loop check. */ if (aspath_loop_check (riattr->aspath, rsclient->as)) { if (BGP_DEBUG (filter, FILTER)) zlog (rsclient->log, LOG_DEBUG, "%s [Update:SEND] suppress announcement to peer AS %u is AS path.", rsclient->host, rsclient->as); return 0; } #endif /* BGP_SEND_ASPATH_CHECK */ /* For modify attribute, copy it to temporary structure. */ bgp_attr_dup (attr, riattr); /* next-hop-set */ if ((p->family == AF_INET && attr->nexthop.s_addr == 0) #ifdef HAVE_IPV6 || (p->family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&attr->extra->mp_nexthop_global)) #endif /* HAVE_IPV6 */ ) { /* Set IPv4 nexthop. */ if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) memcpy (&attr->extra->mp_nexthop_global_in, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); else memcpy (&attr->nexthop, &rsclient->nexthop.v4, IPV4_MAX_BYTELEN); } #ifdef HAVE_IPV6 /* Set IPv6 nexthop. */ if (p->family == AF_INET6) { /* IPv6 global nexthop must be included. */ memcpy (&attr->extra->mp_nexthop_global, &rsclient->nexthop.v6_global, IPV6_MAX_BYTELEN); attr->extra->mp_nexthop_len = 16; } #endif /* HAVE_IPV6 */ } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { struct attr_extra *attre = attr->extra; /* Left nexthop_local unchanged if so configured. */ if ( CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) ) { if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) attre->mp_nexthop_len=32; else attre->mp_nexthop_len=16; } /* Default nexthop_local treatment for RS-Clients */ else { /* Announcer and RS-Client are both in the same network */ if (rsclient->shared_network && from->shared_network && (rsclient->ifindex == from->ifindex)) { if ( IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local) ) attre->mp_nexthop_len=32; else attre->mp_nexthop_len=16; } /* Set link-local address for shared network peer. */ else if (rsclient->shared_network && IN6_IS_ADDR_LINKLOCAL (&rsclient->nexthop.v6_local)) { memcpy (&attre->mp_nexthop_local, &rsclient->nexthop.v6_local, IPV6_MAX_BYTELEN); attre->mp_nexthop_len = 32; } else attre->mp_nexthop_len = 16; } } #endif /* HAVE_IPV6 */ /* If this is EBGP peer and remove-private-AS is set. */ if (rsclient->sort == BGP_PEER_EBGP && peer_af_flag_check (rsclient, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && aspath_private_as_check (attr->aspath)) attr->aspath = aspath_empty_get (); /* Route map & unsuppress-map apply. */ if (ROUTE_MAP_OUT_NAME (filter) || (ri->extra && ri->extra->suppress) ) { info.peer = rsclient; info.attr = attr; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_OUT); if (ri->extra && ri->extra->suppress) ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info); else ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { bgp_attr_flush (attr); return 0; } } return 1; } struct bgp_info_pair { struct bgp_info *old; struct bgp_info *new; }; static void bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, struct bgp_maxpaths_cfg *mpath_cfg, struct bgp_info_pair *result) { struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info *ri; struct bgp_info *ri1; struct bgp_info *ri2; struct bgp_info *nextri = NULL; int paths_eq, do_mpath; struct list mp_list; bgp_mp_list_init (&mp_list); do_mpath = (mpath_cfg->maxpaths_ebgp != BGP_DEFAULT_MAXPATHS || mpath_cfg->maxpaths_ibgp != BGP_DEFAULT_MAXPATHS); /* bgp deterministic-med */ new_select = NULL; if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) for (ri1 = rn->info; ri1; ri1 = ri1->next) { if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK)) continue; if (BGP_INFO_HOLDDOWN (ri1)) continue; new_select = ri1; if (do_mpath) bgp_mp_list_add (&mp_list, ri1); old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL; if (ri1->next) for (ri2 = ri1->next; ri2; ri2 = ri2->next) { if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK)) continue; if (BGP_INFO_HOLDDOWN (ri2)) continue; if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath) || aspath_cmp_left_confed (ri1->attr->aspath, ri2->attr->aspath)) { if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED)) old_select = ri2; if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq)) { bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED); new_select = ri2; if (do_mpath && !paths_eq) { bgp_mp_list_clear (&mp_list); bgp_mp_list_add (&mp_list, ri2); } } if (do_mpath && paths_eq) bgp_mp_list_add (&mp_list, ri2); bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK); } } bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK); bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED); bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); bgp_mp_list_clear (&mp_list); } /* Check old selected route and new selected route. */ old_select = NULL; new_select = NULL; for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) { if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) old_select = ri; if (BGP_INFO_HOLDDOWN (ri)) { /* reap REMOVED routes, if needs be * selected route must stay for a while longer though */ if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && (ri != old_select)) bgp_info_reap (rn, ri); continue; } if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED))) { bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); continue; } bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_CHECK); bgp_info_unset_flag (rn, ri, BGP_INFO_DMED_SELECTED); if (bgp_info_cmp (bgp, ri, new_select, &paths_eq)) { if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (new_select); new_select = ri; if (do_mpath && !paths_eq) { bgp_mp_list_clear (&mp_list); bgp_mp_list_add (&mp_list, ri); } } else if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_mp_dmed_deselect (ri); if (do_mpath && paths_eq) bgp_mp_list_add (&mp_list, ri); } if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg); bgp_info_mpath_aggregate_update (new_select, old_select); bgp_mp_list_clear (&mp_list); result->old = old_select; result->new = new_select; return; } static int bgp_process_announce_selected (struct peer *peer, struct bgp_info *selected, struct bgp_node *rn, afi_t afi, safi_t safi) { struct prefix *p; struct attr attr; struct attr_extra extra; p = &rn->p; /* Announce route to Established peer. */ if (peer->status != Established) return 0; /* Address family configuration check. */ if (! peer->afc_nego[afi][safi]) return 0; /* First update is deferred until ORF or ROUTE-REFRESH is received */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) return 0; /* It's initialized in bgp_announce_[check|check_rsclient]() */ attr.extra = &extra; switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: /* Announcement to peer->conf. If the route is filtered, withdraw it. */ if (selected && bgp_announce_check (selected, peer, p, &attr, afi, safi)) bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); else bgp_adj_out_unset (rn, peer, p, afi, safi); break; case BGP_TABLE_RSCLIENT: /* Announcement to peer->conf. If the route is filtered, withdraw it. */ if (selected && bgp_announce_check_rsclient (selected, peer, p, &attr, afi, safi)) bgp_adj_out_set (rn, peer, p, &attr, afi, safi, selected); else bgp_adj_out_unset (rn, peer, p, afi, safi); break; } return 0; } struct bgp_process_queue { struct bgp *bgp; struct bgp_node *rn; afi_t afi; safi_t safi; }; static wq_item_status bgp_process_rsclient (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp *bgp = pq->bgp; struct bgp_node *rn = pq->rn; afi_t afi = pq->afi; safi_t safi = pq->safi; struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; struct listnode *node, *nnode; struct peer *rsclient = bgp_node_table (rn)->owner; /* Best path selection. */ bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); new_select = old_and_new.new; old_select = old_and_new.old; if (CHECK_FLAG (rsclient->sflags, PEER_STATUS_GROUP)) { if (rsclient->group) for (ALL_LIST_ELEMENTS (rsclient->group->peer, node, nnode, rsclient)) { /* Nothing to do. */ if (old_select && old_select == new_select) if (!CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) continue; if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); } } else { if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } bgp_process_announce_selected (rsclient, new_select, rn, afi, safi); } if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } static wq_item_status bgp_process_main (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp *bgp = pq->bgp; struct bgp_node *rn = pq->rn; afi_t afi = pq->afi; safi_t safi = pq->safi; struct prefix *p = &rn->p; struct bgp_info *new_select; struct bgp_info *old_select; struct bgp_info_pair old_and_new; struct listnode *node, *nnode; struct peer *peer; /* Best path selection. */ bgp_best_selection (bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new); old_select = old_and_new.old; new_select = old_and_new.new; /* Nothing to do. */ if (old_select && old_select == new_select) { if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED)) { if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG)) bgp_zebra_announce (p, old_select, bgp, safi); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } } if (old_select) bgp_info_unset_flag (rn, old_select, BGP_INFO_SELECTED); if (new_select) { bgp_info_set_flag (rn, new_select, BGP_INFO_SELECTED); bgp_info_unset_flag (rn, new_select, BGP_INFO_ATTR_CHANGED); UNSET_FLAG (new_select->flags, BGP_INFO_MULTIPATH_CHG); } /* Check each BGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { bgp_process_announce_selected (peer, new_select, rn, afi, safi); } /* FIB update. */ if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name && ! bgp_option_check (BGP_OPT_NO_FIB))) { if (new_select && new_select->type == ZEBRA_ROUTE_BGP && new_select->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_announce (p, new_select, bgp, safi); else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_withdraw (p, old_select, safi); } } /* Reap old select bgp_info, it it has been removed */ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } static void bgp_processq_del (struct work_queue *wq, void *data) { struct bgp_process_queue *pq = data; struct bgp_table *table = bgp_node_table (pq->rn); bgp_unlock (pq->bgp); bgp_unlock_node (pq->rn); bgp_table_unlock (table); XFREE (MTYPE_BGP_PROCESS_QUEUE, pq); } static void bgp_process_queue_init (void) { bm->process_main_queue = work_queue_new (bm->master, "process_main_queue"); bm->process_rsclient_queue = work_queue_new (bm->master, "process_rsclient_queue"); if ( !(bm->process_main_queue && bm->process_rsclient_queue) ) { zlog_err ("%s: Failed to allocate work queue", __func__); exit (1); } bm->process_main_queue->spec.workfunc = &bgp_process_main; bm->process_main_queue->spec.del_item_data = &bgp_processq_del; bm->process_main_queue->spec.max_retries = 0; bm->process_main_queue->spec.hold = 50; memcpy (bm->process_rsclient_queue, bm->process_main_queue, sizeof (struct work_queue *)); bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient; } void bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi) { struct bgp_process_queue *pqnode; /* already scheduled for processing? */ if (CHECK_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED)) return; if ( (bm->process_main_queue == NULL) || (bm->process_rsclient_queue == NULL) ) bgp_process_queue_init (); pqnode = XCALLOC (MTYPE_BGP_PROCESS_QUEUE, sizeof (struct bgp_process_queue)); if (!pqnode) return; /* all unlocked in bgp_processq_del */ bgp_table_lock (bgp_node_table (rn)); pqnode->rn = bgp_lock_node (rn); pqnode->bgp = bgp; bgp_lock (bgp); pqnode->afi = afi; pqnode->safi = safi; switch (bgp_node_table (rn)->type) { case BGP_TABLE_MAIN: work_queue_add (bm->process_main_queue, pqnode); break; case BGP_TABLE_RSCLIENT: work_queue_add (bm->process_rsclient_queue, pqnode); break; } SET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return; } static int bgp_maximum_prefix_restart_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_pmax_restart = NULL; if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Maximum-prefix restart timer expired, restore peering", peer->host); peer_clear (peer); return 0; } int bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi, int always) { if (!CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) return 0; if (peer->pcount[afi][safi] > peer->pmax[afi][safi]) { if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT) && ! always) return 0; zlog (peer->log, LOG_INFO, "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, " "limit %ld", afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) return 0; { u_int8_t ndata[7]; if (safi == SAFI_MPLS_VPN) safi = SAFI_MPLS_LABELED_VPN; ndata[0] = (afi >> 8); ndata[1] = afi; ndata[2] = safi; ndata[3] = (peer->pmax[afi][safi] >> 24); ndata[4] = (peer->pmax[afi][safi] >> 16); ndata[5] = (peer->pmax[afi][safi] >> 8); ndata[6] = (peer->pmax[afi][safi]); SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7); } /* restart timer start */ if (peer->pmax_restart[afi][safi]) { peer->v_pmax_restart = peer->pmax_restart[afi][safi] * 60; if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Maximum-prefix restart timer started for %d secs", peer->host, peer->v_pmax_restart); BGP_TIMER_ON (peer->t_pmax_restart, bgp_maximum_prefix_restart_timer, peer->v_pmax_restart); } return 1; } else UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT); if (peer->pcount[afi][safi] > (peer->pmax[afi][safi] * peer->pmax_threshold[afi][safi] / 100)) { if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD) && ! always) return 0; zlog (peer->log, LOG_INFO, "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld", afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi], peer->pmax[afi][safi]); SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD); } else UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD); return 0; } /* Unconditionally remove the route from the RIB, without taking * damping into consideration (eg, because the session went down) */ static void bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, afi_t afi, safi_t safi) { bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); if (!CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_info_delete (rn, ri); /* keep historical info */ bgp_process (peer->bgp, rn, afi, safi); } static void bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer, afi_t afi, safi_t safi) { int status = BGP_DAMP_NONE; /* apply dampening, if result is suppressed, we'll be retaining * the bgp_info in the RIB for historical reference. */ if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP) if ( (status = bgp_damp_withdraw (ri, rn, afi, safi, 0)) == BGP_DAMP_SUPPRESSED) { bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi); return; } bgp_rib_remove (rn, ri, peer, afi, safi); } static void bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct attr *attr, struct peer *peer, struct prefix *p, int type, int sub_type, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp *bgp; struct attr new_attr; struct attr_extra new_extra; struct attr *attr_new; struct attr *attr_new2; struct bgp_info *ri; struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; /* Do not insert announces from a rsclient into its own 'bgp_table'. */ if (peer == rsclient) return; bgp = peer->bgp; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); /* Check previously received route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) break; /* AS path loop check. */ if (aspath_loop_check (attr->aspath, rsclient->as) > rsclient->allowas_in[afi][safi]) { reason = "as-path contains our own AS;"; goto filtered; } /* Route reflector originator ID check. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) && IPV4_ADDR_SAME (&rsclient->remote_id, &attr->extra->originator_id)) { reason = "originator is us;"; goto filtered; } new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply export policy. */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && bgp_export_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "export-policy;"; goto filtered; } attr_new2 = bgp_attr_intern (&new_attr); /* Apply import policy. */ if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY) { bgp_attr_unintern (&attr_new2); reason = "import-policy;"; goto filtered; } attr_new = bgp_attr_intern (&new_attr); bgp_attr_unintern (&attr_new2); /* IPv4 unicast next hop check. */ if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST)) { /* Next hop must not be 0.0.0.0 nor Class D/E address. */ if (new_attr.nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr))) { bgp_attr_unintern (&attr_new); reason = "martian next-hop;"; goto filtered; } } /* If the update is implicit withdraw. */ if (ri) { ri->uptime = bgp_clock (); /* Same attribute comes in. */ if (!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s...duplicate ignored", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); return; } /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore (rn, ri); /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Update to new attribute. */ bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); return; } /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) { zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d for RS-client %s", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); } /* Make new BGP info. */ new = bgp_info_new (); new->type = type; new->sub_type = sub_type; new->peer = peer; new->attr = attr_new; new->uptime = bgp_clock (); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); return; filtered: /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- DENIED for RS-client %s due to: %s", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host, reason); if (ri) bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); return; } static void bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct peer *peer, struct prefix *p, int type, int sub_type, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; char buf[SU_ADDRSTRLEN]; if (rsclient == peer) return; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, prd); /* Lookup withdrawn route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) break; /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s Can't find the route %s/%d", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* Unlock bgp_node_get() lock. */ bgp_unlock_node (rn); } static int bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag, int soft_reconfig) { int ret; int aspath_loop_count = 0; struct bgp_node *rn; struct bgp *bgp; struct attr new_attr; struct attr_extra new_extra; struct attr *attr_new; struct bgp_info *ri; struct bgp_info *new; const char *reason; char buf[SU_ADDRSTRLEN]; bgp = peer->bgp; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ if (! soft_reconfig && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) bgp_adj_in_set (rn, peer, attr); /* Check previously received route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) break; /* AS path local-as loop check. */ if (peer->change_local_as) { if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) aspath_loop_count = 1; if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count) { reason = "as-path contains our own AS;"; goto filtered; } } /* AS path loop check. */ if (aspath_loop_check (attr->aspath, bgp->as) > peer->allowas_in[afi][safi] || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) && aspath_loop_check(attr->aspath, bgp->confed_id) > peer->allowas_in[afi][safi])) { reason = "as-path contains our own AS;"; goto filtered; } /* Route reflector originator ID check. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID) && IPV4_ADDR_SAME (&bgp->router_id, &attr->extra->originator_id)) { reason = "originator is us;"; goto filtered; } /* Route reflector cluster ID check. */ if (bgp_cluster_filter (peer, attr)) { reason = "reflected from the same cluster;"; goto filtered; } /* Apply incoming filter. */ if (bgp_input_filter (peer, p, attr, afi, safi) == FILTER_DENY) { reason = "filter;"; goto filtered; } new_attr.extra = &new_extra; bgp_attr_dup (&new_attr, attr); /* Apply incoming route-map. * NB: new_attr may now contain newly allocated values from route-map "set" * commands, so we need bgp_attr_flush in the error paths, until we intern * the attr (which takes over the memory references) */ if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY) { reason = "route-map;"; bgp_attr_flush (&new_attr); goto filtered; } /* IPv4 unicast next hop check. */ if (afi == AFI_IP && safi == SAFI_UNICAST) { /* If the peer is EBGP and nexthop is not on connected route, discard it. */ if (peer->sort == BGP_PEER_EBGP && peer->ttl == 1 && ! bgp_nexthop_onlink (afi, &new_attr) && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) { reason = "non-connected next-hop;"; bgp_attr_flush (&new_attr); goto filtered; } /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop must not be my own address. */ if (new_attr.nexthop.s_addr == 0 || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)) || bgp_nexthop_self (&new_attr)) { reason = "martian next-hop;"; bgp_attr_flush (&new_attr); goto filtered; } } attr_new = bgp_attr_intern (&new_attr); /* If the update is implicit withdraw. */ if (ri) { ri->uptime = bgp_clock (); /* Same attribute comes in. */ if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED) && attrhash_cmp (ri->attr, attr_new)) { bgp_info_unset_flag (rn, ri, BGP_INFO_ATTR_CHANGED); if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); if (bgp_damp_update (ri, rn, afi, safi) != BGP_DAMP_SUPPRESSED) { bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); } } else /* Duplicate - odd */ { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d...duplicate ignored", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) { bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); bgp_process (bgp, rn, afi, safi); } } bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); return 0; } /* Withdraw/Announce before we fully processed the withdraw */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d, flapped quicker than processing", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); bgp_info_restore (rn, ri); } /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* graceful restart STALE flag unset. */ if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) bgp_info_unset_flag (rn, ri, BGP_INFO_STALE); /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* implicit withdraw, decrement aggregate and pcount here. * only if update is accepted, they'll increment below. */ bgp_aggregate_decrement (bgp, p, ri, afi, safi); /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP) { /* This is implicit withdraw so we should update dampening information. */ if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_damp_withdraw (ri, rn, afi, safi, 1); } /* Update to new attribute. */ bgp_attr_unintern (&ri->attr); ri->attr = attr_new; /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (ri))->tag, tag, 3); /* Update bgp route dampening information. */ if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) && peer->sort == BGP_PEER_EBGP) { /* Now we do normal update dampening. */ ret = bgp_damp_update (ri, rn, afi, safi); if (ret == BGP_DAMP_SUPPRESSED) { bgp_unlock_node (rn); return 0; } } /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST && (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL)) bgp_info_set_flag (rn, ri, BGP_INFO_VALID); else bgp_info_unset_flag (rn, ri, BGP_INFO_VALID); } else bgp_info_set_flag (rn, ri, BGP_INFO_VALID); /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); return 0; } /* Received Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) { zlog (peer->log, LOG_DEBUG, "%s rcvd %s/%d", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } /* Make new BGP info. */ new = bgp_info_new (); new->type = type; new->sub_type = sub_type; new->peer = peer; new->attr = attr_new; new->uptime = bgp_clock (); /* Update MPLS tag. */ if (safi == SAFI_MPLS_VPN) memcpy ((bgp_info_extra_get (new))->tag, tag, 3); /* Nexthop reachability check. */ if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST && (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || (peer->sort == BGP_PEER_EBGP && peer->ttl != 1) || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))) { if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL)) bgp_info_set_flag (rn, new, BGP_INFO_VALID); else bgp_info_unset_flag (rn, new, BGP_INFO_VALID); } else bgp_info_set_flag (rn, new, BGP_INFO_VALID); /* Increment prefix */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* If maximum prefix count is configured and current prefix count exeed it. */ if (bgp_maximum_prefix_overflow (peer, afi, safi, 0)) return -1; /* Process change. */ bgp_process (bgp, rn, afi, safi); return 0; /* This BGP update is filtered. Log the reason then update BGP entry. */ filtered: if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- DENIED due to: %s", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, reason); if (ri) bgp_rib_remove (rn, ri, peer, afi, safi); bgp_unlock_node (rn); return 0; } int bgp_update (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag, int soft_reconfig) { struct peer *rsclient; struct listnode *node, *nnode; struct bgp *bgp; int ret; ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag, soft_reconfig); bgp = peer->bgp; /* Process the update for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type, sub_type, prd, tag); } return ret; } int bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, u_char *tag) { struct bgp *bgp; char buf[SU_ADDRSTRLEN]; struct bgp_node *rn; struct bgp_info *ri; struct peer *rsclient; struct listnode *node, *nnode; bgp = peer->bgp; /* Process the withdraw for each RS-client. */ for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd, tag); } /* Logging. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE about %s/%d -- withdrawn", peer->host, inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* Lookup node. */ rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* If peer is soft reconfiguration enabled. Record input packet for further calculation. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG) && peer != bgp->peer_self) bgp_adj_in_unset (rn, peer); /* Lookup withdrawn route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type) break; /* Withdraw specified route from routing table. */ if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) bgp_rib_withdraw (rn, ri, peer, afi, safi); else if (BGP_DEBUG (update, UPDATE_IN)) zlog (peer->log, LOG_DEBUG, "%s Can't find the route %s/%d", peer->host, inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); /* Unlock bgp_node_get() lock. */ bgp_unlock_node (rn); return 0; } void bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw) { struct bgp *bgp; struct attr attr; struct aspath *aspath; struct prefix p; struct peer *from; struct bgp_node *rn; struct bgp_info *ri; int ret = RMAP_DENYMATCH; if (!(afi == AFI_IP || afi == AFI_IP6)) return; bgp = peer->bgp; from = bgp->peer_self; bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); aspath = attr.aspath; attr.local_pref = bgp->default_local_pref; memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN); if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p); #ifdef HAVE_IPV6 else if (afi == AFI_IP6) { struct attr_extra *ae = attr.extra; str2prefix ("::/0", &p); /* IPv6 global nexthop must be included. */ memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global, IPV6_MAX_BYTELEN); ae->mp_nexthop_len = 16; /* If the peer is on shared nextwork and we have link-local nexthop set it. */ if (peer->shared_network && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local)) { memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local, IPV6_MAX_BYTELEN); ae->mp_nexthop_len = 32; } } #endif /* HAVE_IPV6 */ if (peer->default_rmap[afi][safi].name) { SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT); for (rn = bgp_table_top(bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) { for (ri = rn->info; ri; ri = ri->next) { struct attr dummy_attr; struct attr_extra dummy_extra; struct bgp_info info; /* Provide dummy so the route-map can't modify the attributes */ dummy_attr.extra = &dummy_extra; bgp_attr_dup(&dummy_attr, ri->attr); info.peer = ri->peer; info.attr = &dummy_attr; ret = route_map_apply(peer->default_rmap[afi][safi].map, &rn->p, RMAP_BGP, &info); /* The route map might have set attributes. If we don't flush them * here, they will be leaked. */ bgp_attr_flush(&dummy_attr); if (ret != RMAP_DENYMATCH) break; } if (ret != RMAP_DENYMATCH) break; } bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) withdraw = 1; } if (withdraw) { if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) bgp_default_withdraw_send (peer, afi, safi); UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); } else { if (! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE); bgp_default_update_send (peer, &attr, afi, safi, from); } } bgp_attr_extra_free (&attr); aspath_unintern (&aspath); } static void bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, int rsclient) { struct bgp_node *rn; struct bgp_info *ri; struct attr attr; struct attr_extra extra; if (! table) table = (rsclient) ? peer->rib[afi][safi] : peer->bgp->rib[afi][safi]; if (safi != SAFI_MPLS_VPN && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) bgp_default_originate (peer, afi, safi, 0); /* It's initialized in bgp_announce_[check|check_rsclient]() */ attr.extra = &extra; for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer) { if ( (rsclient) ? (bgp_announce_check_rsclient (ri, peer, &rn->p, &attr, afi, safi)) : (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi))) bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri); else bgp_adj_out_unset (rn, peer, &rn->p, afi, safi); } } void bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_table *table; if (peer->status != Established) return; if (! peer->afc_nego[afi][safi]) return; /* First update is deferred until ORF or ROUTE-REFRESH is received */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) return; if (safi != SAFI_MPLS_VPN) bgp_announce_table (peer, afi, safi, NULL, 0); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next(rn)) if ((table = (rn->info)) != NULL) bgp_announce_table (peer, afi, safi, table, 0); if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_announce_table (peer, afi, safi, NULL, 1); } void bgp_announce_route_all (struct peer *peer) { afi_t afi; safi_t safi; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) bgp_announce_route (peer, afi, safi); } static void bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) { struct bgp_node *rn; struct bgp_adj_in *ain; if (! table) table = rsclient->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain; ain = ain->next) { struct bgp_info *ri = rn->info; u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer, &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag); } } void bgp_soft_reconfig_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) { struct bgp_table *table; struct bgp_node *rn; if (safi != SAFI_MPLS_VPN) bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, NULL, NULL); else for (rn = bgp_table_top (rsclient->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) { struct prefix_rd prd; prd.family = AF_UNSPEC; prd.prefixlen = 64; memcpy(&prd.val, rn->p.u.val, 8); bgp_soft_reconfig_table_rsclient (rsclient, afi, safi, table, &prd); } } static void bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd) { int ret; struct bgp_node *rn; struct bgp_adj_in *ain; if (! table) table = peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain; ain = ain->next) { if (ain->peer == peer) { struct bgp_info *ri = rn->info; u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL; ret = bgp_update (peer, &rn->p, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag, 1); if (ret < 0) { bgp_unlock_node (rn); return; } continue; } } } void bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_table *table; if (peer->status != Established) return; if (safi != SAFI_MPLS_VPN) bgp_soft_reconfig_table (peer, afi, safi, NULL, NULL); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) { struct prefix_rd prd; prd.family = AF_UNSPEC; prd.prefixlen = 64; memcpy(&prd.val, rn->p.u.val, 8); bgp_soft_reconfig_table (peer, afi, safi, table, &prd); } } struct bgp_clear_node_queue { struct bgp_node *rn; enum bgp_clear_route_type purpose; }; static wq_item_status bgp_clear_route_node (struct work_queue *wq, void *data) { struct bgp_clear_node_queue *cnq = data; struct bgp_node *rn = cnq->rn; struct peer *peer = wq->spec.data; struct bgp_info *ri; afi_t afi = bgp_node_table (rn)->afi; safi_t safi = bgp_node_table (rn)->safi; assert (rn && peer); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || cnq->purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { /* graceful restart STALE flag set. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT) && peer->nsf[afi][safi] && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE) && ! CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) bgp_info_set_flag (rn, ri, BGP_INFO_STALE); else bgp_rib_remove (rn, ri, peer, afi, safi); break; } return WQ_SUCCESS; } static void bgp_clear_node_queue_del (struct work_queue *wq, void *data) { struct bgp_clear_node_queue *cnq = data; struct bgp_node *rn = cnq->rn; struct bgp_table *table = bgp_node_table (rn); bgp_unlock_node (rn); bgp_table_unlock (table); XFREE (MTYPE_BGP_CLEAR_NODE_QUEUE, cnq); } static void bgp_clear_node_complete (struct work_queue *wq) { struct peer *peer = wq->spec.data; /* Tickle FSM to start moving again */ BGP_EVENT_ADD (peer, Clearing_Completed); peer_unlock (peer); /* bgp_clear_route */ } static void bgp_clear_node_queue_init (struct peer *peer) { char wname[sizeof("clear xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")]; snprintf (wname, sizeof(wname), "clear %s", peer->host); #undef CLEAR_QUEUE_NAME_LEN if ( (peer->clear_node_queue = work_queue_new (bm->master, wname)) == NULL) { zlog_err ("%s: Failed to allocate work queue", __func__); exit (1); } peer->clear_node_queue->spec.hold = 10; peer->clear_node_queue->spec.workfunc = &bgp_clear_route_node; peer->clear_node_queue->spec.del_item_data = &bgp_clear_node_queue_del; peer->clear_node_queue->spec.completion_func = &bgp_clear_node_complete; peer->clear_node_queue->spec.max_retries = 0; /* we only 'lock' this peer reference when the queue is actually active */ peer->clear_node_queue->spec.data = peer; } static void bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi, struct bgp_table *table, struct peer *rsclient, enum bgp_clear_route_type purpose) { struct bgp_node *rn; if (! table) table = (rsclient) ? rsclient->rib[afi][safi] : peer->bgp->rib[afi][safi]; /* If still no table => afi/safi isn't configured at all or smth. */ if (! table) return; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { struct bgp_info *ri; struct bgp_adj_in *ain; struct bgp_adj_out *aout; /* XXX:TODO: This is suboptimal, every non-empty route_node is * queued for every clearing peer, regardless of whether it is * relevant to the peer at hand. * * Overview: There are 3 different indices which need to be * scrubbed, potentially, when a peer is removed: * * 1 peer's routes visible via the RIB (ie accepted routes) * 2 peer's routes visible by the (optional) peer's adj-in index * 3 other routes visible by the peer's adj-out index * * 3 there is no hurry in scrubbing, once the struct peer is * removed from bgp->peer, we could just GC such deleted peer's * adj-outs at our leisure. * * 1 and 2 must be 'scrubbed' in some way, at least made * invisible via RIB index before peer session is allowed to be * brought back up. So one needs to know when such a 'search' is * complete. * * Ideally: * * - there'd be a single global queue or a single RIB walker * - rather than tracking which route_nodes still need to be * examined on a peer basis, we'd track which peers still * aren't cleared * * Given that our per-peer prefix-counts now should be reliable, * this may actually be achievable. It doesn't seem to be a huge * problem at this time, */ for (ain = rn->adj_in; ain; ain = ain->next) if (ain->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_in_remove (rn, ain); bgp_unlock_node (rn); break; } for (aout = rn->adj_out; aout; aout = aout->next) if (aout->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { bgp_adj_out_remove (rn, aout, peer, afi, safi); bgp_unlock_node (rn); break; } for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer || purpose == BGP_CLEAR_ROUTE_MY_RSCLIENT) { struct bgp_clear_node_queue *cnq; /* both unlocked in bgp_clear_node_queue_del */ bgp_table_lock (bgp_node_table (rn)); bgp_lock_node (rn); cnq = XCALLOC (MTYPE_BGP_CLEAR_NODE_QUEUE, sizeof (struct bgp_clear_node_queue)); cnq->rn = rn; cnq->purpose = purpose; work_queue_add (peer->clear_node_queue, cnq); break; } } return; } void bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi, enum bgp_clear_route_type purpose) { struct bgp_node *rn; struct bgp_table *table; struct peer *rsclient; struct listnode *node, *nnode; if (peer->clear_node_queue == NULL) bgp_clear_node_queue_init (peer); /* bgp_fsm.c keeps sessions in state Clearing, not transitioning to * Idle until it receives a Clearing_Completed event. This protects * against peers which flap faster than we can we clear, which could * lead to: * * a) race with routes from the new session being installed before * clear_route_node visits the node (to delete the route of that * peer) * b) resource exhaustion, clear_route_node likely leads to an entry * on the process_main queue. Fast-flapping could cause that queue * to grow and grow. */ if (!peer->clear_node_queue->thread) peer_lock (peer); /* bgp_clear_node_complete */ switch (purpose) { case BGP_CLEAR_ROUTE_NORMAL: if (safi != SAFI_MPLS_VPN) bgp_clear_route_table (peer, afi, safi, NULL, NULL, purpose); else for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn)) if ((table = rn->info) != NULL) bgp_clear_route_table (peer, afi, safi, table, NULL, purpose); for (ALL_LIST_ELEMENTS (peer->bgp->rsclient, node, nnode, rsclient)) if (CHECK_FLAG(rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_clear_route_table (peer, afi, safi, NULL, rsclient, purpose); break; case BGP_CLEAR_ROUTE_MY_RSCLIENT: bgp_clear_route_table (peer, afi, safi, NULL, peer, purpose); break; default: assert (0); break; } /* If no routes were cleared, nothing was added to workqueue, the * completion function won't be run by workqueue code - call it here. * XXX: Actually, this assumption doesn't hold, see * bgp_clear_route_table(), we queue all non-empty nodes. * * Additionally, there is a presumption in FSM that clearing is only * really needed if peer state is Established - peers in * pre-Established states shouldn't have any route-update state * associated with them (in or out). * * We still can get here in pre-Established though, through * peer_delete -> bgp_fsm_change_status, so this is a useful sanity * check to ensure the assumption above holds. * * At some future point, this check could be move to the top of the * function, and do a quick early-return when state is * pre-Established, avoiding above list and table scans. Once we're * sure it is safe.. */ if (!peer->clear_node_queue->thread) bgp_clear_node_complete (peer->clear_node_queue); } void bgp_clear_route_all (struct peer *peer) { afi_t afi; safi_t safi; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); } void bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_table *table; struct bgp_node *rn; struct bgp_adj_in *ain; table = peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ain = rn->adj_in; ain ; ain = ain->next) if (ain->peer == peer) { bgp_adj_in_remove (rn, ain); bgp_unlock_node (rn); break; } } void bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_table *table; table = peer->bgp->rib[afi][safi]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { for (ri = rn->info; ri; ri = ri->next) if (ri->peer == peer) { if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) bgp_rib_remove (rn, ri, peer, afi, safi); break; } } } /* Delete all kernel routes. */ void bgp_cleanup_routes (void) { struct bgp *bgp; struct listnode *node, *nnode; struct bgp_node *rn; struct bgp_table *table; struct bgp_info *ri; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { table = bgp->rib[AFI_IP][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); table = bgp->rib[AFI_IP6][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) for (ri = rn->info; ri; ri = ri->next) if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_NORMAL) bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST); } } void bgp_reset (void) { vty_reset (); bgp_zclient_reset (); access_list_reset (); prefix_list_reset (); } /* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr value. */ int bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet) { u_char *pnt; u_char *lim; struct prefix p; int psize; int ret; /* Check peer status. */ if (peer->status != Established) return 0; pnt = packet->nlri; lim = pnt + packet->length; for (; pnt < lim; pnt += psize) { /* Clear prefix structure. */ memset (&p, 0, sizeof (struct prefix)); /* Fetch prefix length. */ p.prefixlen = *pnt++; p.family = afi2family (packet->afi); /* Already checked in nlri_sanity_check(). We do double check here. */ if ((packet->afi == AFI_IP && p.prefixlen > 32) || (packet->afi == AFI_IP6 && p.prefixlen > 128)) return -1; /* Packet size overflow check. */ psize = PSIZE (p.prefixlen); /* When packet overflow occur return immediately. */ if (pnt + psize > lim) return -1; /* Fetch prefix from NLRI packet. */ memcpy (&p.u.prefix, pnt, psize); /* Check address. */ if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST) { if (IN_CLASSD (ntohl (p.u.prefix4.s_addr))) { /* * From draft-ietf-idr-bgp4-22, Section 6.3: * If a BGP router receives an UPDATE message with a * semantically incorrect NLRI field, in which a prefix is * semantically incorrect (eg. an unexpected multicast IP * address), it should ignore the prefix. */ zlog (peer->log, LOG_ERR, "IPv4 unicast NLRI is multicast address %s", inet_ntoa (p.u.prefix4)); return -1; } } #ifdef HAVE_IPV6 /* Check address. */ if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST) { if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { char buf[BUFSIZ]; zlog (peer->log, LOG_WARNING, "IPv6 link-local NLRI received %s ignore this NLRI", inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ)); continue; } } #endif /* HAVE_IPV6 */ /* Normal process. */ if (attr) ret = bgp_update (peer, &p, attr, packet->afi, packet->safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0); else ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL); /* Address family configuration mismatch or maximum-prefix count overflow. */ if (ret < 0) return -1; } /* Packet length consistency check. */ if (pnt != lim) return -1; return 0; } /* NLRI encode syntax check routine. */ int bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt, bgp_size_t length) { u_char *end; u_char prefixlen; int psize; end = pnt + length; /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for syntactic validity. If the field is syntactically incorrect, then the Error Subcode is set to Invalid Network Field. */ while (pnt < end) { prefixlen = *pnt++; /* Prefix length check. */ if ((afi == AFI_IP && prefixlen > 32) || (afi == AFI_IP6 && prefixlen > 128)) { plog_err (peer->log, "%s [Error] Update packet error (wrong prefix length %d)", peer->host, prefixlen); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } /* Packet size overflow check. */ psize = PSIZE (prefixlen); if (pnt + psize > end) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix data overflow prefix size is %d)", peer->host, psize); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } pnt += psize; } /* Packet length consistency check. */ if (pnt != end) { plog_err (peer->log, "%s [Error] Update packet error" " (prefix length mismatch with total length)", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_INVAL_NETWORK); return -1; } return 0; } static struct bgp_static * bgp_static_new (void) { return XCALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static)); } static void bgp_static_free (struct bgp_static *bgp_static) { if (bgp_static->rmap.name) free (bgp_static->rmap.name); XFREE (MTYPE_BGP_STATIC, bgp_static); } static void bgp_static_withdraw_rsclient (struct bgp *bgp, struct peer *rsclient, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_STATIC) break; /* Withdraw static BGP route from routing table. */ if (ri) { bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } static void bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_info *new; struct bgp_info info; struct attr *attr_new; struct attr attr; struct attr new_attr; struct attr_extra new_extra; struct bgp *bgp; int ret; char buf[SU_ADDRSTRLEN]; bgp = rsclient->bgp; assert (bgp_static); if (!bgp_static) return; rn = bgp_afi_node_get (rsclient->rib[afi][safi], afi, safi, p, NULL); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); attr.nexthop = bgp_static->igpnexthop; attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); /* Apply network route-map for export to this rsclient. */ if (bgp_static->rmap.name) { struct attr attr_tmp = attr; info.peer = rsclient; info.attr = &attr_tmp; SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_EXPORT); SET_FLAG (rsclient->rmap_type, PEER_RMAP_TYPE_NETWORK); ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); rsclient->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_tmp); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); bgp_attr_extra_free (&attr); return; } attr_new = bgp_attr_intern (&attr_tmp); } else attr_new = bgp_attr_intern (&attr); new_attr.extra = &new_extra; bgp_attr_dup(&new_attr, attr_new); SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); if (bgp_import_modifier (rsclient, bgp->peer_self, p, &new_attr, afi, safi) == RMAP_DENY) { /* This BGP update is filtered. Log the reason then update BGP entry. */ if (BGP_DEBUG (update, UPDATE_IN)) zlog (rsclient->log, LOG_DEBUG, "Static UPDATE about %s/%d -- DENIED for RS-client %s due to: import-policy", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rsclient->host); bgp->peer_self->rmap_type = 0; bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); return; } bgp->peer_self->rmap_type = 0; bgp_attr_unintern (&attr_new); attr_new = bgp_attr_intern (&new_attr); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_STATIC) break; if (ri) { if (attrhash_cmp (ri->attr, attr_new) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } else { /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Process change. */ bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } /* Make new BGP info. */ new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = attr_new; new->uptime = bgp_clock (); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } static void bgp_static_update_main (struct bgp *bgp, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_info *new; struct bgp_info info; struct attr attr; struct attr *attr_new; int ret; assert (bgp_static); if (!bgp_static) return; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); bgp_attr_default_set (&attr, BGP_ORIGIN_IGP); attr.nexthop = bgp_static->igpnexthop; attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); /* Apply route-map. */ if (bgp_static->rmap.name) { struct attr attr_tmp = attr; info.peer = bgp->peer_self; info.attr = &attr_tmp; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK); ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info); bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_tmp); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_static_withdraw (bgp, p, afi, safi); return; } attr_new = bgp_attr_intern (&attr_tmp); } else attr_new = bgp_attr_intern (&attr); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_STATIC) break; if (ri) { if (attrhash_cmp (ri->attr, attr_new) && !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) { bgp_unlock_node (rn); bgp_attr_unintern (&attr_new); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } else { /* The attribute is changed. */ bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)) bgp_info_restore(rn, ri); else bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_attr_unintern (&ri->attr); ri->attr = attr_new; ri->uptime = bgp_clock (); /* Process change. */ bgp_aggregate_increment (bgp, p, ri, afi, safi); bgp_process (bgp, rn, afi, safi); bgp_unlock_node (rn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } /* Make new BGP info. */ new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = attr_new; new->uptime = bgp_clock (); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } void bgp_static_update (struct bgp *bgp, struct prefix *p, struct bgp_static *bgp_static, afi_t afi, safi_t safi) { struct peer *rsclient; struct listnode *node, *nnode; bgp_static_update_main (bgp, p, bgp_static, afi, safi); for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient)) { if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_static_update_rsclient (rsclient, p, bgp_static, afi, safi); } } static void bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *new; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Make new BGP info. */ new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_STATIC; new->peer = bgp->peer_self; new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP); SET_FLAG (new->flags, BGP_INFO_VALID); new->uptime = bgp_clock (); new->extra = bgp_info_extra_new(); memcpy (new->extra->tag, tag, 3); /* Aggregate address increment. */ bgp_aggregate_increment (bgp, p, new, afi, safi); /* Register new BGP information. */ bgp_info_add (rn, new); /* route_node_get lock */ bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); } void bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, NULL); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_STATIC) break; /* Withdraw static BGP route from routing table. */ if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi) { struct bgp_static *bgp_static; struct bgp *bgp; struct bgp_node *rn; struct prefix *p; bgp = rsclient->bgp; for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { p = &rn->p; bgp_static_update_rsclient (rsclient, p, bgp_static, afi, safi); } } static void bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { struct bgp_node *rn; struct bgp_info *ri; rn = bgp_afi_node_get (bgp->rib[afi][safi], afi, safi, p, prd); /* Check selected route and self inserted route. */ for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_STATIC) break; /* Withdraw static BGP route from routing table. */ if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, safi); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } /* Configure static BGP network. When user don't run zebra, static route should be installed as valid. */ static int bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, safi_t safi, const char *rmap, int backdoor) { int ret; struct prefix p; struct bgp_static *bgp_static; struct bgp_node *rn; u_char need_update = 0; /* Convert IP prefix string to struct prefix. */ ret = str2prefix (ip_str, &p); if (! ret) { vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } #ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } #endif /* HAVE_IPV6 */ apply_mask (&p); /* Set BGP static route configuration. */ rn = bgp_node_get (bgp->route[afi][safi], &p); if (rn->info) { /* Configuration change. */ bgp_static = rn->info; /* Check previous routes are installed into BGP. */ if (bgp_static->valid && bgp_static->backdoor != backdoor) need_update = 1; bgp_static->backdoor = backdoor; if (rmap) { if (bgp_static->rmap.name) free (bgp_static->rmap.name); bgp_static->rmap.name = strdup (rmap); bgp_static->rmap.map = route_map_lookup_by_name (rmap); } else { if (bgp_static->rmap.name) free (bgp_static->rmap.name); bgp_static->rmap.name = NULL; bgp_static->rmap.map = NULL; bgp_static->valid = 0; } bgp_unlock_node (rn); } else { /* New configuration. */ bgp_static = bgp_static_new (); bgp_static->backdoor = backdoor; bgp_static->valid = 0; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; if (rmap) { if (bgp_static->rmap.name) free (bgp_static->rmap.name); bgp_static->rmap.name = strdup (rmap); bgp_static->rmap.map = route_map_lookup_by_name (rmap); } rn->info = bgp_static; } /* If BGP scan is not enabled, we should install this route here. */ if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { bgp_static->valid = 1; if (need_update) bgp_static_withdraw (bgp, &p, afi, safi); if (! bgp_static->backdoor) bgp_static_update (bgp, &p, bgp_static, afi, safi); } return CMD_SUCCESS; } /* Configure static BGP network. */ static int bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, safi_t safi) { int ret; struct prefix p; struct bgp_static *bgp_static; struct bgp_node *rn; /* Convert IP prefix string to struct prefix. */ ret = str2prefix (ip_str, &p); if (! ret) { vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } #ifdef HAVE_IPV6 if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) { vty_out (vty, "%% Malformed prefix (link-local address)%s", VTY_NEWLINE); return CMD_WARNING; } #endif /* HAVE_IPV6 */ apply_mask (&p); rn = bgp_node_lookup (bgp->route[afi][safi], &p); if (! rn) { vty_out (vty, "%% Can't find specified static route configuration.%s", VTY_NEWLINE); return CMD_WARNING; } bgp_static = rn->info; /* Update BGP RIB. */ if (! bgp_static->backdoor) bgp_static_withdraw (bgp, &p, afi, safi); /* Clear configuration. */ bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); return CMD_SUCCESS; } /* Called from bgp_delete(). Delete all static routes from the BGP instance. */ void bgp_static_delete (struct bgp *bgp) { afi_t afi; safi_t safi; struct bgp_node *rn; struct bgp_node *rm; struct bgp_table *table; struct bgp_static *bgp_static; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { if (safi == SAFI_MPLS_VPN) { table = rn->info; for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) { bgp_static = rn->info; bgp_static_withdraw_vpnv4 (bgp, &rm->p, AFI_IP, SAFI_MPLS_VPN, (struct prefix_rd *)&rn->p, bgp_static->tag); bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); } } else { bgp_static = rn->info; bgp_static_withdraw (bgp, &rn->p, afi, safi); bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); } } } int bgp_static_set_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str) { int ret; struct prefix p; struct prefix_rd prd; struct bgp *bgp; struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; struct bgp_static *bgp_static; u_char tag[3]; bgp = vty->index; ret = str2prefix (ip_str, &p); if (! ret) { vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask (&p); ret = str2prefix_rd (rd_str, &prd); if (! ret) { vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2tag (tag_str, tag); if (! ret) { vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); return CMD_WARNING; } prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); else bgp_unlock_node (prn); table = prn->info; rn = bgp_node_get (table, &p); if (rn->info) { vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE); bgp_unlock_node (rn); } else { /* New configuration. */ bgp_static = bgp_static_new (); bgp_static->valid = 1; memcpy (bgp_static->tag, tag, 3); rn->info = bgp_static; bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); } return CMD_SUCCESS; } /* Configure static BGP network. */ int bgp_static_unset_vpnv4 (struct vty *vty, const char *ip_str, const char *rd_str, const char *tag_str) { int ret; struct bgp *bgp; struct prefix p; struct prefix_rd prd; struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; struct bgp_static *bgp_static; u_char tag[3]; bgp = vty->index; /* Convert IP prefix string to struct prefix. */ ret = str2prefix (ip_str, &p); if (! ret) { vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask (&p); ret = str2prefix_rd (rd_str, &prd); if (! ret) { vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE); return CMD_WARNING; } ret = str2tag (tag_str, tag); if (! ret) { vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE); return CMD_WARNING; } prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN], (struct prefix *)&prd); if (prn->info == NULL) prn->info = bgp_table_init (AFI_IP, SAFI_MPLS_VPN); else bgp_unlock_node (prn); table = prn->info; rn = bgp_node_lookup (table, &p); if (rn) { bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag); bgp_static = rn->info; bgp_static_free (bgp_static); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); } else vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE); return CMD_SUCCESS; } DEFUN (bgp_network, bgp_network_cmd, "network A.B.C.D/M", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_route_map, bgp_network_route_map_cmd, "network A.B.C.D/M route-map WORD", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty), argv[1], 0); } DEFUN (bgp_network_backdoor, bgp_network_backdoor_cmd, "network A.B.C.D/M backdoor", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (bgp_network_mask, bgp_network_mask_cmd, "network A.B.C.D mask A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_mask_route_map, bgp_network_mask_route_map_cmd, "network A.B.C.D mask A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), argv[2], 0); } DEFUN (bgp_network_mask_backdoor, bgp_network_mask_backdoor_cmd, "network A.B.C.D mask A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (bgp_network_mask_natural, bgp_network_mask_natural_cmd, "network A.B.C.D", "Specify a network to announce via BGP\n" "Network number\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), NULL, 0); } DEFUN (bgp_network_mask_natural_route_map, bgp_network_mask_natural_route_map_cmd, "network A.B.C.D route-map WORD", "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty), argv[1], 0); } DEFUN (bgp_network_mask_natural_backdoor, bgp_network_mask_natural_backdoor_cmd, "network A.B.C.D backdoor", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (no_bgp_network, no_bgp_network_cmd, "no network A.B.C.D/M", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_static_unset (vty, vty->index, argv[0], AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network, no_bgp_network_route_map_cmd, "no network A.B.C.D/M route-map WORD", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network, no_bgp_network_backdoor_cmd, "no network A.B.C.D/M backdoor", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") DEFUN (no_bgp_network_mask, no_bgp_network_mask_cmd, "no network A.B.C.D mask A.B.C.D", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network_mask, no_bgp_network_mask_route_map_cmd, "no network A.B.C.D mask A.B.C.D route-map WORD", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network_mask, no_bgp_network_mask_backdoor_cmd, "no network A.B.C.D mask A.B.C.D backdoor", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n") DEFUN (no_bgp_network_mask_natural, no_bgp_network_mask_natural_cmd, "no network A.B.C.D", NO_STR "Specify a network to announce via BGP\n" "Network number\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP, bgp_node_safi (vty)); } ALIAS (no_bgp_network_mask_natural, no_bgp_network_mask_natural_route_map_cmd, "no network A.B.C.D route-map WORD", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (no_bgp_network_mask_natural, no_bgp_network_mask_natural_backdoor_cmd, "no network A.B.C.D backdoor", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n") #ifdef HAVE_IPV6 DEFUN (ipv6_bgp_network, ipv6_bgp_network_cmd, "network X:X::X:X/M", "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty), NULL, 0); } DEFUN (ipv6_bgp_network_route_map, ipv6_bgp_network_route_map_cmd, "network X:X::X:X/M route-map WORD", "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "Route-map to modify the attributes\n" "Name of the route map\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi (vty), argv[1], 0); } DEFUN (no_ipv6_bgp_network, no_ipv6_bgp_network_cmd, "no network X:X::X:X/M", NO_STR "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty)); } ALIAS (no_ipv6_bgp_network, no_ipv6_bgp_network_route_map_cmd, "no network X:X::X:X/M route-map WORD", NO_STR "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "Route-map to modify the attributes\n" "Name of the route map\n") ALIAS (ipv6_bgp_network, old_ipv6_bgp_network_cmd, "ipv6 bgp network X:X::X:X/M", IPV6_STR BGP_STR "Specify a network to announce via BGP\n" "IPv6 prefix /, e.g., 3ffe::/16\n") ALIAS (no_ipv6_bgp_network, old_no_ipv6_bgp_network_cmd, "no ipv6 bgp network X:X::X:X/M", NO_STR IPV6_STR BGP_STR "Specify a network to announce via BGP\n" "IPv6 prefix /, e.g., 3ffe::/16\n") #endif /* HAVE_IPV6 */ /* stubs for removed AS-Pathlimit commands, kept for config compatibility */ ALIAS_DEPRECATED (bgp_network, bgp_network_ttl_cmd, "network A.B.C.D/M pathlimit <0-255>", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_backdoor, bgp_network_backdoor_ttl_cmd, "network A.B.C.D/M backdoor pathlimit <0-255>", "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask, bgp_network_mask_ttl_cmd, "network A.B.C.D mask A.B.C.D pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_backdoor, bgp_network_mask_backdoor_ttl_cmd, "network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_natural, bgp_network_mask_natural_ttl_cmd, "network A.B.C.D pathlimit <0-255>", "Specify a network to announce via BGP\n" "Network number\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (bgp_network_mask_natural_backdoor, bgp_network_mask_natural_backdoor_ttl_cmd, "network A.B.C.D backdoor pathlimit <1-255>", "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_ttl_cmd, "no network A.B.C.D/M pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_backdoor_ttl_cmd, "no network A.B.C.D/M backdoor pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network, no_bgp_network_mask_ttl_cmd, "no network A.B.C.D mask A.B.C.D pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask, no_bgp_network_mask_backdoor_ttl_cmd, "no network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Network mask\n" "Network mask\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask_natural, no_bgp_network_mask_natural_ttl_cmd, "no network A.B.C.D pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_bgp_network_mask_natural, no_bgp_network_mask_natural_backdoor_ttl_cmd, "no network A.B.C.D backdoor pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "Network number\n" "Specify a BGP backdoor route\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") #ifdef HAVE_IPV6 ALIAS_DEPRECATED (ipv6_bgp_network, ipv6_bgp_network_ttl_cmd, "network X:X::X:X/M pathlimit <0-255>", "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") ALIAS_DEPRECATED (no_ipv6_bgp_network, no_ipv6_bgp_network_ttl_cmd, "no network X:X::X:X/M pathlimit <0-255>", NO_STR "Specify a network to announce via BGP\n" "IPv6 prefix /\n" "AS-Path hopcount limit attribute\n" "AS-Pathlimit TTL, in number of AS-Path hops\n") #endif /* HAVE_IPV6 */ /* Aggreagete address: advertise-map Set condition to advertise attribute as-set Generate AS set path information attribute-map Set attributes of aggregate route-map Set parameters of aggregate summary-only Filter more specific routes from updates suppress-map Conditionally filter more specific routes from updates */ struct bgp_aggregate { /* Summary-only flag. */ u_char summary_only; /* AS set generation. */ u_char as_set; /* Route-map for aggregated route. */ struct route_map *map; /* Suppress-count. */ unsigned long count; /* SAFI configuration. */ safi_t safi; }; static struct bgp_aggregate * bgp_aggregate_new (void) { return XCALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate)); } static void bgp_aggregate_free (struct bgp_aggregate *aggregate) { XFREE (MTYPE_BGP_AGGREGATE, aggregate); } static void bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew, afi_t afi, safi_t safi, struct bgp_info *del, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; struct bgp_node *rn; u_char origin; struct aspath *aspath = NULL; struct aspath *asmerge = NULL; struct community *community = NULL; struct community *commerge = NULL; struct bgp_info *ri; struct bgp_info *new; int first = 1; unsigned long match = 0; /* ORIGIN attribute: If at least one route among routes that are aggregated has ORIGIN with the value INCOMPLETE, then the aggregated route must have the ORIGIN attribute with the value INCOMPLETE. Otherwise, if at least one route among routes that are aggregated has ORIGIN with the value EGP, then the aggregated route must have the origin attribute with the value EGP. In all other case the value of the ORIGIN attribute of the aggregated route is INTERNAL. */ origin = BGP_ORIGIN_IGP; table = bgp->rib[afi][safi]; top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (del && ri == del) continue; if (! rinew && first) first = 0; #ifdef AGGREGATE_NEXTHOP_CHECK if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop) || ri->attr->med != med) { if (aspath) aspath_free (aspath); if (community) community_free (community); bgp_unlock_node (rn); bgp_unlock_node (top); return; } #endif /* AGGREGATE_NEXTHOP_CHECK */ if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } aggregate->count++; if (aggregate->as_set) { if (origin < ri->attr->origin) origin = ri->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (ri->attr->aspath); if (ri->attr->community) { if (community) { commerge = community_merge (community, ri->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (ri->attr->community); } } } } if (match) bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (top); if (rinew) { aggregate->count++; if (aggregate->summary_only) (bgp_info_extra_get (rinew))->suppress++; if (aggregate->as_set) { if (origin < rinew->attr->origin) origin = rinew->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, rinew->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (rinew->attr->aspath); if (rinew->attr->community) { if (community) { commerge = community_merge (community, rinew->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (rinew->attr->community); } } } if (aggregate->count > 0) { rn = bgp_node_get (table, p); new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_AGGREGATE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); new->uptime = bgp_clock (); bgp_info_add (rn, new); bgp_unlock_node (rn); bgp_process (bgp, rn, afi, safi); } else { if (aspath) aspath_free (aspath); if (community) community_free (community); } } void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t, struct bgp_aggregate *); void bgp_aggregate_increment (struct bgp *bgp, struct prefix *p, struct bgp_info *ri, afi_t afi, safi_t safi) { struct bgp_node *child; struct bgp_node *rn; struct bgp_aggregate *aggregate; struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if (safi == SAFI_MPLS_VPN) return; table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) return; if (BGP_INFO_HOLDDOWN (ri)) return; child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) { bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); bgp_aggregate_route (bgp, &rn->p, ri, afi, safi, NULL, aggregate); } bgp_unlock_node (child); } void bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p, struct bgp_info *del, afi_t afi, safi_t safi) { struct bgp_node *child; struct bgp_node *rn; struct bgp_aggregate *aggregate; struct bgp_table *table; /* MPLS-VPN aggregation is not yet supported. */ if (safi == SAFI_MPLS_VPN) return; table = bgp->aggregate[afi][safi]; /* No aggregates configured. */ if (bgp_table_top_nolock (table) == NULL) return; if (p->prefixlen == 0) return; child = bgp_node_get (table, p); /* Aggregate address configuration check. */ for (rn = child; rn; rn = bgp_node_parent_nolock (rn)) if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen) { bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate); bgp_aggregate_route (bgp, &rn->p, NULL, afi, safi, del, aggregate); } bgp_unlock_node (child); } static void bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; struct bgp_node *rn; struct bgp_info *new; struct bgp_info *ri; unsigned long match; u_char origin = BGP_ORIGIN_IGP; struct aspath *aspath = NULL; struct aspath *asmerge = NULL; struct community *community = NULL; struct community *commerge = NULL; table = bgp->rib[afi][safi]; /* Sanity check. */ if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) return; if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) return; /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { /* summary-only aggregate route suppress aggregated route announcement. */ if (aggregate->summary_only) { (bgp_info_extra_get (ri))->suppress++; bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } /* as-set aggregate route generate origin, as path, community aggregation. */ if (aggregate->as_set) { if (origin < ri->attr->origin) origin = ri->attr->origin; if (aspath) { asmerge = aspath_aggregate (aspath, ri->attr->aspath); aspath_free (aspath); aspath = asmerge; } else aspath = aspath_dup (ri->attr->aspath); if (ri->attr->community) { if (community) { commerge = community_merge (community, ri->attr->community); community = community_uniq_sort (commerge); community_free (commerge); } else community = community_dup (ri->attr->community); } } aggregate->count++; } } /* If this node is suppressed, process the change. */ if (match) bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (top); /* Add aggregate route to BGP table. */ if (aggregate->count) { rn = bgp_node_get (table, p); new = bgp_info_new (); new->type = ZEBRA_ROUTE_BGP; new->sub_type = BGP_ROUTE_AGGREGATE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set); new->uptime = bgp_clock (); bgp_info_add (rn, new); bgp_unlock_node (rn); /* Process change. */ bgp_process (bgp, rn, afi, safi); } } void bgp_aggregate_delete (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi, struct bgp_aggregate *aggregate) { struct bgp_table *table; struct bgp_node *top; struct bgp_node *rn; struct bgp_info *ri; unsigned long match; table = bgp->rib[afi][safi]; if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN) return; if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN) return; /* If routes exists below this node, generate aggregate routes. */ top = bgp_node_get (table, p); for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top)) if (rn->p.prefixlen > p->prefixlen) { match = 0; for (ri = rn->info; ri; ri = ri->next) { if (BGP_INFO_HOLDDOWN (ri)) continue; if (ri->sub_type != BGP_ROUTE_AGGREGATE) { if (aggregate->summary_only && ri->extra) { ri->extra->suppress--; if (ri->extra->suppress == 0) { bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED); match++; } } aggregate->count--; } } /* If this node was suppressed, process the change. */ if (match) bgp_process (bgp, rn, afi, safi); } bgp_unlock_node (top); /* Delete aggregate route from BGP table. */ rn = bgp_node_get (table, p); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP && ri->sub_type == BGP_ROUTE_AGGREGATE) break; /* Withdraw static BGP route from routing table. */ if (ri) { bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, safi); } /* Unlock bgp_node_lookup. */ bgp_unlock_node (rn); } /* Aggregate route attribute. */ #define AGGREGATE_SUMMARY_ONLY 1 #define AGGREGATE_AS_SET 1 static int bgp_aggregate_unset (struct vty *vty, const char *prefix_str, afi_t afi, safi_t safi) { int ret; struct prefix p; struct bgp_node *rn; struct bgp *bgp; struct bgp_aggregate *aggregate; /* Convert string to prefix structure. */ ret = str2prefix (prefix_str, &p); if (!ret) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask (&p); /* Get BGP structure. */ bgp = vty->index; /* Old configuration check. */ rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p); if (! rn) { vty_out (vty, "%% There is no aggregate-address configuration.%s", VTY_NEWLINE); return CMD_WARNING; } aggregate = rn->info; if (aggregate->safi & SAFI_UNICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate); if (aggregate->safi & SAFI_MULTICAST) bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate); /* Unlock aggregate address configuration. */ rn->info = NULL; bgp_aggregate_free (aggregate); bgp_unlock_node (rn); bgp_unlock_node (rn); return CMD_SUCCESS; } static int bgp_aggregate_set (struct vty *vty, const char *prefix_str, afi_t afi, safi_t safi, u_char summary_only, u_char as_set) { int ret; struct prefix p; struct bgp_node *rn; struct bgp *bgp; struct bgp_aggregate *aggregate; /* Convert string to prefix structure. */ ret = str2prefix (prefix_str, &p); if (!ret) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask (&p); /* Get BGP structure. */ bgp = vty->index; /* Old configuration check. */ rn = bgp_node_get (bgp->aggregate[afi][safi], &p); if (rn->info) { vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE); /* try to remove the old entry */ ret = bgp_aggregate_unset (vty, prefix_str, afi, safi); if (ret) { vty_out (vty, "Error deleting aggregate.%s", VTY_NEWLINE); bgp_unlock_node (rn); return CMD_WARNING; } } /* Make aggregate address structure. */ aggregate = bgp_aggregate_new (); aggregate->summary_only = summary_only; aggregate->as_set = as_set; aggregate->safi = safi; rn->info = aggregate; /* Aggregate address insert into BGP routing table. */ if (safi & SAFI_UNICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_UNICAST, aggregate); if (safi & SAFI_MULTICAST) bgp_aggregate_add (bgp, &p, afi, SAFI_MULTICAST, aggregate); return CMD_SUCCESS; } DEFUN (aggregate_address, aggregate_address_cmd, "aggregate-address A.B.C.D/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, 0); } DEFUN (aggregate_address_mask, aggregate_address_mask_cmd, "aggregate-address A.B.C.D A.B.C.D", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), 0, 0); } DEFUN (aggregate_address_summary_only, aggregate_address_summary_only_cmd, "aggregate-address A.B.C.D/M summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), AGGREGATE_SUMMARY_ONLY, 0); } DEFUN (aggregate_address_mask_summary_only, aggregate_address_mask_summary_only_cmd, "aggregate-address A.B.C.D A.B.C.D summary-only", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), AGGREGATE_SUMMARY_ONLY, 0); } DEFUN (aggregate_address_as_set, aggregate_address_as_set_cmd, "aggregate-address A.B.C.D/M as-set", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), 0, AGGREGATE_AS_SET); } DEFUN (aggregate_address_mask_as_set, aggregate_address_mask_as_set_cmd, "aggregate-address A.B.C.D A.B.C.D as-set", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), 0, AGGREGATE_AS_SET); } DEFUN (aggregate_address_as_set_summary, aggregate_address_as_set_summary_cmd, "aggregate-address A.B.C.D/M as-set summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP, bgp_node_safi (vty), AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); } ALIAS (aggregate_address_as_set_summary, aggregate_address_summary_as_set_cmd, "aggregate-address A.B.C.D/M summary-only as-set", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFUN (aggregate_address_mask_as_set_summary, aggregate_address_mask_as_set_summary_cmd, "aggregate-address A.B.C.D A.B.C.D as-set summary-only", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_aggregate_set (vty, prefix_str, AFI_IP, bgp_node_safi (vty), AGGREGATE_SUMMARY_ONLY, AGGREGATE_AS_SET); } ALIAS (aggregate_address_mask_as_set_summary, aggregate_address_mask_summary_as_set_cmd, "aggregate-address A.B.C.D A.B.C.D summary-only as-set", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFUN (no_aggregate_address, no_aggregate_address_cmd, "no aggregate-address A.B.C.D/M", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_unset (vty, argv[0], AFI_IP, bgp_node_safi (vty)); } ALIAS (no_aggregate_address, no_aggregate_address_summary_only_cmd, "no aggregate-address A.B.C.D/M summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") ALIAS (no_aggregate_address, no_aggregate_address_as_set_cmd, "no aggregate-address A.B.C.D/M as-set", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n") ALIAS (no_aggregate_address, no_aggregate_address_as_set_summary_cmd, "no aggregate-address A.B.C.D/M as-set summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") ALIAS (no_aggregate_address, no_aggregate_address_summary_as_set_cmd, "no aggregate-address A.B.C.D/M summary-only as-set", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") DEFUN (no_aggregate_address_mask, no_aggregate_address_mask_cmd, "no aggregate-address A.B.C.D A.B.C.D", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_aggregate_unset (vty, prefix_str, AFI_IP, bgp_node_safi (vty)); } ALIAS (no_aggregate_address_mask, no_aggregate_address_mask_summary_only_cmd, "no aggregate-address A.B.C.D A.B.C.D summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n") ALIAS (no_aggregate_address_mask, no_aggregate_address_mask_as_set_cmd, "no aggregate-address A.B.C.D A.B.C.D as-set", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n") ALIAS (no_aggregate_address_mask, no_aggregate_address_mask_as_set_summary_cmd, "no aggregate-address A.B.C.D A.B.C.D as-set summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Generate AS set path information\n" "Filter more specific routes from updates\n") ALIAS (no_aggregate_address_mask, no_aggregate_address_mask_summary_as_set_cmd, "no aggregate-address A.B.C.D A.B.C.D summary-only as-set", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" "Filter more specific routes from updates\n" "Generate AS set path information\n") #ifdef HAVE_IPV6 DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, "aggregate-address X:X::X:X/M", "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, 0, 0); } DEFUN (ipv6_aggregate_address_summary_only, ipv6_aggregate_address_summary_only_cmd, "aggregate-address X:X::X:X/M summary-only", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") { return bgp_aggregate_set (vty, argv[0], AFI_IP6, SAFI_UNICAST, AGGREGATE_SUMMARY_ONLY, 0); } DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, "no aggregate-address X:X::X:X/M", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") { return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); } DEFUN (no_ipv6_aggregate_address_summary_only, no_ipv6_aggregate_address_summary_only_cmd, "no aggregate-address X:X::X:X/M summary-only", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") { return bgp_aggregate_unset (vty, argv[0], AFI_IP6, SAFI_UNICAST); } ALIAS (ipv6_aggregate_address, old_ipv6_aggregate_address_cmd, "ipv6 bgp aggregate-address X:X::X:X/M", IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") ALIAS (ipv6_aggregate_address_summary_only, old_ipv6_aggregate_address_summary_only_cmd, "ipv6 bgp aggregate-address X:X::X:X/M summary-only", IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") ALIAS (no_ipv6_aggregate_address, old_no_ipv6_aggregate_address_cmd, "no ipv6 bgp aggregate-address X:X::X:X/M", NO_STR IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n") ALIAS (no_ipv6_aggregate_address_summary_only, old_no_ipv6_aggregate_address_summary_only_cmd, "no ipv6 bgp aggregate-address X:X::X:X/M summary-only", NO_STR IPV6_STR BGP_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Filter more specific routes from updates\n") #endif /* HAVE_IPV6 */ /* Redistribute route treatment. */ void bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, const struct in6_addr *nexthop6, u_int32_t metric, u_char type) { struct bgp *bgp; struct listnode *node, *nnode; struct bgp_info *new; struct bgp_info *bi; struct bgp_info info; struct bgp_node *bn; struct attr attr; struct attr *new_attr; afi_t afi; int ret; /* Make default attribute. */ bgp_attr_default_set (&attr, BGP_ORIGIN_INCOMPLETE); if (nexthop) attr.nexthop = *nexthop; #ifdef HAVE_IPV6 if (nexthop6) { struct attr_extra *extra = bgp_attr_extra_get(&attr); extra->mp_nexthop_global = *nexthop6; extra->mp_nexthop_len = 16; } #endif attr.med = metric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { afi = family2afi (p->family); if (bgp->redist[afi][type]) { struct attr attr_new; struct attr_extra extra_new; /* Copy attribute for modification. */ attr_new.extra = &extra_new; bgp_attr_dup (&attr_new, &attr); if (bgp->redist_metric_flag[afi][type]) attr_new.med = bgp->redist_metric[afi][type]; /* Apply route-map. */ if (bgp->rmap[afi][type].map) { info.peer = bgp->peer_self; info.attr = &attr_new; SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_REDISTRIBUTE); ret = route_map_apply (bgp->rmap[afi][type].map, p, RMAP_BGP, &info); bgp->peer_self->rmap_type = 0; if (ret == RMAP_DENYMATCH) { /* Free uninterned attribute. */ bgp_attr_flush (&attr_new); /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_redistribute_delete (p, type); return; } } bn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL); new_attr = bgp_attr_intern (&attr_new); for (bi = bn->info; bi; bi = bi->next) if (bi->peer == bgp->peer_self && bi->sub_type == BGP_ROUTE_REDISTRIBUTE) break; if (bi) { if (attrhash_cmp (bi->attr, new_attr) && !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) { bgp_attr_unintern (&new_attr); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); bgp_unlock_node (bn); return; } else { /* The attribute is changed. */ bgp_info_set_flag (bn, bi, BGP_INFO_ATTR_CHANGED); /* Rewrite BGP route information. */ if (CHECK_FLAG(bi->flags, BGP_INFO_REMOVED)) bgp_info_restore(bn, bi); else bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); bgp_attr_unintern (&bi->attr); bi->attr = new_attr; bi->uptime = bgp_clock (); /* Process change. */ bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST); bgp_process (bgp, bn, afi, SAFI_UNICAST); bgp_unlock_node (bn); aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); return; } } new = bgp_info_new (); new->type = type; new->sub_type = BGP_ROUTE_REDISTRIBUTE; new->peer = bgp->peer_self; SET_FLAG (new->flags, BGP_INFO_VALID); new->attr = new_attr; new->uptime = bgp_clock (); bgp_aggregate_increment (bgp, p, new, afi, SAFI_UNICAST); bgp_info_add (bn, new); bgp_unlock_node (bn); bgp_process (bgp, bn, afi, SAFI_UNICAST); } } /* Unintern original. */ aspath_unintern (&attr.aspath); bgp_attr_extra_free (&attr); } void bgp_redistribute_delete (struct prefix *p, u_char type) { struct bgp *bgp; struct listnode *node, *nnode; afi_t afi; struct bgp_node *rn; struct bgp_info *ri; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) { afi = family2afi (p->family); if (bgp->redist[afi][type]) { rn = bgp_afi_node_get (bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST, p, NULL); for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == type) break; if (ri) { bgp_aggregate_decrement (bgp, p, ri, afi, SAFI_UNICAST); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, SAFI_UNICAST); } bgp_unlock_node (rn); } } } /* Withdraw specified route type's route. */ void bgp_redistribute_withdraw (struct bgp *bgp, afi_t afi, int type) { struct bgp_node *rn; struct bgp_info *ri; struct bgp_table *table; table = bgp->rib[afi][SAFI_UNICAST]; for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) { for (ri = rn->info; ri; ri = ri->next) if (ri->peer == bgp->peer_self && ri->type == type) break; if (ri) { bgp_aggregate_decrement (bgp, &rn->p, ri, afi, SAFI_UNICAST); bgp_info_delete (rn, ri); bgp_process (bgp, rn, afi, SAFI_UNICAST); } } } /* Static function to display route. */ static void route_vty_out_route (struct prefix *p, struct vty *vty) { int len; u_int32_t destination; char buf[BUFSIZ]; if (p->family == AF_INET) { len = vty_out (vty, "%s", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ)); destination = ntohl (p->u.prefix4.s_addr); if ((IN_CLASSC (destination) && p->prefixlen == 24) || (IN_CLASSB (destination) && p->prefixlen == 16) || (IN_CLASSA (destination) && p->prefixlen == 8) || p->u.prefix4.s_addr == 0) { /* When mask is natural, mask is not displayed. */ } else len += vty_out (vty, "/%d", p->prefixlen); } else len = vty_out (vty, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); len = 17 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 20, " "); else vty_out (vty, "%*s", len, " "); } enum bgp_display_type { normal_list, }; /* Print the short form route status for a bgp_info */ static void route_vty_short_status_out (struct vty *vty, struct bgp_info *binfo) { /* Route status display. */ if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED)) vty_out (vty, "R"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE)) vty_out (vty, "S"); else if (binfo->extra && binfo->extra->suppress) vty_out (vty, "s"); else if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, "*"); else vty_out (vty, " "); /* Selected */ if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, "h"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) vty_out (vty, "d"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) vty_out (vty, ">"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH)) vty_out (vty, "="); else vty_out (vty, " "); /* Internal route. */ if ((binfo->peer->as) && (binfo->peer->as == binfo->peer->local_as)) vty_out (vty, "i"); else vty_out (vty, " "); } /* called from terminal list command */ void route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); /* Print attribute */ attr = binfo->attr; if (attr) { if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; len = vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); len = 16 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); else vty_out (vty, "%*s", len, " "); } #endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) vty_out (vty, "%7u", attr->local_pref); else vty_out (vty, " "); vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0)); /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } /* called from terminal list command */ void route_vty_out_tmp (struct vty *vty, struct prefix *p, struct attr *attr, safi_t safi) { /* Route status display. */ vty_out (vty, "*"); vty_out (vty, ">"); vty_out (vty, " "); /* print prefix and mask */ route_vty_out_route (p, vty); /* Print attribute */ if (attr) { if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { int len; char buf[BUFSIZ]; assert (attr->extra); len = vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); len = 16 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 36, " "); else vty_out (vty, "%*s", len, " "); } #endif /* HAVE_IPV6 */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, "%10u", attr->med); else vty_out (vty, " "); if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) vty_out (vty, "%7u", attr->local_pref); else vty_out (vty, " "); vty_out (vty, "%7u ", (attr->extra ? attr->extra->weight : 0)); /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } void route_vty_out_tag (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; u_int32_t label = 0; if (!binfo->extra) return; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); /* Print attribute */ attr = binfo->attr; if (attr) { if (p->family == AF_INET) { if (safi == SAFI_MPLS_VPN) vty_out (vty, "%-16s", inet_ntoa (attr->extra->mp_nexthop_global_in)); else vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else if (p->family == AF_INET6) { assert (attr->extra); char buf[BUFSIZ]; char buf1[BUFSIZ]; if (attr->extra->mp_nexthop_len == 16) vty_out (vty, "%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ)); else if (attr->extra->mp_nexthop_len == 32) vty_out (vty, "%s(%s)", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, BUFSIZ), inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf1, BUFSIZ)); } #endif /* HAVE_IPV6 */ } label = decode_label (binfo->extra->tag); vty_out (vty, "notag/%d", label); vty_out (vty, "%s", VTY_NEWLINE); } /* dampening route */ static void damp_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; int len; char timebuf[BGP_UPTIME_LEN]; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); len = vty_out (vty, "%s", binfo->peer->host); len = 17 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 34, " "); else vty_out (vty, "%*s", len, " "); vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo, timebuf, BGP_UPTIME_LEN)); /* Print attribute */ attr = binfo->attr; if (attr) { /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } /* flap route */ static void flap_route_vty_out (struct vty *vty, struct prefix *p, struct bgp_info *binfo, int display, safi_t safi) { struct attr *attr; struct bgp_damp_info *bdi; char timebuf[BGP_UPTIME_LEN]; int len; if (!binfo->extra) return; bdi = binfo->extra->damp_info; /* short status lead text */ route_vty_short_status_out (vty, binfo); /* print prefix and mask */ if (! display) route_vty_out_route (p, vty); else vty_out (vty, "%*s", 17, " "); len = vty_out (vty, "%s", binfo->peer->host); len = 16 - len; if (len < 1) vty_out (vty, "%s%*s", VTY_NEWLINE, 33, " "); else vty_out (vty, "%*s", len, " "); len = vty_out (vty, "%d", bdi->flap); len = 5 - len; if (len < 1) vty_out (vty, " "); else vty_out (vty, "%*s ", len, " "); vty_out (vty, "%s ", peer_uptime (bdi->start_time, timebuf, BGP_UPTIME_LEN)); if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED) && ! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, "%s ", bgp_damp_reuse_time_vty (vty, binfo, timebuf, BGP_UPTIME_LEN)); else vty_out (vty, "%*s ", 8, " "); /* Print attribute */ attr = binfo->attr; if (attr) { /* Print aspath */ if (attr->aspath) aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); } vty_out (vty, "%s", VTY_NEWLINE); } static void route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, struct bgp_info *binfo, afi_t afi, safi_t safi) { char buf[INET6_ADDRSTRLEN]; char buf1[BUFSIZ]; struct attr *attr; int sockunion_vty_out (struct vty *, union sockunion *); #ifdef HAVE_CLOCK_MONOTONIC time_t tbuf; #endif attr = binfo->attr; if (attr) { /* Line1 display AS-path, Aggregator */ if (attr->aspath) { vty_out (vty, " "); if (aspath_count_hops (attr->aspath) == 0) vty_out (vty, "Local"); else aspath_print_vty (vty, "%s", attr->aspath, ""); } if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED)) vty_out (vty, ", (removed)"); if (CHECK_FLAG (binfo->flags, BGP_INFO_STALE)) vty_out (vty, ", (stale)"); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))) vty_out (vty, ", (aggregated by %u %s)", attr->extra->aggregator_as, inet_ntoa (attr->extra->aggregator_addr)); if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT)) vty_out (vty, ", (Received from a RR-client)"); if (CHECK_FLAG (binfo->peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) vty_out (vty, ", (Received from a RS-client)"); if (CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, ", (history entry)"); else if (CHECK_FLAG (binfo->flags, BGP_INFO_DAMPED)) vty_out (vty, ", (suppressed due to dampening)"); vty_out (vty, "%s", VTY_NEWLINE); /* Line2 display Next-hop, Neighbor, Router-id */ if (p->family == AF_INET) { vty_out (vty, " %s", safi == SAFI_MPLS_VPN ? inet_ntoa (attr->extra->mp_nexthop_global_in) : inet_ntoa (attr->nexthop)); } #ifdef HAVE_IPV6 else { assert (attr->extra); vty_out (vty, " %s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, buf, INET6_ADDRSTRLEN)); } #endif /* HAVE_IPV6 */ if (binfo->peer == bgp->peer_self) { vty_out (vty, " from %s ", p->family == AF_INET ? "0.0.0.0" : "::"); vty_out (vty, "(%s)", inet_ntoa(bgp->router_id)); } else { if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) vty_out (vty, " (inaccessible)"); else if (binfo->extra && binfo->extra->igpmetric) vty_out (vty, " (metric %u)", binfo->extra->igpmetric); vty_out (vty, " from %s", sockunion2str (&binfo->peer->su, buf, SU_ADDRSTRLEN)); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " (%s)", inet_ntoa (attr->extra->originator_id)); else vty_out (vty, " (%s)", inet_ntop (AF_INET, &binfo->peer->remote_id, buf1, BUFSIZ)); } vty_out (vty, "%s", VTY_NEWLINE); #ifdef HAVE_IPV6 /* display nexthop local */ if (attr->extra && attr->extra->mp_nexthop_len == 32) { vty_out (vty, " (%s)%s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); } #endif /* HAVE_IPV6 */ /* Line 3 display Origin, Med, Locpref, Weight, valid, Int/Ext/Local, Atomic, best */ vty_out (vty, " Origin %s", bgp_origin_long_str[attr->origin]); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) vty_out (vty, ", metric %u", attr->med); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) vty_out (vty, ", localpref %u", attr->local_pref); else vty_out (vty, ", localpref %u", bgp->default_local_pref); if (attr->extra && attr->extra->weight != 0) vty_out (vty, ", weight %u", attr->extra->weight); if (! CHECK_FLAG (binfo->flags, BGP_INFO_HISTORY)) vty_out (vty, ", valid"); if (binfo->peer != bgp->peer_self) { if (binfo->peer->as == binfo->peer->local_as) vty_out (vty, ", internal"); else vty_out (vty, ", %s", (bgp_confederation_peers_check(bgp, binfo->peer->as) ? "confed-external" : "external")); } else if (binfo->sub_type == BGP_ROUTE_AGGREGATE) vty_out (vty, ", aggregated, local"); else if (binfo->type != ZEBRA_ROUTE_BGP) vty_out (vty, ", sourced"); else vty_out (vty, ", sourced, local"); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) vty_out (vty, ", atomic-aggregate"); if (CHECK_FLAG (binfo->flags, BGP_INFO_MULTIPATH) || (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED) && bgp_info_mpath_count (binfo))) vty_out (vty, ", multipath"); if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED)) vty_out (vty, ", best"); vty_out (vty, "%s", VTY_NEWLINE); /* Line 4 display Community */ if (attr->community) vty_out (vty, " Community: %s%s", attr->community->str, VTY_NEWLINE); /* Line 5 display Extended-community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) vty_out (vty, " Extended Community: %s%s", attr->extra->ecommunity->str, VTY_NEWLINE); /* Line 6 display Originator, Cluster-id */ if ((attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) || (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))) { assert (attr->extra); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) vty_out (vty, " Originator: %s", inet_ntoa (attr->extra->originator_id)); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST)) { int i; vty_out (vty, ", Cluster list: "); for (i = 0; i < attr->extra->cluster->length / 4; i++) vty_out (vty, "%s ", inet_ntoa (attr->extra->cluster->list[i])); } vty_out (vty, "%s", VTY_NEWLINE); } if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo); /* Line 7 display Uptime */ #ifdef HAVE_CLOCK_MONOTONIC tbuf = time(NULL) - (bgp_clock() - binfo->uptime); vty_out (vty, " Last update: %s", ctime(&tbuf)); #else vty_out (vty, " Last update: %s", ctime(&binfo->uptime)); #endif /* HAVE_CLOCK_MONOTONIC */ } vty_out (vty, "%s", VTY_NEWLINE); } #define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\ "h history, * valid, > best, = multipath,%s"\ " i internal, r RIB-failure, S Stale, R Removed%s" #define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s" #define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s" #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path%s" #define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path%s" enum bgp_show_type { bgp_show_type_normal, bgp_show_type_regexp, bgp_show_type_prefix_list, bgp_show_type_filter_list, bgp_show_type_route_map, bgp_show_type_neighbor, bgp_show_type_cidr_only, bgp_show_type_prefix_longer, bgp_show_type_community_all, bgp_show_type_community, bgp_show_type_community_exact, bgp_show_type_community_list, bgp_show_type_community_list_exact, bgp_show_type_flap_statistics, bgp_show_type_flap_address, bgp_show_type_flap_prefix, bgp_show_type_flap_cidr_only, bgp_show_type_flap_regexp, bgp_show_type_flap_filter_list, bgp_show_type_flap_prefix_list, bgp_show_type_flap_prefix_longer, bgp_show_type_flap_route_map, bgp_show_type_flap_neighbor, bgp_show_type_dampend_paths, bgp_show_type_damp_neighbor }; static int bgp_show_table (struct vty *vty, struct bgp_table *table, struct in_addr *router_id, enum bgp_show_type type, void *output_arg) { struct bgp_info *ri; struct bgp_node *rn; int header = 1; int display; unsigned long output_count; /* This is first entry point, so reset total line. */ output_count = 0; /* Start processing of routes. */ for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if (rn->info != NULL) { display = 0; for (ri = rn->info; ri; ri = ri->next) { if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix || type == bgp_show_type_flap_cidr_only || type == bgp_show_type_flap_regexp || type == bgp_show_type_flap_filter_list || type == bgp_show_type_flap_prefix_list || type == bgp_show_type_flap_prefix_longer || type == bgp_show_type_flap_route_map || type == bgp_show_type_flap_neighbor || type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) { if (!(ri->extra && ri->extra->damp_info)) continue; } if (type == bgp_show_type_regexp || type == bgp_show_type_flap_regexp) { regex_t *regex = output_arg; if (bgp_regexec (regex, ri->attr->aspath) == REG_NOMATCH) continue; } if (type == bgp_show_type_prefix_list || type == bgp_show_type_flap_prefix_list) { struct prefix_list *plist = output_arg; if (prefix_list_apply (plist, &rn->p) != PREFIX_PERMIT) continue; } if (type == bgp_show_type_filter_list || type == bgp_show_type_flap_filter_list) { struct as_list *as_list = output_arg; if (as_list_apply (as_list, ri->attr->aspath) != AS_FILTER_PERMIT) continue; } if (type == bgp_show_type_route_map || type == bgp_show_type_flap_route_map) { struct route_map *rmap = output_arg; struct bgp_info binfo; struct attr dummy_attr; struct attr_extra dummy_extra; int ret; dummy_attr.extra = &dummy_extra; bgp_attr_dup (&dummy_attr, ri->attr); binfo.peer = ri->peer; binfo.attr = &dummy_attr; ret = route_map_apply (rmap, &rn->p, RMAP_BGP, &binfo); if (ret == RMAP_DENYMATCH) continue; } if (type == bgp_show_type_neighbor || type == bgp_show_type_flap_neighbor || type == bgp_show_type_damp_neighbor) { union sockunion *su = output_arg; if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) continue; } if (type == bgp_show_type_cidr_only || type == bgp_show_type_flap_cidr_only) { u_int32_t destination; destination = ntohl (rn->p.u.prefix4.s_addr); if (IN_CLASSC (destination) && rn->p.prefixlen == 24) continue; if (IN_CLASSB (destination) && rn->p.prefixlen == 16) continue; if (IN_CLASSA (destination) && rn->p.prefixlen == 8) continue; } if (type == bgp_show_type_prefix_longer || type == bgp_show_type_flap_prefix_longer) { struct prefix *p = output_arg; if (! prefix_match (p, &rn->p)) continue; } if (type == bgp_show_type_community_all) { if (! ri->attr->community) continue; } if (type == bgp_show_type_community) { struct community *com = output_arg; if (! ri->attr->community || ! community_match (ri->attr->community, com)) continue; } if (type == bgp_show_type_community_exact) { struct community *com = output_arg; if (! ri->attr->community || ! community_cmp (ri->attr->community, com)) continue; } if (type == bgp_show_type_community_list) { struct community_list *list = output_arg; if (! community_list_match (ri->attr->community, list)) continue; } if (type == bgp_show_type_community_list_exact) { struct community_list *list = output_arg; if (! community_list_exact_match (ri->attr->community, list)) continue; } if (type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix) { struct prefix *p = output_arg; if (! prefix_match (&rn->p, p)) continue; if (type == bgp_show_type_flap_prefix) if (p->prefixlen != rn->p.prefixlen) continue; } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) { if (! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED) || CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) continue; } if (header) { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (*router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) vty_out (vty, BGP_SHOW_DAMP_HEADER, VTY_NEWLINE); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix || type == bgp_show_type_flap_cidr_only || type == bgp_show_type_flap_regexp || type == bgp_show_type_flap_filter_list || type == bgp_show_type_flap_prefix_list || type == bgp_show_type_flap_prefix_longer || type == bgp_show_type_flap_route_map || type == bgp_show_type_flap_neighbor) vty_out (vty, BGP_SHOW_FLAP_HEADER, VTY_NEWLINE); else vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); header = 0; } if (type == bgp_show_type_dampend_paths || type == bgp_show_type_damp_neighbor) damp_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); else if (type == bgp_show_type_flap_statistics || type == bgp_show_type_flap_address || type == bgp_show_type_flap_prefix || type == bgp_show_type_flap_cidr_only || type == bgp_show_type_flap_regexp || type == bgp_show_type_flap_filter_list || type == bgp_show_type_flap_prefix_list || type == bgp_show_type_flap_prefix_longer || type == bgp_show_type_flap_route_map || type == bgp_show_type_flap_neighbor) flap_route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); else route_vty_out (vty, &rn->p, ri, display, SAFI_UNICAST); display++; } if (display) output_count++; } /* No route is displayed */ if (output_count == 0) { if (type == bgp_show_type_normal) vty_out (vty, "No BGP network exists%s", VTY_NEWLINE); } else vty_out (vty, "%sTotal number of prefixes %ld%s", VTY_NEWLINE, output_count, VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_show (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_show_type type, void *output_arg) { struct bgp_table *table; if (bgp == NULL) { bgp = bgp_get_default (); } if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } table = bgp->rib[afi][safi]; return bgp_show_table (vty, table, &bgp->router_id, type, output_arg); } /* Header of detailed BGP route information */ static void route_vty_out_detail_header (struct vty *vty, struct bgp *bgp, struct bgp_node *rn, struct prefix_rd *prd, afi_t afi, safi_t safi) { struct bgp_info *ri; struct prefix *p; struct peer *peer; struct listnode *node, *nnode; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; int count = 0; int best = 0; int suppress = 0; int no_export = 0; int no_advertise = 0; int local_as = 0; int first = 0; p = &rn->p; vty_out (vty, "BGP routing table entry for %s%s%s/%d%s", (safi == SAFI_MPLS_VPN ? prefix_rd2str (prd, buf1, RD_ADDRSTRLEN) : ""), safi == SAFI_MPLS_VPN ? ":" : "", inet_ntop (p->family, &p->u.prefix, buf2, INET6_ADDRSTRLEN), p->prefixlen, VTY_NEWLINE); for (ri = rn->info; ri; ri = ri->next) { count++; if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)) { best = count; if (ri->extra && ri->extra->suppress) suppress = 1; if (ri->attr->community != NULL) { if (community_include (ri->attr->community, COMMUNITY_NO_ADVERTISE)) no_advertise = 1; if (community_include (ri->attr->community, COMMUNITY_NO_EXPORT)) no_export = 1; if (community_include (ri->attr->community, COMMUNITY_LOCAL_AS)) local_as = 1; } } } vty_out (vty, "Paths: (%d available", count); if (best) { vty_out (vty, ", best #%d", best); if (safi == SAFI_UNICAST) vty_out (vty, ", table Default-IP-Routing-Table"); } else vty_out (vty, ", no best path"); if (no_advertise) vty_out (vty, ", not advertised to any peer"); else if (no_export) vty_out (vty, ", not advertised to EBGP peer"); else if (local_as) vty_out (vty, ", not advertised outside local AS"); if (suppress) vty_out (vty, ", Advertisements suppressed by an aggregate."); vty_out (vty, ")%s", VTY_NEWLINE); /* advertised peer */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (bgp_adj_out_lookup (peer, p, afi, safi, rn)) { if (! first) vty_out (vty, " Advertised to non peer-group peers:%s ", VTY_NEWLINE); vty_out (vty, " %s", sockunion2str (&peer->su, buf1, SU_ADDRSTRLEN)); first = 1; } } if (! first) vty_out (vty, " Not advertised to any peer"); vty_out (vty, "%s", VTY_NEWLINE); } /* Display specified route of BGP table. */ static int bgp_show_route_in_table (struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check) { int ret; int header; int display = 0; struct prefix match; struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; struct bgp_table *table; /* Check IP address argument. */ ret = str2prefix (ip_str, &match); if (! ret) { vty_out (vty, "address is malformed%s", VTY_NEWLINE); return CMD_WARNING; } match.family = afi2family (afi); if (safi == SAFI_MPLS_VPN) { for (rn = bgp_table_top (rib); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) { header = 1; if ((rm = bgp_node_match (table, &match)) != NULL) { if (prefix_check && rm->p.prefixlen != match.prefixlen) { bgp_unlock_node (rm); continue; } for (ri = rm->info; ri; ri = ri->next) { if (header) { route_vty_out_detail_header (vty, bgp, rm, (struct prefix_rd *)&rn->p, AFI_IP, SAFI_MPLS_VPN); header = 0; } display++; route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN); } bgp_unlock_node (rm); } } } } else { header = 1; if ((rn = bgp_node_match (rib, &match)) != NULL) { if (! prefix_check || rn->p.prefixlen == match.prefixlen) { for (ri = rn->info; ri; ri = ri->next) { if (header) { route_vty_out_detail_header (vty, bgp, rn, NULL, afi, safi); header = 0; } display++; route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi); } } bgp_unlock_node (rn); } } if (! display) { vty_out (vty, "%% Network not in table%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } /* Display specified route of Main RIB */ static int bgp_show_route (struct vty *vty, const char *view_name, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check) { struct bgp *bgp; /* BGP structure lookup. */ if (view_name) { bgp = bgp_lookup_by_name (view_name); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } return bgp_show_route_in_table (vty, bgp, bgp->rib[afi][safi], ip_str, afi, safi, prd, prefix_check); } /* BGP route print out function. */ DEFUN (show_ip_bgp, show_ip_bgp_cmd, "show ip bgp", SHOW_STR IP_STR BGP_STR) { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_ip_bgp_ipv4, show_ip_bgp_ipv4_cmd, "show ip bgp ipv4 (unicast|multicast)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_normal, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } ALIAS (show_ip_bgp_ipv4, show_bgp_ipv4_safi_cmd, "show bgp ipv4 (unicast|multicast)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n") DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, "show ip bgp A.B.C.D", SHOW_STR IP_STR BGP_STR "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); } DEFUN (show_ip_bgp_ipv4_route, show_ip_bgp_ipv4_route_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 0); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } ALIAS (show_ip_bgp_ipv4_route, show_bgp_ipv4_safi_route_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") DEFUN (show_ip_bgp_vpnv4_all_route, show_ip_bgp_vpnv4_all_route_cmd, "show ip bgp vpnv4 all A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 0); } DEFUN (show_ip_bgp_vpnv4_rd_route, show_ip_bgp_vpnv4_rd_route_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "Network in the BGP routing table to display\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 0); } DEFUN (show_ip_bgp_prefix, show_ip_bgp_prefix_cmd, "show ip bgp A.B.C.D/M", SHOW_STR IP_STR BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (show_ip_bgp_ipv4_prefix, show_ip_bgp_ipv4_prefix_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MULTICAST, NULL, 1); return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } ALIAS (show_ip_bgp_ipv4_prefix, show_bgp_ipv4_safi_prefix_cmd, "show bgp ipv4 (unicast|multicast) A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (show_ip_bgp_vpnv4_all_prefix, show_ip_bgp_vpnv4_all_prefix_cmd, "show ip bgp vpnv4 all A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information about all VPNv4 NLRIs\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP, SAFI_MPLS_VPN, NULL, 1); } DEFUN (show_ip_bgp_vpnv4_rd_prefix, show_ip_bgp_vpnv4_rd_prefix_cmd, "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display VPNv4 NLRI specific information\n" "Display information for a route distinguisher\n" "VPN Route Distinguisher\n" "IP prefix /, e.g., 35.0.0.0/8\n") { int ret; struct prefix_rd prd; ret = str2prefix_rd (argv[0], &prd); if (! ret) { vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_MPLS_VPN, &prd, 1); } DEFUN (show_ip_bgp_view, show_ip_bgp_view_cmd, "show ip bgp view WORD", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n") { struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_ip_bgp_view_route, show_ip_bgp_view_route_cmd, "show ip bgp view WORD A.B.C.D", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } DEFUN (show_ip_bgp_view_prefix, show_ip_bgp_view_prefix_cmd, "show ip bgp view WORD A.B.C.D/M", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } #ifdef HAVE_IPV6 DEFUN (show_bgp, show_bgp_cmd, "show bgp", SHOW_STR BGP_STR) { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } ALIAS (show_bgp, show_bgp_ipv6_cmd, "show bgp ipv6", SHOW_STR BGP_STR "Address family\n") DEFUN (show_bgp_ipv6_safi, show_bgp_ipv6_safi_cmd, "show bgp ipv6 (unicast|multicast)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, NULL); return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } /* old command */ DEFUN (show_ipv6_bgp, show_ipv6_bgp_cmd, "show ipv6 bgp", SHOW_STR IP_STR BGP_STR) { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } DEFUN (show_bgp_route, show_bgp_route_cmd, "show bgp X:X::X:X", SHOW_STR BGP_STR "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); } ALIAS (show_bgp_route, show_bgp_ipv6_route_cmd, "show bgp ipv6 X:X::X:X", SHOW_STR BGP_STR "Address family\n" "Network in the BGP routing table to display\n") DEFUN (show_bgp_ipv6_safi_route, show_bgp_ipv6_safi_route_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Network in the BGP routing table to display\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } /* old command */ DEFUN (show_ipv6_bgp_route, show_ipv6_bgp_route_cmd, "show ipv6 bgp X:X::X:X", SHOW_STR IP_STR BGP_STR "Network in the BGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); } DEFUN (show_bgp_prefix, show_bgp_prefix_cmd, "show bgp X:X::X:X/M", SHOW_STR BGP_STR "IPv6 prefix /\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); } ALIAS (show_bgp_prefix, show_bgp_ipv6_prefix_cmd, "show bgp ipv6 X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /\n") DEFUN (show_bgp_ipv6_safi_prefix, show_bgp_ipv6_safi_prefix_cmd, "show bgp ipv6 (unicast|multicast) X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IPv6 prefix /, e.g., 3ffe::/16\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1); return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } /* old command */ DEFUN (show_ipv6_bgp_prefix, show_ipv6_bgp_prefix_cmd, "show ipv6 bgp X:X::X:X/M", SHOW_STR IP_STR BGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 1); } DEFUN (show_bgp_view, show_bgp_view_cmd, "show bgp view WORD", SHOW_STR BGP_STR "BGP view\n" "View name\n") { struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view, show_bgp_view_ipv6_cmd, "show bgp view WORD ipv6", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n") DEFUN (show_bgp_view_route, show_bgp_view_route_cmd, "show bgp view WORD X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Network in the BGP routing table to display\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } ALIAS (show_bgp_view_route, show_bgp_view_ipv6_route_cmd, "show bgp view WORD ipv6 X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_prefix, show_bgp_view_prefix_cmd, "show bgp view WORD X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "IPv6 prefix /\n") { return bgp_show_route (vty, argv[0], argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } ALIAS (show_bgp_view_prefix, show_bgp_view_ipv6_prefix_cmd, "show bgp view WORD ipv6 X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "IPv6 prefix /\n") /* old command */ DEFUN (show_ipv6_mbgp, show_ipv6_mbgp_cmd, "show ipv6 mbgp", SHOW_STR IP_STR MBGP_STR) { return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal, NULL); } /* old command */ DEFUN (show_ipv6_mbgp_route, show_ipv6_mbgp_route_cmd, "show ipv6 mbgp X:X::X:X", SHOW_STR IP_STR MBGP_STR "Network in the MBGP routing table to display\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 0); } /* old command */ DEFUN (show_ipv6_mbgp_prefix, show_ipv6_mbgp_prefix_cmd, "show ipv6 mbgp X:X::X:X/M", SHOW_STR IP_STR MBGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { return bgp_show_route (vty, NULL, argv[0], AFI_IP6, SAFI_MULTICAST, NULL, 1); } #endif static int bgp_show_regexp (struct vty *vty, int argc, const char **argv, afi_t afi, safi_t safi, enum bgp_show_type type) { int i; struct buffer *b; char *regstr; int first; regex_t *regex; int rc; first = 0; b = buffer_new (1024); for (i = 0; i < argc; i++) { if (first) buffer_putc (b, ' '); else { if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) continue; first = 1; } buffer_putstr (b, argv[i]); } buffer_putc (b, '\0'); regstr = buffer_getstr (b); buffer_free (b); regex = bgp_regcomp (regstr); XFREE(MTYPE_TMP, regstr); if (! regex) { vty_out (vty, "Can't compile regexp %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } rc = bgp_show (vty, NULL, afi, safi, type, regex); bgp_regex_free (regex); return rc; } DEFUN (show_ip_bgp_regexp, show_ip_bgp_regexp_cmd, "show ip bgp regexp .LINE", SHOW_STR IP_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, bgp_show_type_regexp); } DEFUN (show_ip_bgp_flap_regexp, show_ip_bgp_flap_regexp_cmd, "show ip bgp flap-statistics regexp .LINE", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_regexp); } DEFUN (show_ip_bgp_ipv4_regexp, show_ip_bgp_ipv4_regexp_cmd, "show ip bgp ipv4 (unicast|multicast) regexp .LINE", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_MULTICAST, bgp_show_type_regexp); return bgp_show_regexp (vty, argc, argv, AFI_IP, SAFI_UNICAST, bgp_show_type_regexp); } #ifdef HAVE_IPV6 DEFUN (show_bgp_regexp, show_bgp_regexp_cmd, "show bgp regexp .LINE", SHOW_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } ALIAS (show_bgp_regexp, show_bgp_ipv6_regexp_cmd, "show bgp ipv6 regexp .LINE", SHOW_STR BGP_STR "Address family\n" "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") /* old command */ DEFUN (show_ipv6_bgp_regexp, show_ipv6_bgp_regexp_cmd, "show ipv6 bgp regexp .LINE", SHOW_STR IP_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the BGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_UNICAST, bgp_show_type_regexp); } /* old command */ DEFUN (show_ipv6_mbgp_regexp, show_ipv6_mbgp_regexp_cmd, "show ipv6 mbgp regexp .LINE", SHOW_STR IP_STR BGP_STR "Display routes matching the AS path regular expression\n" "A regular-expression to match the MBGP AS paths\n") { return bgp_show_regexp (vty, argc, argv, AFI_IP6, SAFI_MULTICAST, bgp_show_type_regexp); } #endif /* HAVE_IPV6 */ static int bgp_show_prefix_list (struct vty *vty, const char *prefix_list_str, afi_t afi, safi_t safi, enum bgp_show_type type) { struct prefix_list *plist; plist = prefix_list_lookup (afi, prefix_list_str); if (plist == NULL) { vty_out (vty, "%% %s is not a valid prefix-list name%s", prefix_list_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, type, plist); } DEFUN (show_ip_bgp_prefix_list, show_ip_bgp_prefix_list_cmd, "show ip bgp prefix-list WORD", SHOW_STR IP_STR BGP_STR "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_list); } DEFUN (show_ip_bgp_flap_prefix_list, show_ip_bgp_flap_prefix_list_cmd, "show ip bgp flap-statistics prefix-list WORD", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_prefix_list); } DEFUN (show_ip_bgp_ipv4_prefix_list, show_ip_bgp_ipv4_prefix_list_cmd, "show ip bgp ipv4 (unicast|multicast) prefix-list WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the prefix-list\n" "IP prefix-list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_prefix_list); return bgp_show_prefix_list (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_list); } #ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_list, show_bgp_prefix_list_cmd, "show bgp prefix-list WORD", SHOW_STR BGP_STR "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_list); } ALIAS (show_bgp_prefix_list, show_bgp_ipv6_prefix_list_cmd, "show bgp ipv6 prefix-list WORD", SHOW_STR BGP_STR "Address family\n" "Display routes conforming to the prefix-list\n" "IPv6 prefix-list name\n") /* old command */ DEFUN (show_ipv6_bgp_prefix_list, show_ipv6_bgp_prefix_list_cmd, "show ipv6 bgp prefix-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_list); } /* old command */ DEFUN (show_ipv6_mbgp_prefix_list, show_ipv6_mbgp_prefix_list_cmd, "show ipv6 mbgp prefix-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the prefix-list\n" "IPv6 prefix-list name\n") { return bgp_show_prefix_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_list); } #endif /* HAVE_IPV6 */ static int bgp_show_filter_list (struct vty *vty, const char *filter, afi_t afi, safi_t safi, enum bgp_show_type type) { struct as_list *as_list; as_list = as_list_lookup (filter); if (as_list == NULL) { vty_out (vty, "%% %s is not a valid AS-path access-list name%s", filter, VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, type, as_list); } DEFUN (show_ip_bgp_filter_list, show_ip_bgp_filter_list_cmd, "show ip bgp filter-list WORD", SHOW_STR IP_STR BGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_filter_list); } DEFUN (show_ip_bgp_flap_filter_list, show_ip_bgp_flap_filter_list_cmd, "show ip bgp flap-statistics filter-list WORD", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_filter_list); } DEFUN (show_ip_bgp_ipv4_filter_list, show_ip_bgp_ipv4_filter_list_cmd, "show ip bgp ipv4 (unicast|multicast) filter-list WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_filter_list); return bgp_show_filter_list (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_filter_list); } #ifdef HAVE_IPV6 DEFUN (show_bgp_filter_list, show_bgp_filter_list_cmd, "show bgp filter-list WORD", SHOW_STR BGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } ALIAS (show_bgp_filter_list, show_bgp_ipv6_filter_list_cmd, "show bgp ipv6 filter-list WORD", SHOW_STR BGP_STR "Address family\n" "Display routes conforming to the filter-list\n" "Regular expression access list name\n") /* old command */ DEFUN (show_ipv6_bgp_filter_list, show_ipv6_bgp_filter_list_cmd, "show ipv6 bgp filter-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_filter_list); } /* old command */ DEFUN (show_ipv6_mbgp_filter_list, show_ipv6_mbgp_filter_list_cmd, "show ipv6 mbgp filter-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes conforming to the filter-list\n" "Regular expression access list name\n") { return bgp_show_filter_list (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_filter_list); } #endif /* HAVE_IPV6 */ static int bgp_show_route_map (struct vty *vty, const char *rmap_str, afi_t afi, safi_t safi, enum bgp_show_type type) { struct route_map *rmap; rmap = route_map_lookup_by_name (rmap_str); if (! rmap) { vty_out (vty, "%% %s is not a valid route-map name%s", rmap_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, type, rmap); } DEFUN (show_ip_bgp_route_map, show_ip_bgp_route_map_cmd, "show ip bgp route-map WORD", SHOW_STR IP_STR BGP_STR "Display routes matching the route-map\n" "A route-map to match on\n") { return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_route_map); } DEFUN (show_ip_bgp_flap_route_map, show_ip_bgp_flap_route_map_cmd, "show ip bgp flap-statistics route-map WORD", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Display routes matching the route-map\n" "A route-map to match on\n") { return bgp_show_route_map (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_route_map); } DEFUN (show_ip_bgp_ipv4_route_map, show_ip_bgp_ipv4_route_map_cmd, "show ip bgp ipv4 (unicast|multicast) route-map WORD", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the route-map\n" "A route-map to match on\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_route_map); return bgp_show_route_map (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_route_map); } DEFUN (show_bgp_route_map, show_bgp_route_map_cmd, "show bgp route-map WORD", SHOW_STR BGP_STR "Display routes matching the route-map\n" "A route-map to match on\n") { return bgp_show_route_map (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_route_map); } ALIAS (show_bgp_route_map, show_bgp_ipv6_route_map_cmd, "show bgp ipv6 route-map WORD", SHOW_STR BGP_STR "Address family\n" "Display routes matching the route-map\n" "A route-map to match on\n") DEFUN (show_ip_bgp_cidr_only, show_ip_bgp_cidr_only_cmd, "show ip bgp cidr-only", SHOW_STR IP_STR BGP_STR "Display only routes with non-natural netmasks\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } DEFUN (show_ip_bgp_flap_cidr_only, show_ip_bgp_flap_cidr_only_cmd, "show ip bgp flap-statistics cidr-only", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Display only routes with non-natural netmasks\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_cidr_only, NULL); } DEFUN (show_ip_bgp_ipv4_cidr_only, show_ip_bgp_ipv4_cidr_only_cmd, "show ip bgp ipv4 (unicast|multicast) cidr-only", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display only routes with non-natural netmasks\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_cidr_only, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_cidr_only, NULL); } DEFUN (show_ip_bgp_community_all, show_ip_bgp_community_all_cmd, "show ip bgp community", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_community_all, NULL); } DEFUN (show_ip_bgp_ipv4_community_all, show_ip_bgp_ipv4_community_all_cmd, "show ip bgp ipv4 (unicast|multicast) community", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show (vty, NULL, AFI_IP, SAFI_MULTICAST, bgp_show_type_community_all, NULL); return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_community_all, NULL); } #ifdef HAVE_IPV6 DEFUN (show_bgp_community_all, show_bgp_community_all_cmd, "show bgp community", SHOW_STR BGP_STR "Display routes matching the communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_community_all, NULL); } ALIAS (show_bgp_community_all, show_bgp_ipv6_community_all_cmd, "show bgp ipv6 community", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n") /* old command */ DEFUN (show_ipv6_bgp_community_all, show_ipv6_bgp_community_all_cmd, "show ipv6 bgp community", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_community_all, NULL); } /* old command */ DEFUN (show_ipv6_mbgp_community_all, show_ipv6_mbgp_community_all_cmd, "show ipv6 mbgp community", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n") { return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_community_all, NULL); } #endif /* HAVE_IPV6 */ static int bgp_show_community (struct vty *vty, const char *view_name, int argc, const char **argv, int exact, afi_t afi, safi_t safi) { struct community *com; struct buffer *b; struct bgp *bgp; int i; char *str; int first = 0; /* BGP structure lookup */ if (view_name) { bgp = bgp_lookup_by_name (view_name); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } b = buffer_new (1024); for (i = 0; i < argc; i++) { if (first) buffer_putc (b, ' '); else { if ((strcmp (argv[i], "unicast") == 0) || (strcmp (argv[i], "multicast") == 0)) continue; first = 1; } buffer_putstr (b, argv[i]); } buffer_putc (b, '\0'); str = buffer_getstr (b); buffer_free (b); com = community_str2com (str); XFREE (MTYPE_TMP, str); if (! com) { vty_out (vty, "%% Community malformed: %s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, bgp, afi, safi, (exact ? bgp_show_type_community_exact : bgp_show_type_community), com); } DEFUN (show_ip_bgp_community, show_ip_bgp_community_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_community, show_ip_bgp_community2_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_ip_bgp_community, show_ip_bgp_community3_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_ip_bgp_community, show_ip_bgp_community4_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFUN (show_ip_bgp_ipv4_community, show_ip_bgp_ipv4_community_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_community, show_ip_bgp_ipv4_community2_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_ip_bgp_ipv4_community, show_ip_bgp_ipv4_community3_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_ip_bgp_ipv4_community, show_ip_bgp_ipv4_community4_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFUN (show_bgp_view_afi_safi_community_all, show_bgp_view_afi_safi_community_all_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community", #else "show bgp view WORD ipv4 (unicast|multicast) community", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n") { int afi; int safi; struct bgp *bgp; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } #ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; #endif return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL); } DEFUN (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { int afi; int safi; #ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi); #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi); #endif } ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community2_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community3_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_view_afi_safi_community, show_bgp_view_afi_safi_community4_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #else "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address family modifier\n" "Address family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFUN (show_ip_bgp_community_exact, show_ip_bgp_community_exact_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") { return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_community_exact, show_ip_bgp_community2_exact_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_ip_bgp_community_exact, show_ip_bgp_community3_exact_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_ip_bgp_community_exact, show_ip_bgp_community4_exact_cmd, "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") DEFUN (show_ip_bgp_ipv4_community_exact, show_ip_bgp_ipv4_community_exact_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST); return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST); } ALIAS (show_ip_bgp_ipv4_community_exact, show_ip_bgp_ipv4_community2_exact_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_ip_bgp_ipv4_community_exact, show_ip_bgp_ipv4_community3_exact_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_ip_bgp_ipv4_community_exact, show_ip_bgp_ipv4_community4_exact_cmd, "show ip bgp ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") #ifdef HAVE_IPV6 DEFUN (show_bgp_community, show_bgp_community_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community, show_bgp_ipv6_community_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_community2_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_ipv6_community2_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_community3_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_ipv6_community3_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_community4_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") ALIAS (show_bgp_community, show_bgp_ipv6_community4_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ DEFUN (show_ipv6_bgp_community, show_ipv6_bgp_community_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST); } /* old command */ ALIAS (show_ipv6_bgp_community, show_ipv6_bgp_community2_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ ALIAS (show_ipv6_bgp_community, show_ipv6_bgp_community3_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ ALIAS (show_ipv6_bgp_community, show_ipv6_bgp_community4_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") DEFUN (show_bgp_community_exact, show_bgp_community_exact_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") { return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_exact, show_bgp_ipv6_community_exact_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_community2_exact_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_ipv6_community2_exact_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_community3_exact_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_ipv6_community3_exact_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_community4_exact_cmd, "show bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") ALIAS (show_bgp_community_exact, show_bgp_ipv6_community4_exact_cmd, "show bgp ipv6 community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ DEFUN (show_ipv6_bgp_community_exact, show_ipv6_bgp_community_exact_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") { return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST); } /* old command */ ALIAS (show_ipv6_bgp_community_exact, show_ipv6_bgp_community2_exact_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ ALIAS (show_ipv6_bgp_community_exact, show_ipv6_bgp_community3_exact_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ ALIAS (show_ipv6_bgp_community_exact, show_ipv6_bgp_community4_exact_cmd, "show ipv6 bgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ DEFUN (show_ipv6_mbgp_community, show_ipv6_mbgp_community_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") { return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_MULTICAST); } /* old command */ ALIAS (show_ipv6_mbgp_community, show_ipv6_mbgp_community2_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ ALIAS (show_ipv6_mbgp_community, show_ipv6_mbgp_community3_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ ALIAS (show_ipv6_mbgp_community, show_ipv6_mbgp_community4_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n") /* old command */ DEFUN (show_ipv6_mbgp_community_exact, show_ipv6_mbgp_community_exact_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") { return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_MULTICAST); } /* old command */ ALIAS (show_ipv6_mbgp_community_exact, show_ipv6_mbgp_community2_exact_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ ALIAS (show_ipv6_mbgp_community_exact, show_ipv6_mbgp_community3_exact_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") /* old command */ ALIAS (show_ipv6_mbgp_community_exact, show_ipv6_mbgp_community4_exact_cmd, "show ipv6 mbgp community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the communities\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "community number\n" "Do not send outside local AS (well-known community)\n" "Do not advertise to any peer (well-known community)\n" "Do not export to next AS (well-known community)\n" "Exact match of the communities") #endif /* HAVE_IPV6 */ static int bgp_show_community_list (struct vty *vty, const char *com, int exact, afi_t afi, safi_t safi) { struct community_list *list; list = community_list_lookup (bgp_clist, com, COMMUNITY_LIST_MASTER); if (list == NULL) { vty_out (vty, "%% %s is not a valid community-list name%s", com, VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, NULL, afi, safi, (exact ? bgp_show_type_community_list_exact : bgp_show_type_community_list), list); } DEFUN (show_ip_bgp_community_list, show_ip_bgp_community_list_cmd, "show ip bgp community-list (<1-500>|WORD)", SHOW_STR IP_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_community_list, show_ip_bgp_ipv4_community_list_cmd, "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD)", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_MULTICAST); return bgp_show_community_list (vty, argv[1], 0, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_community_list_exact, show_ip_bgp_community_list_exact_cmd, "show ip bgp community-list (<1-500>|WORD) exact-match", SHOW_STR IP_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_community_list_exact, show_ip_bgp_ipv4_community_list_exact_cmd, "show ip bgp ipv4 (unicast|multicast) community-list (<1-500>|WORD) exact-match", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_MULTICAST); return bgp_show_community_list (vty, argv[1], 1, AFI_IP, SAFI_UNICAST); } #ifdef HAVE_IPV6 DEFUN (show_bgp_community_list, show_bgp_community_list_cmd, "show bgp community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_list, show_bgp_ipv6_community_list_cmd, "show bgp ipv6 community-list (<1-500>|WORD)", SHOW_STR BGP_STR "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n") /* old command */ DEFUN (show_ipv6_bgp_community_list, show_ipv6_bgp_community_list_cmd, "show ipv6 bgp community-list WORD", SHOW_STR IPV6_STR BGP_STR "Display routes matching the community-list\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_community_list, show_ipv6_mbgp_community_list_cmd, "show ipv6 mbgp community-list WORD", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the community-list\n" "community-list name\n") { return bgp_show_community_list (vty, argv[0], 0, AFI_IP6, SAFI_MULTICAST); } DEFUN (show_bgp_community_list_exact, show_bgp_community_list_exact_cmd, "show bgp community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); } ALIAS (show_bgp_community_list_exact, show_bgp_ipv6_community_list_exact_cmd, "show bgp ipv6 community-list (<1-500>|WORD) exact-match", SHOW_STR BGP_STR "Address family\n" "Display routes matching the community-list\n" "community-list number\n" "community-list name\n" "Exact match of the communities\n") /* old command */ DEFUN (show_ipv6_bgp_community_list_exact, show_ipv6_bgp_community_list_exact_cmd, "show ipv6 bgp community-list WORD exact-match", SHOW_STR IPV6_STR BGP_STR "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_UNICAST); } /* old command */ DEFUN (show_ipv6_mbgp_community_list_exact, show_ipv6_mbgp_community_list_exact_cmd, "show ipv6 mbgp community-list WORD exact-match", SHOW_STR IPV6_STR MBGP_STR "Display routes matching the community-list\n" "community-list name\n" "Exact match of the communities\n") { return bgp_show_community_list (vty, argv[0], 1, AFI_IP6, SAFI_MULTICAST); } #endif /* HAVE_IPV6 */ static int bgp_show_prefix_longer (struct vty *vty, const char *prefix, afi_t afi, safi_t safi, enum bgp_show_type type) { int ret; struct prefix *p; p = prefix_new(); ret = str2prefix (prefix, p); if (! ret) { vty_out (vty, "%% Malformed Prefix%s", VTY_NEWLINE); return CMD_WARNING; } ret = bgp_show (vty, NULL, afi, safi, type, p); prefix_free(p); return ret; } DEFUN (show_ip_bgp_prefix_longer, show_ip_bgp_prefix_longer_cmd, "show ip bgp A.B.C.D/M longer-prefixes", SHOW_STR IP_STR BGP_STR "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_longer); } DEFUN (show_ip_bgp_flap_prefix_longer, show_ip_bgp_flap_prefix_longer_cmd, "show ip bgp flap-statistics A.B.C.D/M longer-prefixes", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_prefix_longer); } DEFUN (show_ip_bgp_ipv4_prefix_longer, show_ip_bgp_ipv4_prefix_longer_cmd, "show ip bgp ipv4 (unicast|multicast) A.B.C.D/M longer-prefixes", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "IP prefix /, e.g., 35.0.0.0/8\n" "Display route and more specific routes\n") { if (strncmp (argv[0], "m", 1) == 0) return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_MULTICAST, bgp_show_type_prefix_longer); return bgp_show_prefix_longer (vty, argv[1], AFI_IP, SAFI_UNICAST, bgp_show_type_prefix_longer); } DEFUN (show_ip_bgp_flap_address, show_ip_bgp_flap_address_cmd, "show ip bgp flap-statistics A.B.C.D", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "Network in the BGP routing table to display\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_address); } DEFUN (show_ip_bgp_flap_prefix, show_ip_bgp_flap_prefix_cmd, "show ip bgp flap-statistics A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP, SAFI_UNICAST, bgp_show_type_flap_prefix); } #ifdef HAVE_IPV6 DEFUN (show_bgp_prefix_longer, show_bgp_prefix_longer_cmd, "show bgp X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "IPv6 prefix /\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } ALIAS (show_bgp_prefix_longer, show_bgp_ipv6_prefix_longer_cmd, "show bgp ipv6 X:X::X:X/M longer-prefixes", SHOW_STR BGP_STR "Address family\n" "IPv6 prefix /\n" "Display route and more specific routes\n") /* old command */ DEFUN (show_ipv6_bgp_prefix_longer, show_ipv6_bgp_prefix_longer_cmd, "show ipv6 bgp X:X::X:X/M longer-prefixes", SHOW_STR IPV6_STR BGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_UNICAST, bgp_show_type_prefix_longer); } /* old command */ DEFUN (show_ipv6_mbgp_prefix_longer, show_ipv6_mbgp_prefix_longer_cmd, "show ipv6 mbgp X:X::X:X/M longer-prefixes", SHOW_STR IPV6_STR MBGP_STR "IPv6 prefix /, e.g., 3ffe::/16\n" "Display route and more specific routes\n") { return bgp_show_prefix_longer (vty, argv[0], AFI_IP6, SAFI_MULTICAST, bgp_show_type_prefix_longer); } #endif /* HAVE_IPV6 */ static struct peer * peer_lookup_in_view (struct vty *vty, const char *view_name, const char *ip_str) { int ret; struct bgp *bgp; struct peer *peer; union sockunion su; /* BGP structure lookup. */ if (view_name) { bgp = bgp_lookup_by_name (view_name); if (! bgp) { vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE); return NULL; } } else { bgp = bgp_get_default (); if (! bgp) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return NULL; } } /* Get peer sockunion. */ ret = str2sockunion (ip_str, &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", ip_str, VTY_NEWLINE); return NULL; } /* Peer structure lookup. */ peer = peer_lookup (bgp, &su); if (! peer) { vty_out (vty, "No such neighbor%s", VTY_NEWLINE); return NULL; } return peer; } enum bgp_stats { BGP_STATS_MAXBITLEN = 0, BGP_STATS_RIB, BGP_STATS_PREFIXES, BGP_STATS_TOTPLEN, BGP_STATS_UNAGGREGATEABLE, BGP_STATS_MAX_AGGREGATEABLE, BGP_STATS_AGGREGATES, BGP_STATS_SPACE, BGP_STATS_ASPATH_COUNT, BGP_STATS_ASPATH_MAXHOPS, BGP_STATS_ASPATH_TOTHOPS, BGP_STATS_ASPATH_MAXSIZE, BGP_STATS_ASPATH_TOTSIZE, BGP_STATS_ASN_HIGHEST, BGP_STATS_MAX, }; static const char *table_stats_strs[] = { [BGP_STATS_PREFIXES] = "Total Prefixes", [BGP_STATS_TOTPLEN] = "Average prefix length", [BGP_STATS_RIB] = "Total Advertisements", [BGP_STATS_UNAGGREGATEABLE] = "Unaggregateable prefixes", [BGP_STATS_MAX_AGGREGATEABLE] = "Maximum aggregateable prefixes", [BGP_STATS_AGGREGATES] = "BGP Aggregate advertisements", [BGP_STATS_SPACE] = "Address space advertised", [BGP_STATS_ASPATH_COUNT] = "Advertisements with paths", [BGP_STATS_ASPATH_MAXHOPS] = "Longest AS-Path (hops)", [BGP_STATS_ASPATH_MAXSIZE] = "Largest AS-Path (bytes)", [BGP_STATS_ASPATH_TOTHOPS] = "Average AS-Path length (hops)", [BGP_STATS_ASPATH_TOTSIZE] = "Average AS-Path size (bytes)", [BGP_STATS_ASN_HIGHEST] = "Highest public ASN", [BGP_STATS_MAX] = NULL, }; struct bgp_table_stats { struct bgp_table *table; unsigned long long counts[BGP_STATS_MAX]; }; #if 0 #define TALLY_SIGFIG 100000 static unsigned long ravg_tally (unsigned long count, unsigned long oldavg, unsigned long newval) { unsigned long newtot = (count-1) * oldavg + (newval * TALLY_SIGFIG); unsigned long res = (newtot * TALLY_SIGFIG) / count; unsigned long ret = newtot / count; if ((res % TALLY_SIGFIG) > (TALLY_SIGFIG/2)) return ret + 1; else return ret; } #endif static int bgp_table_stats_walker (struct thread *t) { struct bgp_node *rn; struct bgp_node *top; struct bgp_table_stats *ts = THREAD_ARG (t); unsigned int space = 0; if (!(top = bgp_table_top (ts->table))) return 0; switch (top->p.family) { case AF_INET: space = IPV4_MAX_BITLEN; break; case AF_INET6: space = IPV6_MAX_BITLEN; break; } ts->counts[BGP_STATS_MAXBITLEN] = space; for (rn = top; rn; rn = bgp_route_next (rn)) { struct bgp_info *ri; struct bgp_node *prn = bgp_node_parent_nolock (rn); unsigned int rinum = 0; if (rn == top) continue; if (!rn->info) continue; ts->counts[BGP_STATS_PREFIXES]++; ts->counts[BGP_STATS_TOTPLEN] += rn->p.prefixlen; #if 0 ts->counts[BGP_STATS_AVGPLEN] = ravg_tally (ts->counts[BGP_STATS_PREFIXES], ts->counts[BGP_STATS_AVGPLEN], rn->p.prefixlen); #endif /* check if the prefix is included by any other announcements */ while (prn && !prn->info) prn = bgp_node_parent_nolock (prn); if (prn == NULL || prn == top) { ts->counts[BGP_STATS_UNAGGREGATEABLE]++; /* announced address space */ if (space) ts->counts[BGP_STATS_SPACE] += 1 << (space - rn->p.prefixlen); } else if (prn->info) ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; for (ri = rn->info; ri; ri = ri->next) { rinum++; ts->counts[BGP_STATS_RIB]++; if (ri->attr && (CHECK_FLAG (ri->attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)))) ts->counts[BGP_STATS_AGGREGATES]++; /* as-path stats */ if (ri->attr && ri->attr->aspath) { unsigned int hops = aspath_count_hops (ri->attr->aspath); unsigned int size = aspath_size (ri->attr->aspath); as_t highest = aspath_highest (ri->attr->aspath); ts->counts[BGP_STATS_ASPATH_COUNT]++; if (hops > ts->counts[BGP_STATS_ASPATH_MAXHOPS]) ts->counts[BGP_STATS_ASPATH_MAXHOPS] = hops; if (size > ts->counts[BGP_STATS_ASPATH_MAXSIZE]) ts->counts[BGP_STATS_ASPATH_MAXSIZE] = size; ts->counts[BGP_STATS_ASPATH_TOTHOPS] += hops; ts->counts[BGP_STATS_ASPATH_TOTSIZE] += size; #if 0 ts->counts[BGP_STATS_ASPATH_AVGHOPS] = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], ts->counts[BGP_STATS_ASPATH_AVGHOPS], hops); ts->counts[BGP_STATS_ASPATH_AVGSIZE] = ravg_tally (ts->counts[BGP_STATS_ASPATH_COUNT], ts->counts[BGP_STATS_ASPATH_AVGSIZE], size); #endif if (highest > ts->counts[BGP_STATS_ASN_HIGHEST]) ts->counts[BGP_STATS_ASN_HIGHEST] = highest; } } } return 0; } static int bgp_table_stats (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_table_stats ts; unsigned int i; if (!bgp->rib[afi][safi]) { vty_out (vty, "%% No RIB exist for the AFI/SAFI%s", VTY_NEWLINE); return CMD_WARNING; } memset (&ts, 0, sizeof (ts)); ts.table = bgp->rib[afi][safi]; thread_execute (bm->master, bgp_table_stats_walker, &ts, 0); vty_out (vty, "BGP %s RIB statistics%s%s", afi_safi_print (afi, safi), VTY_NEWLINE, VTY_NEWLINE); for (i = 0; i < BGP_STATS_MAX; i++) { if (!table_stats_strs[i]) continue; switch (i) { #if 0 case BGP_STATS_ASPATH_AVGHOPS: case BGP_STATS_ASPATH_AVGSIZE: case BGP_STATS_AVGPLEN: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", (float)ts.counts[i] / (float)TALLY_SIGFIG); break; #endif case BGP_STATS_ASPATH_TOTHOPS: case BGP_STATS_ASPATH_TOTSIZE: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", ts.counts[i] ? (float)ts.counts[i] / (float)ts.counts[BGP_STATS_ASPATH_COUNT] : 0); break; case BGP_STATS_TOTPLEN: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12.2f", ts.counts[i] ? (float)ts.counts[i] / (float)ts.counts[BGP_STATS_PREFIXES] : 0); break; case BGP_STATS_SPACE: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12llu%s", ts.counts[i], VTY_NEWLINE); if (ts.counts[BGP_STATS_MAXBITLEN] < 9) break; vty_out (vty, "%30s: ", "%% announced "); vty_out (vty, "%12.2f%s", 100 * (float)ts.counts[BGP_STATS_SPACE] / (float)((uint64_t)1UL << ts.counts[BGP_STATS_MAXBITLEN]), VTY_NEWLINE); vty_out (vty, "%30s: ", "/8 equivalent "); vty_out (vty, "%12.2f%s", (float)ts.counts[BGP_STATS_SPACE] / (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 8)), VTY_NEWLINE); if (ts.counts[BGP_STATS_MAXBITLEN] < 25) break; vty_out (vty, "%30s: ", "/24 equivalent "); vty_out (vty, "%12.2f", (float)ts.counts[BGP_STATS_SPACE] / (float)(1UL << (ts.counts[BGP_STATS_MAXBITLEN] - 24))); break; default: vty_out (vty, "%-30s: ", table_stats_strs[i]); vty_out (vty, "%12llu", ts.counts[i]); } vty_out (vty, "%s", VTY_NEWLINE); } return CMD_SUCCESS; } static int bgp_table_stats_vty (struct vty *vty, const char *name, const char *afi_str, const char *safi_str) { struct bgp *bgp; afi_t afi; safi_t safi; if (name) bgp = bgp_lookup_by_name (name); else bgp = bgp_get_default (); if (!bgp) { vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE); return CMD_WARNING; } if (strncmp (afi_str, "ipv", 3) == 0) { if (strncmp (afi_str, "ipv4", 4) == 0) afi = AFI_IP; else if (strncmp (afi_str, "ipv6", 4) == 0) afi = AFI_IP6; else { vty_out (vty, "%% Invalid address family %s%s", afi_str, VTY_NEWLINE); return CMD_WARNING; } if (strncmp (safi_str, "m", 1) == 0) safi = SAFI_MULTICAST; else if (strncmp (safi_str, "u", 1) == 0) safi = SAFI_UNICAST; else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) safi = SAFI_MPLS_LABELED_VPN; else { vty_out (vty, "%% Invalid subsequent address family %s%s", safi_str, VTY_NEWLINE); return CMD_WARNING; } } else { vty_out (vty, "%% Invalid address family %s%s", afi_str, VTY_NEWLINE); return CMD_WARNING; } return bgp_table_stats (vty, bgp, afi, safi); } DEFUN (show_bgp_statistics, show_bgp_statistics_cmd, "show bgp (ipv4|ipv6) (unicast|multicast) statistics", SHOW_STR BGP_STR "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } ALIAS (show_bgp_statistics, show_bgp_statistics_vpnv4_cmd, "show bgp (ipv4) (vpnv4) statistics", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") DEFUN (show_bgp_statistics_view, show_bgp_statistics_view_cmd, "show bgp view WORD (ipv4|ipv6) (unicast|multicast) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") { return bgp_table_stats_vty (vty, NULL, argv[0], argv[1]); } ALIAS (show_bgp_statistics_view, show_bgp_statistics_view_vpnv4_cmd, "show bgp view WORD (ipv4) (vpnv4) statistics", SHOW_STR BGP_STR "BGP view\n" "Address family\n" "Address Family modifier\n" "BGP RIB advertisement statistics\n") enum bgp_pcounts { PCOUNT_ADJ_IN = 0, PCOUNT_DAMPED, PCOUNT_REMOVED, PCOUNT_HISTORY, PCOUNT_STALE, PCOUNT_VALID, PCOUNT_ALL, PCOUNT_COUNTED, PCOUNT_PFCNT, /* the figure we display to users */ PCOUNT_MAX, }; static const char *pcount_strs[] = { [PCOUNT_ADJ_IN] = "Adj-in", [PCOUNT_DAMPED] = "Damped", [PCOUNT_REMOVED] = "Removed", [PCOUNT_HISTORY] = "History", [PCOUNT_STALE] = "Stale", [PCOUNT_VALID] = "Valid", [PCOUNT_ALL] = "All RIB", [PCOUNT_COUNTED] = "PfxCt counted", [PCOUNT_PFCNT] = "Useable", [PCOUNT_MAX] = NULL, }; struct peer_pcounts { unsigned int count[PCOUNT_MAX]; const struct peer *peer; const struct bgp_table *table; }; static int bgp_peer_count_walker (struct thread *t) { struct bgp_node *rn; struct peer_pcounts *pc = THREAD_ARG (t); const struct peer *peer = pc->peer; for (rn = bgp_table_top (pc->table); rn; rn = bgp_route_next (rn)) { struct bgp_adj_in *ain; struct bgp_info *ri; for (ain = rn->adj_in; ain; ain = ain->next) if (ain->peer == peer) pc->count[PCOUNT_ADJ_IN]++; for (ri = rn->info; ri; ri = ri->next) { char buf[SU_ADDRSTRLEN]; if (ri->peer != peer) continue; pc->count[PCOUNT_ALL]++; if (CHECK_FLAG (ri->flags, BGP_INFO_DAMPED)) pc->count[PCOUNT_DAMPED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)) pc->count[PCOUNT_HISTORY]++; if (CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)) pc->count[PCOUNT_REMOVED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_STALE)) pc->count[PCOUNT_STALE]++; if (CHECK_FLAG (ri->flags, BGP_INFO_VALID)) pc->count[PCOUNT_VALID]++; if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) pc->count[PCOUNT_PFCNT]++; if (CHECK_FLAG (ri->flags, BGP_INFO_COUNTED)) { pc->count[PCOUNT_COUNTED]++; if (CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) plog_warn (peer->log, "%s [pcount] %s/%d is counted but flags 0x%x", peer->host, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, SU_ADDRSTRLEN), rn->p.prefixlen, ri->flags); } else { if (!CHECK_FLAG (ri->flags, BGP_INFO_UNUSEABLE)) plog_warn (peer->log, "%s [pcount] %s/%d not counted but flags 0x%x", peer->host, inet_ntop(rn->p.family, &rn->p.u.prefix, buf, SU_ADDRSTRLEN), rn->p.prefixlen, ri->flags); } } } return 0; } static int bgp_peer_counts (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) { struct peer_pcounts pcounts = { .peer = peer }; unsigned int i; if (!peer || !peer->bgp || !peer->afc[afi][safi] || !peer->bgp->rib[afi][safi]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } memset (&pcounts, 0, sizeof(pcounts)); pcounts.peer = peer; pcounts.table = peer->bgp->rib[afi][safi]; /* in-place call via thread subsystem so as to record execution time * stats for the thread-walk (i.e. ensure this can't be blamed on * on just vty_read()). */ thread_execute (bm->master, bgp_peer_count_walker, &pcounts, 0); vty_out (vty, "Prefix counts for %s, %s%s", peer->host, afi_safi_print (afi, safi), VTY_NEWLINE); vty_out (vty, "PfxCt: %ld%s", peer->pcount[afi][safi], VTY_NEWLINE); vty_out (vty, "%sCounts from RIB table walk:%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); for (i = 0; i < PCOUNT_MAX; i++) vty_out (vty, "%20s: %-10d%s", pcount_strs[i], pcounts.count[i], VTY_NEWLINE); if (pcounts.count[PCOUNT_PFCNT] != peer->pcount[afi][safi]) { vty_out (vty, "%s [pcount] PfxCt drift!%s", peer->host, VTY_NEWLINE); vty_out (vty, "Please report this bug, with the above command output%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (show_ip_bgp_neighbor_prefix_counts, show_ip_bgp_neighbor_prefix_counts_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); } DEFUN (show_bgp_ipv6_neighbor_prefix_counts, show_bgp_ipv6_neighbor_prefix_counts_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP6, SAFI_UNICAST); } DEFUN (show_ip_bgp_ipv4_neighbor_prefix_counts, show_ip_bgp_ipv4_neighbor_prefix_counts_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MULTICAST); return bgp_peer_counts (vty, peer, AFI_IP, SAFI_UNICAST); } DEFUN (show_ip_bgp_vpnv4_neighbor_prefix_counts, show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd, "show ip bgp vpnv4 all neighbors (A.B.C.D|X:X::X:X) prefix-counts", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display detailed prefix count information\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_peer_counts (vty, peer, AFI_IP, SAFI_MPLS_VPN); } static void show_adj_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in) { struct bgp_table *table; struct bgp_adj_in *ain; struct bgp_adj_out *adj; unsigned long output_count; struct bgp_node *rn; int header1 = 1; struct bgp *bgp; int header2 = 1; bgp = peer->bgp; if (! bgp) return; table = bgp->rib[afi][safi]; output_count = 0; if (! in && CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE)) { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, "Originating default network 0.0.0.0%s%s", VTY_NEWLINE, VTY_NEWLINE); header1 = 0; } for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if (in) { for (ain = rn->adj_in; ain; ain = ain->next) if (ain->peer == peer) { if (header1) { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); header1 = 0; } if (header2) { vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); header2 = 0; } if (ain->attr) { route_vty_out_tmp (vty, &rn->p, ain->attr, safi); output_count++; } } } else { for (adj = rn->adj_out; adj; adj = adj->next) if (adj->peer == peer) { if (header1) { vty_out (vty, "BGP table version is 0, local router ID is %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE); header1 = 0; } if (header2) { vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE); header2 = 0; } if (adj->attr) { route_vty_out_tmp (vty, &rn->p, adj->attr, safi); output_count++; } } } if (output_count != 0) vty_out (vty, "%sTotal number of prefixes %ld%s", VTY_NEWLINE, output_count, VTY_NEWLINE); } static int peer_adj_routes (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, int in) { if (! peer || ! peer->afc[afi][safi]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } if (in && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) { vty_out (vty, "%% Inbound soft reconfiguration not enabled%s", VTY_NEWLINE); return CMD_WARNING; } show_adj_route (vty, peer, afi, safi, in); return CMD_SUCCESS; } DEFUN (show_ip_bgp_view_neighbor_advertised_route, show_ip_bgp_view_neighbor_advertised_route_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } ALIAS (show_ip_bgp_view_neighbor_advertised_route, show_ip_bgp_neighbor_advertised_route_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFUN (show_ip_bgp_ipv4_neighbor_advertised_route, show_ip_bgp_ipv4_neighbor_advertised_route_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 0); return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 0); } #ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_advertised_route, show_bgp_view_neighbor_advertised_route_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 0); } ALIAS (show_bgp_view_neighbor_advertised_route, show_bgp_view_ipv6_neighbor_advertised_route_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") DEFUN (show_bgp_view_neighbor_received_routes, show_bgp_view_neighbor_received_routes_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_UNICAST, 1); } ALIAS (show_bgp_view_neighbor_received_routes, show_bgp_view_ipv6_neighbor_received_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") ALIAS (show_bgp_view_neighbor_advertised_route, show_bgp_neighbor_advertised_route_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") ALIAS (show_bgp_view_neighbor_advertised_route, show_bgp_ipv6_neighbor_advertised_route_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") /* old command */ ALIAS (show_bgp_view_neighbor_advertised_route, ipv6_bgp_neighbor_advertised_route_cmd, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR IPV6_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") /* old command */ DEFUN (ipv6_mbgp_neighbor_advertised_route, ipv6_mbgp_neighbor_advertised_route_cmd, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) advertised-routes", SHOW_STR IPV6_STR MBGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the routes advertised to a BGP neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 0); } #endif /* HAVE_IPV6 */ DEFUN (show_ip_bgp_view_neighbor_received_routes, show_ip_bgp_view_neighbor_received_routes_cmd, "show ip bgp view WORD neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } ALIAS (show_ip_bgp_view_neighbor_received_routes, show_ip_bgp_neighbor_received_routes_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFUN (show_ip_bgp_ipv4_neighbor_received_routes, show_ip_bgp_ipv4_neighbor_received_routes_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return peer_adj_routes (vty, peer, AFI_IP, SAFI_MULTICAST, 1); return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1); } DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes, show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd, #ifdef HAVE_IPV6 "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", #else "show bgp view WORD ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)", #endif SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" #ifdef HAVE_IPV6 "Address family\n" #endif "Address family modifier\n" "Address family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the advertised routes to neighbor\n" "Display the received routes from neighbor\n") { int afi; int safi; int in; struct peer *peer; #ifdef HAVE_IPV6 peer = peer_lookup_in_view (vty, argv[0], argv[3]); #else peer = peer_lookup_in_view (vty, argv[0], argv[2]); #endif if (! peer) return CMD_WARNING; #ifdef HAVE_IPV6 afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP; safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0; #else afi = AFI_IP; safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; in = (strncmp (argv[3], "r", 1) == 0) ? 1 : 0; #endif return peer_adj_routes (vty, peer, afi, safi, in); } DEFUN (show_ip_bgp_neighbor_received_prefix_filter, show_ip_bgp_neighbor_received_prefix_filter_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") { char name[BUFSIZ]; union sockunion su; struct peer *peer; int count, ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); if (count) { vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP, name); } return CMD_SUCCESS; } DEFUN (show_ip_bgp_ipv4_neighbor_received_prefix_filter, show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") { char name[BUFSIZ]; union sockunion su; struct peer *peer; int count, ret; ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) { sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_MULTICAST); count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); if (count) { vty_out (vty, "Address family: IPv4 Multicast%s", VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP, name); } } else { sprintf (name, "%s.%d.%d", peer->host, AFI_IP, SAFI_UNICAST); count = prefix_bgp_show_prefix_list (NULL, AFI_IP, name); if (count) { vty_out (vty, "Address family: IPv4 Unicast%s", VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP, name); } } return CMD_SUCCESS; } #ifdef HAVE_IPV6 ALIAS (show_bgp_view_neighbor_received_routes, show_bgp_neighbor_received_routes_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") ALIAS (show_bgp_view_neighbor_received_routes, show_bgp_ipv6_neighbor_received_routes_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") DEFUN (show_bgp_neighbor_received_prefix_filter, show_bgp_neighbor_received_prefix_filter_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") { char name[BUFSIZ]; union sockunion su; struct peer *peer; int count, ret; ret = str2sockunion (argv[0], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (NULL, &su); if (! peer) return CMD_WARNING; sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); if (count) { vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP6, name); } return CMD_SUCCESS; } ALIAS (show_bgp_neighbor_received_prefix_filter, show_bgp_ipv6_neighbor_received_prefix_filter_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") /* old command */ ALIAS (show_bgp_view_neighbor_received_routes, ipv6_bgp_neighbor_received_routes_cmd, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IPV6_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") /* old command */ DEFUN (ipv6_mbgp_neighbor_received_routes, ipv6_mbgp_neighbor_received_routes_cmd, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) received-routes", SHOW_STR IPV6_STR MBGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the received routes from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return peer_adj_routes (vty, peer, AFI_IP6, SAFI_MULTICAST, 1); } DEFUN (show_bgp_view_neighbor_received_prefix_filter, show_bgp_view_neighbor_received_prefix_filter_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") { char name[BUFSIZ]; union sockunion su; struct peer *peer; struct bgp *bgp; int count, ret; /* BGP structure lookup. */ bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } ret = str2sockunion (argv[1], &su); if (ret < 0) { vty_out (vty, "Malformed address: %s%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } peer = peer_lookup (bgp, &su); if (! peer) return CMD_WARNING; sprintf (name, "%s.%d.%d", peer->host, AFI_IP6, SAFI_UNICAST); count = prefix_bgp_show_prefix_list (NULL, AFI_IP6, name); if (count) { vty_out (vty, "Address family: IPv6 Unicast%s", VTY_NEWLINE); prefix_bgp_show_prefix_list (vty, AFI_IP6, name); } return CMD_SUCCESS; } ALIAS (show_bgp_view_neighbor_received_prefix_filter, show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) received prefix-filter", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display information received from a BGP neighbor\n" "Display the prefixlist filter\n") #endif /* HAVE_IPV6 */ static int bgp_show_neighbor_route (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, enum bgp_show_type type) { if (! peer || ! peer->afc[afi][safi]) { vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show (vty, peer->bgp, afi, safi, type, &peer->su); } DEFUN (show_ip_bgp_neighbor_routes, show_ip_bgp_neighbor_routes_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, bgp_show_type_neighbor); } DEFUN (show_ip_bgp_neighbor_flap, show_ip_bgp_neighbor_flap_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_neighbor); } DEFUN (show_ip_bgp_neighbor_damp, show_ip_bgp_neighbor_damp_cmd, "show ip bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR IP_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, bgp_show_type_damp_neighbor); } DEFUN (show_ip_bgp_ipv4_neighbor_routes, show_ip_bgp_ipv4_neighbor_routes_cmd, "show ip bgp ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR IP_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[1]); if (! peer) return CMD_WARNING; if (strncmp (argv[0], "m", 1) == 0) return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_MULTICAST, bgp_show_type_neighbor); return bgp_show_neighbor_route (vty, peer, AFI_IP, SAFI_UNICAST, bgp_show_type_neighbor); } DEFUN (show_ip_bgp_view_rsclient, show_ip_bgp_view_rsclient_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_ip_bgp_view_rsclient, show_ip_bgp_rsclient_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_ipv4_safi_rsclient, show_bgp_view_ipv4_safi_rsclient_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; safi_t safi; if (argc == 3) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP][safi]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_ipv4_safi_rsclient, show_bgp_ipv4_safi_rsclient_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_ip_bgp_view_rsclient_route, show_ip_bgp_view_rsclient_route_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP, SAFI_UNICAST, NULL, 0); } ALIAS (show_ip_bgp_view_rsclient_route, show_ip_bgp_rsclient_route_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_view_ipv4_safi_rsclient_route_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP, safi, NULL, 0); } ALIAS (show_bgp_view_ipv4_safi_rsclient_route, show_bgp_ipv4_safi_rsclient_route_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_ip_bgp_view_rsclient_prefix, show_ip_bgp_view_rsclient_prefix_cmd, "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP, SAFI_UNICAST, NULL, 1); } ALIAS (show_ip_bgp_view_rsclient_prefix, show_ip_bgp_rsclient_prefix_cmd, "show ip bgp rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR IP_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_view_ipv4_safi_rsclient_prefix_cmd, "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP, safi, NULL, 1); } ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix, show_bgp_ipv4_safi_rsclient_prefix_cmd, "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 35.0.0.0/8\n") #ifdef HAVE_IPV6 DEFUN (show_bgp_view_neighbor_routes, show_bgp_view_neighbor_routes_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_neighbor); } ALIAS (show_bgp_view_neighbor_routes, show_bgp_view_ipv6_neighbor_routes_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") DEFUN (show_bgp_view_neighbor_damp, show_bgp_view_neighbor_damp_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_damp_neighbor); } ALIAS (show_bgp_view_neighbor_damp, show_bgp_view_ipv6_neighbor_damp_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFUN (show_bgp_view_neighbor_flap, show_bgp_view_neighbor_flap_cmd, "show bgp view WORD neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") { struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_UNICAST, bgp_show_type_flap_neighbor); } ALIAS (show_bgp_view_neighbor_flap, show_bgp_view_ipv6_neighbor_flap_cmd, "show bgp view WORD ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_routes, show_bgp_neighbor_routes_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_routes, show_bgp_ipv6_neighbor_routes_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") /* old command */ ALIAS (show_bgp_view_neighbor_routes, ipv6_bgp_neighbor_routes_cmd, "show ipv6 bgp neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR IPV6_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") /* old command */ DEFUN (ipv6_mbgp_neighbor_routes, ipv6_mbgp_neighbor_routes_cmd, "show ipv6 mbgp neighbors (A.B.C.D|X:X::X:X) routes", SHOW_STR IPV6_STR MBGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display routes learned from neighbor\n") { struct peer *peer; peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; return bgp_show_neighbor_route (vty, peer, AFI_IP6, SAFI_MULTICAST, bgp_show_type_neighbor); } ALIAS (show_bgp_view_neighbor_flap, show_bgp_neighbor_flap_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_flap, show_bgp_ipv6_neighbor_flap_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) flap-statistics", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display flap statistics of the routes learned from neighbor\n") ALIAS (show_bgp_view_neighbor_damp, show_bgp_neighbor_damp_cmd, "show bgp neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") ALIAS (show_bgp_view_neighbor_damp, show_bgp_ipv6_neighbor_damp_cmd, "show bgp ipv6 neighbors (A.B.C.D|X:X::X:X) dampened-routes", SHOW_STR BGP_STR "Address family\n" "Detailed information on TCP and BGP neighbor connections\n" "Neighbor to display information about\n" "Neighbor to display information about\n" "Display the dampened routes received from neighbor\n") DEFUN (show_bgp_view_rsclient, show_bgp_view_rsclient_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; if (argc == 2) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP6][SAFI_UNICAST]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_rsclient, show_bgp_rsclient_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_ipv6_safi_rsclient, show_bgp_view_ipv6_safi_rsclient_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) { struct bgp_table *table; struct peer *peer; safi_t safi; if (argc == 3) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } table = peer->rib[AFI_IP6][safi]; return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL); } ALIAS (show_bgp_view_ipv6_safi_rsclient, show_bgp_ipv6_safi_rsclient_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR) DEFUN (show_bgp_view_rsclient_route, show_bgp_view_rsclient_route_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0); } ALIAS (show_bgp_view_rsclient_route, show_bgp_rsclient_route_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_ipv6_safi_rsclient_route, show_bgp_view_ipv6_safi_rsclient_route_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP6, safi, NULL, 0); } ALIAS (show_bgp_view_ipv6_safi_rsclient_route, show_bgp_ipv6_safi_rsclient_route_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "Network in the BGP routing table to display\n") DEFUN (show_bgp_view_rsclient_prefix, show_bgp_view_rsclient_prefix_cmd, "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") { struct bgp *bgp; struct peer *peer; /* BGP structure lookup. */ if (argc == 3) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 3) peer = peer_lookup_in_view (vty, argv[0], argv[1]); else peer = peer_lookup_in_view (vty, NULL, argv[0]); if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][SAFI_UNICAST]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][SAFI_UNICAST], (argc == 3) ? argv[2] : argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1); } ALIAS (show_bgp_view_rsclient_prefix, show_bgp_rsclient_prefix_cmd, "show bgp rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IPv6 prefix /, e.g., 3ffe::/16\n") DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix, show_bgp_view_ipv6_safi_rsclient_prefix_cmd, "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "BGP view\n" "View name\n" "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 3ffe::/16\n") { struct bgp *bgp; struct peer *peer; safi_t safi; /* BGP structure lookup. */ if (argc == 4) { bgp = bgp_lookup_by_name (argv[0]); if (bgp == NULL) { vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } if (argc == 4) { peer = peer_lookup_in_view (vty, argv[0], argv[2]); safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } else { peer = peer_lookup_in_view (vty, NULL, argv[1]); safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST; } if (! peer) return CMD_WARNING; if (! peer->afc[AFI_IP6][safi]) { vty_out (vty, "%% Activate the neighbor for the address family first%s", VTY_NEWLINE); return CMD_WARNING; } if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi], PEER_FLAG_RSERVER_CLIENT)) { vty_out (vty, "%% Neighbor is not a Route-Server client%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi], (argc == 4) ? argv[3] : argv[2], AFI_IP6, safi, NULL, 1); } ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix, show_bgp_ipv6_safi_rsclient_prefix_cmd, "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M", SHOW_STR BGP_STR "Address family\n" "Address Family modifier\n" "Address Family modifier\n" "Information about Route Server Client\n" NEIGHBOR_ADDR_STR "IP prefix /, e.g., 3ffe::/16\n") #endif /* HAVE_IPV6 */ struct bgp_table *bgp_distance_table; struct bgp_distance { /* Distance value for the IP source prefix. */ u_char distance; /* Name of the access-list to be matched. */ char *access_list; }; static struct bgp_distance * bgp_distance_new (void) { return XCALLOC (MTYPE_BGP_DISTANCE, sizeof (struct bgp_distance)); } static void bgp_distance_free (struct bgp_distance *bdistance) { XFREE (MTYPE_BGP_DISTANCE, bdistance); } static int bgp_distance_set (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); /* Get BGP distance node. */ rn = bgp_node_get (bgp_distance_table, (struct prefix *) &p); if (rn->info) { bdistance = rn->info; bgp_unlock_node (rn); } else { bdistance = bgp_distance_new (); rn->info = bdistance; } /* Set distance value. */ bdistance->distance = distance; /* Reset access-list configuration. */ if (bdistance->access_list) { free (bdistance->access_list); bdistance->access_list = NULL; } if (access_list_str) bdistance->access_list = strdup (access_list_str); return CMD_SUCCESS; } static int bgp_distance_unset (struct vty *vty, const char *distance_str, const char *ip_str, const char *access_list_str) { int ret; struct prefix_ipv4 p; u_char distance; struct bgp_node *rn; struct bgp_distance *bdistance; ret = str2prefix_ipv4 (ip_str, &p); if (ret == 0) { vty_out (vty, "Malformed prefix%s", VTY_NEWLINE); return CMD_WARNING; } distance = atoi (distance_str); rn = bgp_node_lookup (bgp_distance_table, (struct prefix *)&p); if (! rn) { vty_out (vty, "Can't find specified prefix%s", VTY_NEWLINE); return CMD_WARNING; } bdistance = rn->info; if (bdistance->distance != distance) { vty_out (vty, "Distance does not match configured%s", VTY_NEWLINE); return CMD_WARNING; } if (bdistance->access_list) free (bdistance->access_list); bgp_distance_free (bdistance); rn->info = NULL; bgp_unlock_node (rn); bgp_unlock_node (rn); return CMD_SUCCESS; } /* Apply BGP information to distance method. */ u_char bgp_distance_apply (struct prefix *p, struct bgp_info *rinfo, struct bgp *bgp) { struct bgp_node *rn; struct prefix_ipv4 q; struct peer *peer; struct bgp_distance *bdistance; struct access_list *alist; struct bgp_static *bgp_static; if (! bgp) return 0; if (p->family != AF_INET) return 0; peer = rinfo->peer; if (peer->su.sa.sa_family != AF_INET) return 0; memset (&q, 0, sizeof (struct prefix_ipv4)); q.family = AF_INET; q.prefix = peer->su.sin.sin_addr; q.prefixlen = IPV4_MAX_BITLEN; /* Check source address. */ rn = bgp_node_match (bgp_distance_table, (struct prefix *) &q); if (rn) { bdistance = rn->info; bgp_unlock_node (rn); if (bdistance->access_list) { alist = access_list_lookup (AFI_IP, bdistance->access_list); if (alist && access_list_apply (alist, p) == FILTER_PERMIT) return bdistance->distance; } else return bdistance->distance; } /* Backdoor check. */ rn = bgp_node_lookup (bgp->route[AFI_IP][SAFI_UNICAST], p); if (rn) { bgp_static = rn->info; bgp_unlock_node (rn); if (bgp_static->backdoor) { if (bgp->distance_local) return bgp->distance_local; else return ZEBRA_IBGP_DISTANCE_DEFAULT; } } if (peer->sort == BGP_PEER_EBGP) { if (bgp->distance_ebgp) return bgp->distance_ebgp; return ZEBRA_EBGP_DISTANCE_DEFAULT; } else { if (bgp->distance_ibgp) return bgp->distance_ibgp; return ZEBRA_IBGP_DISTANCE_DEFAULT; } } DEFUN (bgp_distance, bgp_distance_cmd, "distance bgp <1-255> <1-255> <1-255>", "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") { struct bgp *bgp; bgp = vty->index; bgp->distance_ebgp = atoi (argv[0]); bgp->distance_ibgp = atoi (argv[1]); bgp->distance_local = atoi (argv[2]); return CMD_SUCCESS; } DEFUN (no_bgp_distance, no_bgp_distance_cmd, "no distance bgp <1-255> <1-255> <1-255>", NO_STR "Define an administrative distance\n" "BGP distance\n" "Distance for routes external to the AS\n" "Distance for routes internal to the AS\n" "Distance for local routes\n") { struct bgp *bgp; bgp = vty->index; bgp->distance_ebgp= 0; bgp->distance_ibgp = 0; bgp->distance_local = 0; return CMD_SUCCESS; } ALIAS (no_bgp_distance, no_bgp_distance2_cmd, "no distance bgp", NO_STR "Define an administrative distance\n" "BGP distance\n") DEFUN (bgp_distance_source, bgp_distance_source_cmd, "distance <1-255> A.B.C.D/M", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") { bgp_distance_set (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (no_bgp_distance_source, no_bgp_distance_source_cmd, "no distance <1-255> A.B.C.D/M", NO_STR "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n") { bgp_distance_unset (vty, argv[0], argv[1], NULL); return CMD_SUCCESS; } DEFUN (bgp_distance_source_access_list, bgp_distance_source_access_list_cmd, "distance <1-255> A.B.C.D/M WORD", "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") { bgp_distance_set (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (no_bgp_distance_source_access_list, no_bgp_distance_source_access_list_cmd, "no distance <1-255> A.B.C.D/M WORD", NO_STR "Define an administrative distance\n" "Administrative distance\n" "IP source prefix\n" "Access list name\n") { bgp_distance_unset (vty, argv[0], argv[1], argv[2]); return CMD_SUCCESS; } DEFUN (bgp_damp_set, bgp_damp_set_cmd, "bgp dampening <1-45> <1-20000> <1-20000> <1-255>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") { struct bgp *bgp; int half = DEFAULT_HALF_LIFE * 60; int reuse = DEFAULT_REUSE; int suppress = DEFAULT_SUPPRESS; int max = 4 * half; if (argc == 4) { half = atoi (argv[0]) * 60; reuse = atoi (argv[1]); suppress = atoi (argv[2]); max = atoi (argv[3]) * 60; } else if (argc == 1) { half = atoi (argv[0]) * 60; max = 4 * half; } bgp = vty->index; return bgp_damp_enable (bgp, bgp_node_afi (vty), bgp_node_safi (vty), half, reuse, suppress, max); } ALIAS (bgp_damp_set, bgp_damp_set2_cmd, "bgp dampening <1-45>", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n") ALIAS (bgp_damp_set, bgp_damp_set3_cmd, "bgp dampening", "BGP Specific commands\n" "Enable route-flap dampening\n") DEFUN (bgp_damp_unset, bgp_damp_unset_cmd, "no bgp dampening", NO_STR "BGP Specific commands\n" "Enable route-flap dampening\n") { struct bgp *bgp; bgp = vty->index; return bgp_damp_disable (bgp, bgp_node_afi (vty), bgp_node_safi (vty)); } ALIAS (bgp_damp_unset, bgp_damp_unset2_cmd, "no bgp dampening <1-45> <1-20000> <1-20000> <1-255>", NO_STR "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" "Value to start reusing a route\n" "Value to start suppressing a route\n" "Maximum duration to suppress a stable route\n") DEFUN (show_ip_bgp_dampened_paths, show_ip_bgp_dampened_paths_cmd, "show ip bgp dampened-paths", SHOW_STR IP_STR BGP_STR "Display paths suppressed due to dampening\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_dampend_paths, NULL); } DEFUN (show_ip_bgp_flap_statistics, show_ip_bgp_flap_statistics_cmd, "show ip bgp flap-statistics", SHOW_STR IP_STR BGP_STR "Display flap statistics of routes\n") { return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_flap_statistics, NULL); } /* Display specified route of BGP table. */ static int bgp_clear_damp_route (struct vty *vty, const char *view_name, const char *ip_str, afi_t afi, safi_t safi, struct prefix_rd *prd, int prefix_check) { int ret; struct prefix match; struct bgp_node *rn; struct bgp_node *rm; struct bgp_info *ri; struct bgp_info *ri_temp; struct bgp *bgp; struct bgp_table *table; /* BGP structure lookup. */ if (view_name) { bgp = bgp_lookup_by_name (view_name); if (bgp == NULL) { vty_out (vty, "%% Can't find BGP view %s%s", view_name, VTY_NEWLINE); return CMD_WARNING; } } else { bgp = bgp_get_default (); if (bgp == NULL) { vty_out (vty, "%% No BGP process is configured%s", VTY_NEWLINE); return CMD_WARNING; } } /* Check IP address argument. */ ret = str2prefix (ip_str, &match); if (! ret) { vty_out (vty, "%% address is malformed%s", VTY_NEWLINE); return CMD_WARNING; } match.family = afi2family (afi); if (safi == SAFI_MPLS_VPN) { for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) { if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) continue; if ((table = rn->info) != NULL) if ((rm = bgp_node_match (table, &match)) != NULL) { if (! prefix_check || rm->p.prefixlen == match.prefixlen) { ri = rm->info; while (ri) { if (ri->extra && ri->extra->damp_info) { ri_temp = ri->next; bgp_damp_info_free (ri->extra->damp_info, 1); ri = ri_temp; } else ri = ri->next; } } bgp_unlock_node (rm); } } } else { if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL) { if (! prefix_check || rn->p.prefixlen == match.prefixlen) { ri = rn->info; while (ri) { if (ri->extra && ri->extra->damp_info) { ri_temp = ri->next; bgp_damp_info_free (ri->extra->damp_info, 1); ri = ri_temp; } else ri = ri->next; } } bgp_unlock_node (rn); } } return CMD_SUCCESS; } DEFUN (clear_ip_bgp_dampening, clear_ip_bgp_dampening_cmd, "clear ip bgp dampening", CLEAR_STR IP_STR BGP_STR "Clear route flap dampening information\n") { bgp_damp_info_clean (); return CMD_SUCCESS; } DEFUN (clear_ip_bgp_dampening_prefix, clear_ip_bgp_dampening_prefix_cmd, "clear ip bgp dampening A.B.C.D/M", CLEAR_STR IP_STR BGP_STR "Clear route flap dampening information\n" "IP prefix /, e.g., 35.0.0.0/8\n") { return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); } DEFUN (clear_ip_bgp_dampening_address, clear_ip_bgp_dampening_address_cmd, "clear ip bgp dampening A.B.C.D", CLEAR_STR IP_STR BGP_STR "Clear route flap dampening information\n" "Network to clear damping information\n") { return bgp_clear_damp_route (vty, NULL, argv[0], AFI_IP, SAFI_UNICAST, NULL, 0); } DEFUN (clear_ip_bgp_dampening_address_mask, clear_ip_bgp_dampening_address_mask_cmd, "clear ip bgp dampening A.B.C.D A.B.C.D", CLEAR_STR IP_STR BGP_STR "Clear route flap dampening information\n" "Network to clear damping information\n" "Network mask\n") { int ret; char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE); return CMD_WARNING; } return bgp_clear_damp_route (vty, NULL, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 0); } static int bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { struct bgp_node *prn; struct bgp_node *rn; struct bgp_table *table; struct prefix *p; struct prefix_rd *prd; struct bgp_static *bgp_static; u_int32_t label; char buf[SU_ADDRSTRLEN]; char rdbuf[RD_ADDRSTRLEN]; /* Network configuration. */ for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn)) if ((table = prn->info) != NULL) for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { p = &rn->p; prd = (struct prefix_rd *) &prn->p; /* "address-family" display. */ bgp_config_write_family_header (vty, afi, safi, write); /* "network" configuration display. */ prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN); label = decode_label (bgp_static->tag); vty_out (vty, " network %s/%d rd %s tag %d", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen, rdbuf, label); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } /* Configuration of static route announcement and aggregate information. */ int bgp_config_write_network (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, int *write) { struct bgp_node *rn; struct prefix *p; struct bgp_static *bgp_static; struct bgp_aggregate *bgp_aggregate; char buf[SU_ADDRSTRLEN]; if (afi == AFI_IP && safi == SAFI_MPLS_VPN) return bgp_config_write_network_vpnv4 (vty, bgp, afi, safi, write); /* Network configuration. */ for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_static = rn->info) != NULL) { p = &rn->p; /* "address-family" display. */ bgp_config_write_family_header (vty, afi, safi, write); /* "network" configuration display. */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { u_int32_t destination; struct in_addr netmask; destination = ntohl (p->u.prefix4.s_addr); masklen2ip (p->prefixlen, &netmask); vty_out (vty, " network %s", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN)); if ((IN_CLASSC (destination) && p->prefixlen == 24) || (IN_CLASSB (destination) && p->prefixlen == 16) || (IN_CLASSA (destination) && p->prefixlen == 8) || p->u.prefix4.s_addr == 0) { /* Natural mask is not display. */ } else vty_out (vty, " mask %s", inet_ntoa (netmask)); } else { vty_out (vty, " network %s/%d", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } if (bgp_static->rmap.name) vty_out (vty, " route-map %s", bgp_static->rmap.name); else { if (bgp_static->backdoor) vty_out (vty, " backdoor"); } vty_out (vty, "%s", VTY_NEWLINE); } /* Aggregate-address configuration. */ for (rn = bgp_table_top (bgp->aggregate[afi][safi]); rn; rn = bgp_route_next (rn)) if ((bgp_aggregate = rn->info) != NULL) { p = &rn->p; /* "address-family" display. */ bgp_config_write_family_header (vty, afi, safi, write); if (bgp_option_check (BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) { struct in_addr netmask; masklen2ip (p->prefixlen, &netmask); vty_out (vty, " aggregate-address %s %s", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), inet_ntoa (netmask)); } else { vty_out (vty, " aggregate-address %s/%d", inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN), p->prefixlen); } if (bgp_aggregate->as_set) vty_out (vty, " as-set"); if (bgp_aggregate->summary_only) vty_out (vty, " summary-only"); vty_out (vty, "%s", VTY_NEWLINE); } return 0; } int bgp_config_write_distance (struct vty *vty, struct bgp *bgp) { struct bgp_node *rn; struct bgp_distance *bdistance; /* Distance configuration. */ if (bgp->distance_ebgp && bgp->distance_ibgp && bgp->distance_local && (bgp->distance_ebgp != ZEBRA_EBGP_DISTANCE_DEFAULT || bgp->distance_ibgp != ZEBRA_IBGP_DISTANCE_DEFAULT || bgp->distance_local != ZEBRA_IBGP_DISTANCE_DEFAULT)) vty_out (vty, " distance bgp %d %d %d%s", bgp->distance_ebgp, bgp->distance_ibgp, bgp->distance_local, VTY_NEWLINE); for (rn = bgp_table_top (bgp_distance_table); rn; rn = bgp_route_next (rn)) if ((bdistance = rn->info) != NULL) { vty_out (vty, " distance %d %s/%d %s%s", bdistance->distance, inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, bdistance->access_list ? bdistance->access_list : "", VTY_NEWLINE); } return 0; } /* Allocate routing table structure and install commands. */ void bgp_route_init (void) { /* Init BGP distance table. */ bgp_distance_table = bgp_table_init (AFI_IP, SAFI_UNICAST); /* IPv4 BGP commands. */ install_element (BGP_NODE, &bgp_network_cmd); install_element (BGP_NODE, &bgp_network_mask_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_cmd); install_element (BGP_NODE, &bgp_network_route_map_cmd); install_element (BGP_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_route_map_cmd); install_element (BGP_NODE, &bgp_network_backdoor_cmd); install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd); install_element (BGP_NODE, &no_bgp_network_cmd); install_element (BGP_NODE, &no_bgp_network_mask_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd); install_element (BGP_NODE, &no_bgp_network_route_map_cmd); install_element (BGP_NODE, &no_bgp_network_mask_route_map_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_route_map_cmd); install_element (BGP_NODE, &no_bgp_network_backdoor_cmd); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd); install_element (BGP_NODE, &aggregate_address_cmd); install_element (BGP_NODE, &aggregate_address_mask_cmd); install_element (BGP_NODE, &aggregate_address_summary_only_cmd); install_element (BGP_NODE, &aggregate_address_mask_summary_only_cmd); install_element (BGP_NODE, &aggregate_address_as_set_cmd); install_element (BGP_NODE, &aggregate_address_mask_as_set_cmd); install_element (BGP_NODE, &aggregate_address_as_set_summary_cmd); install_element (BGP_NODE, &aggregate_address_mask_as_set_summary_cmd); install_element (BGP_NODE, &aggregate_address_summary_as_set_cmd); install_element (BGP_NODE, &aggregate_address_mask_summary_as_set_cmd); install_element (BGP_NODE, &no_aggregate_address_cmd); install_element (BGP_NODE, &no_aggregate_address_summary_only_cmd); install_element (BGP_NODE, &no_aggregate_address_as_set_cmd); install_element (BGP_NODE, &no_aggregate_address_as_set_summary_cmd); install_element (BGP_NODE, &no_aggregate_address_summary_as_set_cmd); install_element (BGP_NODE, &no_aggregate_address_mask_cmd); install_element (BGP_NODE, &no_aggregate_address_mask_summary_only_cmd); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_cmd); install_element (BGP_NODE, &no_aggregate_address_mask_as_set_summary_cmd); install_element (BGP_NODE, &no_aggregate_address_mask_summary_as_set_cmd); /* IPv4 unicast configuration. */ install_element (BGP_IPV4_NODE, &bgp_network_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_cmd); install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_only_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_as_set_summary_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_as_set_summary_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_summary_as_set_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_summary_as_set_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_only_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_as_set_summary_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_summary_as_set_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_only_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_as_set_summary_cmd); install_element (BGP_IPV4_NODE, &no_aggregate_address_mask_summary_as_set_cmd); /* IPv4 multicast configuration. */ install_element (BGP_IPV4M_NODE, &bgp_network_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_only_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_as_set_summary_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_as_set_summary_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_as_set_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_summary_as_set_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_only_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_as_set_summary_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_summary_as_set_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_only_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_as_set_summary_cmd); install_element (BGP_IPV4M_NODE, &no_aggregate_address_mask_summary_as_set_cmd); install_element (VIEW_NODE, &show_ip_bgp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_all_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_cmd); install_element (VIEW_NODE, &show_ip_bgp_community2_cmd); install_element (VIEW_NODE, &show_ip_bgp_community3_cmd); install_element (VIEW_NODE, &show_ip_bgp_community4_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); install_element (VIEW_NODE, &show_ip_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_ip_bgp_dampened_paths_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_address_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_cidr_only_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_regexp_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_filter_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_list_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_prefix_longer_cmd); install_element (VIEW_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* Restricted node: VIEW_NODE - (set of dangerous commands) */ install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd); install_element (ENABLE_NODE, &show_ip_bgp_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_all_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community2_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community3_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community4_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ip_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_ip_bgp_dampened_paths_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_statistics_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_address_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_cidr_only_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_regexp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_filter_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_list_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ip_bgp_flap_route_map_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd); /* BGP dampening clear commands */ install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_prefix_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_cmd); install_element (ENABLE_NODE, &clear_ip_bgp_dampening_address_mask_cmd); /* prefix count */ install_element (ENABLE_NODE, &show_ip_bgp_neighbor_prefix_counts_cmd); install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_prefix_counts_cmd); install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_neighbor_prefix_counts_cmd); #ifdef HAVE_IPV6 install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_prefix_counts_cmd); /* New config IPv6 BGP commands. */ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd); /* Old config IPv6 BGP commands. */ install_element (BGP_NODE, &old_ipv6_bgp_network_cmd); install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); install_element (BGP_NODE, &old_ipv6_aggregate_address_cmd); install_element (BGP_NODE, &old_ipv6_aggregate_address_summary_only_cmd); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_cmd); install_element (BGP_NODE, &old_no_ipv6_aggregate_address_summary_only_cmd); install_element (VIEW_NODE, &show_bgp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd); install_element (VIEW_NODE, &show_bgp_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (VIEW_NODE, &show_bgp_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (VIEW_NODE, &show_bgp_regexp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd); install_element (VIEW_NODE, &show_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (VIEW_NODE, &show_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (VIEW_NODE, &show_bgp_route_map_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_route_map_cmd); install_element (VIEW_NODE, &show_bgp_community_all_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_all_cmd); install_element (VIEW_NODE, &show_bgp_community_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_cmd); install_element (VIEW_NODE, &show_bgp_community2_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_cmd); install_element (VIEW_NODE, &show_bgp_community3_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_cmd); install_element (VIEW_NODE, &show_bgp_community4_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_cmd); install_element (VIEW_NODE, &show_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (VIEW_NODE, &show_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (VIEW_NODE, &show_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (VIEW_NODE, &show_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (VIEW_NODE, &show_bgp_community_list_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_cmd); install_element (VIEW_NODE, &show_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (VIEW_NODE, &show_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd); install_element (VIEW_NODE, &show_bgp_view_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_route_cmd); install_element (VIEW_NODE, &show_bgp_view_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Restricted: * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev) */ install_element (RESTRICTED_NODE, &show_bgp_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_cmd); install_element (RESTRICTED_NODE, &show_bgp_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd); install_element (ENABLE_NODE, &show_bgp_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_list_cmd); install_element (ENABLE_NODE, &show_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_filter_list_cmd); install_element (ENABLE_NODE, &show_bgp_route_map_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_route_map_cmd); install_element (ENABLE_NODE, &show_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_all_cmd); install_element (ENABLE_NODE, &show_bgp_community_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_cmd); install_element (ENABLE_NODE, &show_bgp_community2_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_cmd); install_element (ENABLE_NODE, &show_bgp_community3_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_cmd); install_element (ENABLE_NODE, &show_bgp_community4_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_cmd); install_element (ENABLE_NODE, &show_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community2_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community3_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community4_exact_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_cmd); install_element (ENABLE_NODE, &show_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_community_list_exact_cmd); install_element (ENABLE_NODE, &show_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_longer_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd); install_element (ENABLE_NODE, &show_bgp_view_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_routes_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_flap_cmd); install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd); install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd); install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd); /* Statistics */ install_element (ENABLE_NODE, &show_bgp_statistics_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_vpnv4_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_cmd); install_element (ENABLE_NODE, &show_bgp_statistics_view_vpnv4_cmd); /* old command */ install_element (VIEW_NODE, &show_ipv6_bgp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_route_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_regexp_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_filter_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_all_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community2_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community3_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community4_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ipv6_bgp_prefix_longer_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_route_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_regexp_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_filter_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_all_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community2_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community3_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community4_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_community_list_exact_cmd); install_element (VIEW_NODE, &show_ipv6_mbgp_prefix_longer_cmd); /* old command */ install_element (ENABLE_NODE, &show_ipv6_bgp_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_route_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_regexp_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_all_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_bgp_prefix_longer_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_route_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_regexp_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_filter_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_all_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community2_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community3_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community4_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_community_list_exact_cmd); install_element (ENABLE_NODE, &show_ipv6_mbgp_prefix_longer_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_advertised_route_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_advertised_route_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_received_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_received_routes_cmd); /* old command */ install_element (VIEW_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &ipv6_bgp_neighbor_routes_cmd); install_element (VIEW_NODE, &ipv6_mbgp_neighbor_routes_cmd); install_element (ENABLE_NODE, &ipv6_mbgp_neighbor_routes_cmd); #endif /* HAVE_IPV6 */ install_element (BGP_NODE, &bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance_cmd); install_element (BGP_NODE, &no_bgp_distance2_cmd); install_element (BGP_NODE, &bgp_distance_source_cmd); install_element (BGP_NODE, &no_bgp_distance_source_cmd); install_element (BGP_NODE, &bgp_distance_source_access_list_cmd); install_element (BGP_NODE, &no_bgp_distance_source_access_list_cmd); install_element (BGP_NODE, &bgp_damp_set_cmd); install_element (BGP_NODE, &bgp_damp_set2_cmd); install_element (BGP_NODE, &bgp_damp_set3_cmd); install_element (BGP_NODE, &bgp_damp_unset_cmd); install_element (BGP_NODE, &bgp_damp_unset2_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set2_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_set3_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset_cmd); install_element (BGP_IPV4_NODE, &bgp_damp_unset2_cmd); /* Deprecated AS-Pathlimit commands */ install_element (BGP_NODE, &bgp_network_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); #ifdef HAVE_IPV6 install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); #endif } void bgp_route_finish (void) { bgp_table_unlock (bgp_distance_table); bgp_distance_table = NULL; } quagga-0.99.24.1/bgpd/bgp_debug.c0000644000175000017500000006403412476520570013241 00000000000000/* BGP-4, BGP-4+ packet debug routine Copyright (C) 1996, 97, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "prefix.h" #include "linklist.h" #include "stream.h" #include "command.h" #include "str.h" #include "log.h" #include "sockunion.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_community.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_fsm; unsigned long conf_bgp_debug_events; unsigned long conf_bgp_debug_packet; unsigned long conf_bgp_debug_filter; unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_normal; unsigned long conf_bgp_debug_zebra; unsigned long term_bgp_debug_as4; unsigned long term_bgp_debug_fsm; unsigned long term_bgp_debug_events; unsigned long term_bgp_debug_packet; unsigned long term_bgp_debug_filter; unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_normal; unsigned long term_bgp_debug_zebra; /* messages for BGP-4 status */ const struct message bgp_status_msg[] = { { Idle, "Idle" }, { Connect, "Connect" }, { Active, "Active" }, { OpenSent, "OpenSent" }, { OpenConfirm, "OpenConfirm" }, { Established, "Established" }, { Clearing, "Clearing" }, { Deleted, "Deleted" }, }; const int bgp_status_msg_max = BGP_STATUS_MAX; /* BGP message type string. */ const char *bgp_type_str[] = { NULL, "OPEN", "UPDATE", "NOTIFICATION", "KEEPALIVE", "ROUTE-REFRESH", "CAPABILITY" }; /* message for BGP-4 Notify */ static const struct message bgp_notify_msg[] = { { BGP_NOTIFY_HEADER_ERR, "Message Header Error"}, { BGP_NOTIFY_OPEN_ERR, "OPEN Message Error"}, { BGP_NOTIFY_UPDATE_ERR, "UPDATE Message Error"}, { BGP_NOTIFY_HOLD_ERR, "Hold Timer Expired"}, { BGP_NOTIFY_FSM_ERR, "Finite State Machine Error"}, { BGP_NOTIFY_CEASE, "Cease"}, { BGP_NOTIFY_CAPABILITY_ERR, "CAPABILITY Message Error"}, }; static const int bgp_notify_msg_max = BGP_NOTIFY_MAX; static const struct message bgp_notify_head_msg[] = { { BGP_NOTIFY_HEADER_NOT_SYNC, "/Connection Not Synchronized"}, { BGP_NOTIFY_HEADER_BAD_MESLEN, "/Bad Message Length"}, { BGP_NOTIFY_HEADER_BAD_MESTYPE, "/Bad Message Type"} }; static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX; static const struct message bgp_notify_open_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" }, { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"}, { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, { BGP_NOTIFY_OPEN_UNSUP_PARAM, "/Unsupported Optional Parameter"}, { BGP_NOTIFY_OPEN_AUTH_FAILURE, "/Authentication Failure"}, { BGP_NOTIFY_OPEN_UNACEP_HOLDTIME, "/Unacceptable Hold Time"}, { BGP_NOTIFY_OPEN_UNSUP_CAPBL, "/Unsupported Capability"}, }; static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX; static const struct message bgp_notify_update_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"}, { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"}, { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, { BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, "/Attribute Flags Error"}, { BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, "/Attribute Length Error"}, { BGP_NOTIFY_UPDATE_INVAL_ORIGIN, "/Invalid ORIGIN Attribute"}, { BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP, "/AS Routing Loop"}, { BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, "/Invalid NEXT_HOP Attribute"}, { BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, "/Optional Attribute Error"}, { BGP_NOTIFY_UPDATE_INVAL_NETWORK, "/Invalid Network Field"}, { BGP_NOTIFY_UPDATE_MAL_AS_PATH, "/Malformed AS_PATH"}, }; static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX; static const struct message bgp_notify_cease_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"}, { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, { BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset"}, { BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected"}, { BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change"}, { BGP_NOTIFY_CEASE_COLLISION_RESOLUTION, "/Connection collision resolution"}, { BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"}, }; static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX; static const struct message bgp_notify_capability_msg[] = { { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" }, { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"}, { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, }; static const int bgp_notify_capability_msg_max = BGP_NOTIFY_CAPABILITY_MAX; /* Origin strings. */ const char *bgp_origin_str[] = {"i","e","?"}; const char *bgp_origin_long_str[] = {"IGP","EGP","incomplete"}; /* Dump attribute. */ int bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) { if (! attr) return 0; if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))) snprintf (buf, size, "nexthop %s", inet_ntoa (attr->nexthop)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) snprintf (buf + strlen (buf), size - strlen (buf), ", origin %s", bgp_origin_str[attr->origin]); #ifdef HAVE_IPV6 if (attr->extra) { char addrbuf[BUFSIZ]; /* Add MP case. */ if (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) snprintf (buf + strlen (buf), size - strlen (buf), ", mp_nexthop %s", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_global, addrbuf, BUFSIZ)); if (attr->extra->mp_nexthop_len == 32) snprintf (buf + strlen (buf), size - strlen (buf), "(%s)", inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, addrbuf, BUFSIZ)); } #endif /* HAVE_IPV6 */ if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) snprintf (buf + strlen (buf), size - strlen (buf), ", localpref %u", attr->local_pref); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))) snprintf (buf + strlen (buf), size - strlen (buf), ", metric %u", attr->med); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) snprintf (buf + strlen (buf), size - strlen (buf), ", community %s", community_str (attr->community)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))) snprintf (buf + strlen (buf), size - strlen (buf), ", atomic-aggregate"); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))) snprintf (buf + strlen (buf), size - strlen (buf), ", aggregated by %u %s", attr->extra->aggregator_as, inet_ntoa (attr->extra->aggregator_addr)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))) snprintf (buf + strlen (buf), size - strlen (buf), ", originator %s", inet_ntoa (attr->extra->originator_id)); if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST))) { int i; snprintf (buf + strlen (buf), size - strlen (buf), ", clusterlist"); for (i = 0; i < attr->extra->cluster->length / 4; i++) snprintf (buf + strlen (buf), size - strlen (buf), " %s", inet_ntoa (attr->extra->cluster->list[i])); } if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", aspath_print (attr->aspath)); if (strlen (buf) > 1) return 1; else return 0; } /* dump notify packet */ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, const char *direct) { const char *subcode_str; const char *code_str; subcode_str = ""; code_str = LOOKUP_DEF (bgp_notify_msg, bgp_notify->code, "Unrecognized Error Code"); switch (bgp_notify->code) { case BGP_NOTIFY_HEADER_ERR: subcode_str = LOOKUP_DEF (bgp_notify_head_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_OPEN_ERR: subcode_str = LOOKUP_DEF (bgp_notify_open_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_UPDATE_ERR: subcode_str = LOOKUP_DEF (bgp_notify_update_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_HOLD_ERR: break; case BGP_NOTIFY_FSM_ERR: break; case BGP_NOTIFY_CEASE: subcode_str = LOOKUP_DEF (bgp_notify_cease_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; case BGP_NOTIFY_CAPABILITY_ERR: subcode_str = LOOKUP_DEF (bgp_notify_capability_msg, bgp_notify->subcode, "Unrecognized Error Subcode"); break; } if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s", strcmp (direct, "received") == 0 ? "received from" : "sent to", peer->host, bgp_notify->code, bgp_notify->subcode, code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); else if (BGP_DEBUG (normal, NORMAL)) plog_debug (peer->log, "%s %s NOTIFICATION %d/%d (%s%s) %d bytes %s", peer ? peer->host : "", direct, bgp_notify->code, bgp_notify->subcode, code_str, subcode_str, bgp_notify->length, bgp_notify->data ? bgp_notify->data : ""); } /* Debug option setting interface. */ unsigned long bgp_debug_option = 0; int debug (unsigned int option) { return bgp_debug_option & option; } DEFUN (debug_bgp_as4, debug_bgp_as4_cmd, "debug bgp as4", DEBUG_STR BGP_STR "BGP AS4 actions\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (as4, AS4); else { TERM_DEBUG_ON (as4, AS4); vty_out (vty, "BGP as4 debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_as4, no_debug_bgp_as4_cmd, "no debug bgp as4", NO_STR DEBUG_STR BGP_STR "BGP AS4 actions\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (as4, AS4); else { TERM_DEBUG_OFF (as4, AS4); vty_out (vty, "BGP as4 debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_as4, undebug_bgp_as4_cmd, "undebug bgp as4", UNDEBUG_STR BGP_STR "BGP AS4 actions\n") DEFUN (debug_bgp_as4_segment, debug_bgp_as4_segment_cmd, "debug bgp as4 segment", DEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (as4, AS4_SEGMENT); else { TERM_DEBUG_ON (as4, AS4_SEGMENT); vty_out (vty, "BGP as4 segment debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_as4_segment, no_debug_bgp_as4_segment_cmd, "no debug bgp as4 segment", NO_STR DEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (as4, AS4_SEGMENT); else { TERM_DEBUG_OFF (as4, AS4_SEGMENT); vty_out (vty, "BGP as4 segment debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_as4_segment, undebug_bgp_as4_segment_cmd, "undebug bgp as4 segment", UNDEBUG_STR BGP_STR "BGP AS4 actions\n" "BGP AS4 aspath segment handling\n") DEFUN (debug_bgp_fsm, debug_bgp_fsm_cmd, "debug bgp fsm", DEBUG_STR BGP_STR "BGP Finite State Machine\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (fsm, FSM); else { TERM_DEBUG_ON (fsm, FSM); vty_out (vty, "BGP fsm debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_fsm, no_debug_bgp_fsm_cmd, "no debug bgp fsm", NO_STR DEBUG_STR BGP_STR "Finite State Machine\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (fsm, FSM); else { TERM_DEBUG_OFF (fsm, FSM); vty_out (vty, "BGP fsm debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_fsm, undebug_bgp_fsm_cmd, "undebug bgp fsm", UNDEBUG_STR BGP_STR "Finite State Machine\n") DEFUN (debug_bgp_events, debug_bgp_events_cmd, "debug bgp events", DEBUG_STR BGP_STR "BGP events\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (events, EVENTS); else { TERM_DEBUG_ON (events, EVENTS); vty_out (vty, "BGP events debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_events, no_debug_bgp_events_cmd, "no debug bgp events", NO_STR DEBUG_STR BGP_STR "BGP events\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (events, EVENTS); else { TERM_DEBUG_OFF (events, EVENTS); vty_out (vty, "BGP events debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_events, undebug_bgp_events_cmd, "undebug bgp events", UNDEBUG_STR BGP_STR "BGP events\n") DEFUN (debug_bgp_filter, debug_bgp_filter_cmd, "debug bgp filters", DEBUG_STR BGP_STR "BGP filters\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (filter, FILTER); else { TERM_DEBUG_ON (filter, FILTER); vty_out (vty, "BGP filters debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_filter, no_debug_bgp_filter_cmd, "no debug bgp filters", NO_STR DEBUG_STR BGP_STR "BGP filters\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (filter, FILTER); else { TERM_DEBUG_OFF (filter, FILTER); vty_out (vty, "BGP filters debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_filter, undebug_bgp_filter_cmd, "undebug bgp filters", UNDEBUG_STR BGP_STR "BGP filters\n") DEFUN (debug_bgp_keepalive, debug_bgp_keepalive_cmd, "debug bgp keepalives", DEBUG_STR BGP_STR "BGP keepalives\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (keepalive, KEEPALIVE); else { TERM_DEBUG_ON (keepalive, KEEPALIVE); vty_out (vty, "BGP keepalives debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_keepalive, no_debug_bgp_keepalive_cmd, "no debug bgp keepalives", NO_STR DEBUG_STR BGP_STR "BGP keepalives\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (keepalive, KEEPALIVE); else { TERM_DEBUG_OFF (keepalive, KEEPALIVE); vty_out (vty, "BGP keepalives debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_keepalive, undebug_bgp_keepalive_cmd, "undebug bgp keepalives", UNDEBUG_STR BGP_STR "BGP keepalives\n") DEFUN (debug_bgp_update, debug_bgp_update_cmd, "debug bgp updates", DEBUG_STR BGP_STR "BGP updates\n") { if (vty->node == CONFIG_NODE) { DEBUG_ON (update, UPDATE_IN); DEBUG_ON (update, UPDATE_OUT); } else { TERM_DEBUG_ON (update, UPDATE_IN); TERM_DEBUG_ON (update, UPDATE_OUT); vty_out (vty, "BGP updates debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (debug_bgp_update_direct, debug_bgp_update_direct_cmd, "debug bgp updates (in|out)", DEBUG_STR BGP_STR "BGP updates\n" "Inbound updates\n" "Outbound updates\n") { if (vty->node == CONFIG_NODE) { if (strncmp ("i", argv[0], 1) == 0) { DEBUG_OFF (update, UPDATE_OUT); DEBUG_ON (update, UPDATE_IN); } else { DEBUG_OFF (update, UPDATE_IN); DEBUG_ON (update, UPDATE_OUT); } } else { if (strncmp ("i", argv[0], 1) == 0) { TERM_DEBUG_OFF (update, UPDATE_OUT); TERM_DEBUG_ON (update, UPDATE_IN); vty_out (vty, "BGP updates debugging is on (inbound)%s", VTY_NEWLINE); } else { TERM_DEBUG_OFF (update, UPDATE_IN); TERM_DEBUG_ON (update, UPDATE_OUT); vty_out (vty, "BGP updates debugging is on (outbound)%s", VTY_NEWLINE); } } return CMD_SUCCESS; } DEFUN (no_debug_bgp_update, no_debug_bgp_update_cmd, "no debug bgp updates", NO_STR DEBUG_STR BGP_STR "BGP updates\n") { if (vty->node == CONFIG_NODE) { DEBUG_OFF (update, UPDATE_IN); DEBUG_OFF (update, UPDATE_OUT); } else { TERM_DEBUG_OFF (update, UPDATE_IN); TERM_DEBUG_OFF (update, UPDATE_OUT); vty_out (vty, "BGP updates debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_update, undebug_bgp_update_cmd, "undebug bgp updates", UNDEBUG_STR BGP_STR "BGP updates\n") DEFUN (debug_bgp_normal, debug_bgp_normal_cmd, "debug bgp", DEBUG_STR BGP_STR) { if (vty->node == CONFIG_NODE) DEBUG_ON (normal, NORMAL); else { TERM_DEBUG_ON (normal, NORMAL); vty_out (vty, "BGP debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_normal, no_debug_bgp_normal_cmd, "no debug bgp", NO_STR DEBUG_STR BGP_STR) { if (vty->node == CONFIG_NODE) DEBUG_OFF (normal, NORMAL); else { TERM_DEBUG_OFF (normal, NORMAL); vty_out (vty, "BGP debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_normal, undebug_bgp_normal_cmd, "undebug bgp", UNDEBUG_STR BGP_STR) DEFUN (debug_bgp_zebra, debug_bgp_zebra_cmd, "debug bgp zebra", DEBUG_STR BGP_STR "BGP Zebra messages\n") { if (vty->node == CONFIG_NODE) DEBUG_ON (zebra, ZEBRA); else { TERM_DEBUG_ON (zebra, ZEBRA); vty_out (vty, "BGP zebra debugging is on%s", VTY_NEWLINE); } return CMD_SUCCESS; } DEFUN (no_debug_bgp_zebra, no_debug_bgp_zebra_cmd, "no debug bgp zebra", NO_STR DEBUG_STR BGP_STR "BGP Zebra messages\n") { if (vty->node == CONFIG_NODE) DEBUG_OFF (zebra, ZEBRA); else { TERM_DEBUG_OFF (zebra, ZEBRA); vty_out (vty, "BGP zebra debugging is off%s", VTY_NEWLINE); } return CMD_SUCCESS; } ALIAS (no_debug_bgp_zebra, undebug_bgp_zebra_cmd, "undebug bgp zebra", UNDEBUG_STR BGP_STR "BGP Zebra messages\n") DEFUN (no_debug_bgp_all, no_debug_bgp_all_cmd, "no debug all bgp", NO_STR DEBUG_STR "Enable all debugging\n" BGP_STR) { TERM_DEBUG_OFF (normal, NORMAL); TERM_DEBUG_OFF (events, EVENTS); TERM_DEBUG_OFF (keepalive, KEEPALIVE); TERM_DEBUG_OFF (update, UPDATE_IN); TERM_DEBUG_OFF (update, UPDATE_OUT); TERM_DEBUG_OFF (as4, AS4); TERM_DEBUG_OFF (as4, AS4_SEGMENT); TERM_DEBUG_OFF (fsm, FSM); TERM_DEBUG_OFF (filter, FILTER); TERM_DEBUG_OFF (zebra, ZEBRA); vty_out (vty, "All possible debugging has been turned off%s", VTY_NEWLINE); return CMD_SUCCESS; } ALIAS (no_debug_bgp_all, undebug_bgp_all_cmd, "undebug all bgp", UNDEBUG_STR "Enable all debugging\n" BGP_STR) DEFUN (show_debugging_bgp, show_debugging_bgp_cmd, "show debugging bgp", SHOW_STR DEBUG_STR BGP_STR) { vty_out (vty, "BGP debugging status:%s", VTY_NEWLINE); if (BGP_DEBUG (normal, NORMAL)) vty_out (vty, " BGP debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (events, EVENTS)) vty_out (vty, " BGP events debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (keepalive, KEEPALIVE)) vty_out (vty, " BGP keepalives debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (update, UPDATE_IN) && BGP_DEBUG (update, UPDATE_OUT)) vty_out (vty, " BGP updates debugging is on%s", VTY_NEWLINE); else if (BGP_DEBUG (update, UPDATE_IN)) vty_out (vty, " BGP updates debugging is on (inbound)%s", VTY_NEWLINE); else if (BGP_DEBUG (update, UPDATE_OUT)) vty_out (vty, " BGP updates debugging is on (outbound)%s", VTY_NEWLINE); if (BGP_DEBUG (fsm, FSM)) vty_out (vty, " BGP fsm debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (filter, FILTER)) vty_out (vty, " BGP filter debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (zebra, ZEBRA)) vty_out (vty, " BGP zebra debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (as4, AS4)) vty_out (vty, " BGP as4 debugging is on%s", VTY_NEWLINE); if (BGP_DEBUG (as4, AS4_SEGMENT)) vty_out (vty, " BGP as4 aspath segment debugging is on%s", VTY_NEWLINE); vty_out (vty, "%s", VTY_NEWLINE); return CMD_SUCCESS; } static int bgp_config_write_debug (struct vty *vty) { int write = 0; if (CONF_BGP_DEBUG (normal, NORMAL)) { vty_out (vty, "debug bgp%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (as4, AS4)) { vty_out (vty, "debug bgp as4%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (as4, AS4_SEGMENT)) { vty_out (vty, "debug bgp as4 segment%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (events, EVENTS)) { vty_out (vty, "debug bgp events%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (keepalive, KEEPALIVE)) { vty_out (vty, "debug bgp keepalives%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (update, UPDATE_IN) && CONF_BGP_DEBUG (update, UPDATE_OUT)) { vty_out (vty, "debug bgp updates%s", VTY_NEWLINE); write++; } else if (CONF_BGP_DEBUG (update, UPDATE_IN)) { vty_out (vty, "debug bgp updates in%s", VTY_NEWLINE); write++; } else if (CONF_BGP_DEBUG (update, UPDATE_OUT)) { vty_out (vty, "debug bgp updates out%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (fsm, FSM)) { vty_out (vty, "debug bgp fsm%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (filter, FILTER)) { vty_out (vty, "debug bgp filters%s", VTY_NEWLINE); write++; } if (CONF_BGP_DEBUG (zebra, ZEBRA)) { vty_out (vty, "debug bgp zebra%s", VTY_NEWLINE); write++; } return write; } static struct cmd_node debug_node = { DEBUG_NODE, "", 1 }; void bgp_debug_init (void) { install_node (&debug_node, bgp_config_write_debug); install_element (ENABLE_NODE, &show_debugging_bgp_cmd); install_element (ENABLE_NODE, &debug_bgp_as4_cmd); install_element (CONFIG_NODE, &debug_bgp_as4_cmd); install_element (ENABLE_NODE, &debug_bgp_as4_segment_cmd); install_element (CONFIG_NODE, &debug_bgp_as4_segment_cmd); install_element (ENABLE_NODE, &debug_bgp_fsm_cmd); install_element (CONFIG_NODE, &debug_bgp_fsm_cmd); install_element (ENABLE_NODE, &debug_bgp_events_cmd); install_element (CONFIG_NODE, &debug_bgp_events_cmd); install_element (ENABLE_NODE, &debug_bgp_filter_cmd); install_element (CONFIG_NODE, &debug_bgp_filter_cmd); install_element (ENABLE_NODE, &debug_bgp_keepalive_cmd); install_element (CONFIG_NODE, &debug_bgp_keepalive_cmd); install_element (ENABLE_NODE, &debug_bgp_update_cmd); install_element (CONFIG_NODE, &debug_bgp_update_cmd); install_element (ENABLE_NODE, &debug_bgp_update_direct_cmd); install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd); install_element (ENABLE_NODE, &debug_bgp_normal_cmd); install_element (CONFIG_NODE, &debug_bgp_normal_cmd); install_element (ENABLE_NODE, &debug_bgp_zebra_cmd); install_element (CONFIG_NODE, &debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &no_debug_bgp_as4_cmd); install_element (ENABLE_NODE, &undebug_bgp_as4_cmd); install_element (CONFIG_NODE, &no_debug_bgp_as4_cmd); install_element (ENABLE_NODE, &no_debug_bgp_as4_segment_cmd); install_element (ENABLE_NODE, &undebug_bgp_as4_segment_cmd); install_element (CONFIG_NODE, &no_debug_bgp_as4_segment_cmd); install_element (ENABLE_NODE, &no_debug_bgp_fsm_cmd); install_element (ENABLE_NODE, &undebug_bgp_fsm_cmd); install_element (CONFIG_NODE, &no_debug_bgp_fsm_cmd); install_element (ENABLE_NODE, &no_debug_bgp_events_cmd); install_element (ENABLE_NODE, &undebug_bgp_events_cmd); install_element (CONFIG_NODE, &no_debug_bgp_events_cmd); install_element (ENABLE_NODE, &no_debug_bgp_filter_cmd); install_element (ENABLE_NODE, &undebug_bgp_filter_cmd); install_element (CONFIG_NODE, &no_debug_bgp_filter_cmd); install_element (ENABLE_NODE, &no_debug_bgp_keepalive_cmd); install_element (ENABLE_NODE, &undebug_bgp_keepalive_cmd); install_element (CONFIG_NODE, &no_debug_bgp_keepalive_cmd); install_element (ENABLE_NODE, &no_debug_bgp_update_cmd); install_element (ENABLE_NODE, &undebug_bgp_update_cmd); install_element (CONFIG_NODE, &no_debug_bgp_update_cmd); install_element (ENABLE_NODE, &no_debug_bgp_normal_cmd); install_element (ENABLE_NODE, &undebug_bgp_normal_cmd); install_element (CONFIG_NODE, &no_debug_bgp_normal_cmd); install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &undebug_bgp_zebra_cmd); install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd); install_element (ENABLE_NODE, &no_debug_bgp_all_cmd); install_element (ENABLE_NODE, &undebug_bgp_all_cmd); } quagga-0.99.24.1/bgpd/bgp_attr.c0000644000175000017500000023516112476520570013126 00000000000000/* BGP attributes management routines. Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "memory.h" #include "vector.h" #include "vty.h" #include "stream.h" #include "log.h" #include "hash.h" #include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" /* Attribute strings for logging. */ static const struct message attr_str [] = { { BGP_ATTR_ORIGIN, "ORIGIN" }, { BGP_ATTR_AS_PATH, "AS_PATH" }, { BGP_ATTR_NEXT_HOP, "NEXT_HOP" }, { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" }, { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" }, { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, { BGP_ATTR_AGGREGATOR, "AGGREGATOR" }, { BGP_ATTR_COMMUNITIES, "COMMUNITY" }, { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" }, { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" }, { BGP_ATTR_DPA, "DPA" }, { BGP_ATTR_ADVERTISER, "ADVERTISER"} , { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" }, { BGP_ATTR_AS4_PATH, "AS4_PATH" }, { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, }; static const int attr_str_max = array_size(attr_str); static const struct message attr_flag_str[] = { { BGP_ATTR_FLAG_OPTIONAL, "Optional" }, { BGP_ATTR_FLAG_TRANS, "Transitive" }, { BGP_ATTR_FLAG_PARTIAL, "Partial" }, /* bgp_attr_flags_diagnose() relies on this bit being last in this list */ { BGP_ATTR_FLAG_EXTLEN, "Extended Length" }, }; static const size_t attr_flag_str_max = array_size(attr_flag_str); static struct hash *cluster_hash; static void * cluster_hash_alloc (void *p) { struct cluster_list * val = (struct cluster_list *) p; struct cluster_list *cluster; cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); cluster->length = val->length; if (cluster->length) { cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length); memcpy (cluster->list, val->list, val->length); } else cluster->list = NULL; cluster->refcnt = 0; return cluster; } /* Cluster list related functions. */ static struct cluster_list * cluster_parse (struct in_addr * pnt, int length) { struct cluster_list tmp; struct cluster_list *cluster; tmp.length = length; tmp.list = pnt; cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc); cluster->refcnt++; return cluster; } int cluster_loop_check (struct cluster_list *cluster, struct in_addr originator) { int i; for (i = 0; i < cluster->length / 4; i++) if (cluster->list[i].s_addr == originator.s_addr) return 1; return 0; } static unsigned int cluster_hash_key_make (void *p) { const struct cluster_list *cluster = p; return jhash(cluster->list, cluster->length, 0); } static int cluster_hash_cmp (const void *p1, const void *p2) { const struct cluster_list * cluster1 = p1; const struct cluster_list * cluster2 = p2; return (cluster1->length == cluster2->length && memcmp (cluster1->list, cluster2->list, cluster1->length) == 0); } static void cluster_free (struct cluster_list *cluster) { if (cluster->list) XFREE (MTYPE_CLUSTER_VAL, cluster->list); XFREE (MTYPE_CLUSTER, cluster); } #if 0 static struct cluster_list * cluster_dup (struct cluster_list *cluster) { struct cluster_list *new; new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list)); new->length = cluster->length; if (cluster->length) { new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length); memcpy (new->list, cluster->list, cluster->length); } else new->list = NULL; return new; } #endif static struct cluster_list * cluster_intern (struct cluster_list *cluster) { struct cluster_list *find; find = hash_get (cluster_hash, cluster, cluster_hash_alloc); find->refcnt++; return find; } void cluster_unintern (struct cluster_list *cluster) { if (cluster->refcnt) cluster->refcnt--; if (cluster->refcnt == 0) { hash_release (cluster_hash, cluster); cluster_free (cluster); } } static void cluster_init (void) { cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); } static void cluster_finish (void) { hash_free (cluster_hash); cluster_hash = NULL; } /* Unknown transit attribute. */ static struct hash *transit_hash; static void transit_free (struct transit *transit) { if (transit->val) XFREE (MTYPE_TRANSIT_VAL, transit->val); XFREE (MTYPE_TRANSIT, transit); } static void * transit_hash_alloc (void *p) { /* Transit structure is already allocated. */ return p; } static struct transit * transit_intern (struct transit *transit) { struct transit *find; find = hash_get (transit_hash, transit, transit_hash_alloc); if (find != transit) transit_free (transit); find->refcnt++; return find; } void transit_unintern (struct transit *transit) { if (transit->refcnt) transit->refcnt--; if (transit->refcnt == 0) { hash_release (transit_hash, transit); transit_free (transit); } } static unsigned int transit_hash_key_make (void *p) { const struct transit * transit = p; return jhash(transit->val, transit->length, 0); } static int transit_hash_cmp (const void *p1, const void *p2) { const struct transit * transit1 = p1; const struct transit * transit2 = p2; return (transit1->length == transit2->length && memcmp (transit1->val, transit2->val, transit1->length) == 0); } static void transit_init (void) { transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); } static void transit_finish (void) { hash_free (transit_hash); transit_hash = NULL; } /* Attribute hash routines. */ static struct hash *attrhash; static struct attr_extra * bgp_attr_extra_new (void) { return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra)); } void bgp_attr_extra_free (struct attr *attr) { if (attr->extra) { XFREE (MTYPE_ATTR_EXTRA, attr->extra); attr->extra = NULL; } } struct attr_extra * bgp_attr_extra_get (struct attr *attr) { if (!attr->extra) attr->extra = bgp_attr_extra_new(); return attr->extra; } /* Shallow copy of an attribute * Though, not so shallow that it doesn't copy the contents * of the attr_extra pointed to by 'extra' */ void bgp_attr_dup (struct attr *new, struct attr *orig) { struct attr_extra *extra = new->extra; *new = *orig; /* if caller provided attr_extra space, use it in any case. * * This is neccesary even if orig->extra equals NULL, because otherwise * memory may be later allocated on the heap by bgp_attr_extra_get. * * That memory would eventually be leaked, because the caller must not * call bgp_attr_extra_free if he provided attr_extra on the stack. */ if (extra) { new->extra = extra; memset(new->extra, 0, sizeof(struct attr_extra)); if (orig->extra) *new->extra = *orig->extra; } else if (orig->extra) { new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; } } unsigned long int attr_count (void) { return attrhash->count; } unsigned long int attr_unknown_count (void) { return transit_hash->count; } unsigned int attrhash_key_make (void *p) { const struct attr *attr = (struct attr *) p; const struct attr_extra *extra = attr->extra; uint32_t key = 0; #define MIX(val) key = jhash_1word(val, key) MIX(attr->origin); MIX(attr->nexthop.s_addr); MIX(attr->med); MIX(attr->local_pref); key += attr->origin; key += attr->nexthop.s_addr; key += attr->med; key += attr->local_pref; if (extra) { MIX(extra->aggregator_as); MIX(extra->aggregator_addr.s_addr); MIX(extra->weight); MIX(extra->mp_nexthop_global_in.s_addr); MIX(extra->originator_id.s_addr); } if (attr->aspath) MIX(aspath_key_make (attr->aspath)); if (attr->community) MIX(community_hash_make (attr->community)); if (extra) { if (extra->ecommunity) MIX(ecommunity_hash_make (extra->ecommunity)); if (extra->cluster) MIX(cluster_hash_key_make (extra->cluster)); if (extra->transit) MIX(transit_hash_key_make (extra->transit)); #ifdef HAVE_IPV6 MIX(extra->mp_nexthop_len); key = jhash(extra->mp_nexthop_global.s6_addr, 16, key); key = jhash(extra->mp_nexthop_local.s6_addr, 16, key); #endif /* HAVE_IPV6 */ } return key; } int attrhash_cmp (const void *p1, const void *p2) { const struct attr * attr1 = p1; const struct attr * attr2 = p2; if (attr1->flag == attr2->flag && attr1->origin == attr2->origin && attr1->nexthop.s_addr == attr2->nexthop.s_addr && attr1->aspath == attr2->aspath && attr1->community == attr2->community && attr1->med == attr2->med && attr1->local_pref == attr2->local_pref) { const struct attr_extra *ae1 = attr1->extra; const struct attr_extra *ae2 = attr2->extra; if (ae1 && ae2 && ae1->aggregator_as == ae2->aggregator_as && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight #ifdef HAVE_IPV6 && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) #endif /* HAVE_IPV6 */ && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) return 1; else if (ae1 || ae2) return 0; /* neither attribute has extra attributes, so they're same */ return 1; } else return 0; } static void attrhash_init (void) { attrhash = hash_create (attrhash_key_make, attrhash_cmp); } static void attrhash_finish (void) { hash_free (attrhash); attrhash = NULL; } static void attr_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct attr *attr = backet->data; vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, inet_ntoa (attr->nexthop), VTY_NEWLINE); } void attr_show_all (struct vty *vty) { hash_iterate (attrhash, (void (*)(struct hash_backet *, void *)) attr_show_all_iterator, vty); } static void * bgp_attr_hash_alloc (void *p) { struct attr * val = (struct attr *) p; struct attr *attr; attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr)); *attr = *val; if (val->extra) { attr->extra = bgp_attr_extra_new (); *attr->extra = *val->extra; } attr->refcnt = 0; return attr; } /* Internet argument attribute. */ struct attr * bgp_attr_intern (struct attr *attr) { struct attr *find; /* Intern referenced strucutre. */ if (attr->aspath) { if (! attr->aspath->refcnt) attr->aspath = aspath_intern (attr->aspath); else attr->aspath->refcnt++; } if (attr->community) { if (! attr->community->refcnt) attr->community = community_intern (attr->community); else attr->community->refcnt++; } if (attr->extra) { struct attr_extra *attre = attr->extra; if (attre->ecommunity) { if (! attre->ecommunity->refcnt) attre->ecommunity = ecommunity_intern (attre->ecommunity); else attre->ecommunity->refcnt++; } if (attre->cluster) { if (! attre->cluster->refcnt) attre->cluster = cluster_intern (attre->cluster); else attre->cluster->refcnt++; } if (attre->transit) { if (! attre->transit->refcnt) attre->transit = transit_intern (attre->transit); else attre->transit->refcnt++; } } find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc); find->refcnt++; return find; } /* Make network statement's attribute. */ struct attr * bgp_attr_default_set (struct attr *attr, u_char origin) { memset (attr, 0, sizeof (struct attr)); bgp_attr_extra_get (attr); attr->origin = origin; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); attr->aspath = aspath_empty (); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); #ifdef HAVE_IPV6 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN; #endif return attr; } /* Make network statement's attribute. */ struct attr * bgp_attr_default_intern (u_char origin) { struct attr attr; struct attr *new; bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); bgp_attr_extra_free (&attr); aspath_unintern (&new->aspath); return new; } struct attr * bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin, struct aspath *aspath, struct community *community, int as_set) { struct attr attr; struct attr *new; struct attr_extra attre; memset (&attr, 0, sizeof (struct attr)); memset (&attre, 0, sizeof (struct attr_extra)); attr.extra = &attre; /* Origin attribute. */ attr.origin = origin; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); /* AS path attribute. */ if (aspath) attr.aspath = aspath_intern (aspath); else attr.aspath = aspath_empty (); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); /* Next hop attribute. */ attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); if (community) { attr.community = community; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); } attre.weight = BGP_ATTR_DEFAULT_WEIGHT; #ifdef HAVE_IPV6 attre.mp_nexthop_len = IPV6_MAX_BYTELEN; #endif if (! as_set) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) attre.aggregator_as = bgp->confed_id; else attre.aggregator_as = bgp->as; attre.aggregator_addr = bgp->router_id; new = bgp_attr_intern (&attr); aspath_unintern (&new->aspath); return new; } /* Unintern just the sub-components of the attr, but not the attr */ void bgp_attr_unintern_sub (struct attr *attr) { /* aspath refcount shoud be decrement. */ if (attr->aspath) aspath_unintern (&attr->aspath); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)); if (attr->community) community_unintern (&attr->community); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)); if (attr->extra) { if (attr->extra->ecommunity) ecommunity_unintern (&attr->extra->ecommunity); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)); if (attr->extra->cluster) cluster_unintern (attr->extra->cluster); UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST)); if (attr->extra->transit) transit_unintern (attr->extra->transit); } } /* Free bgp attribute and aspath. */ void bgp_attr_unintern (struct attr **pattr) { struct attr *attr = *pattr; struct attr *ret; struct attr tmp; struct attr_extra tmp_extra; /* Decrement attribute reference. */ attr->refcnt--; tmp = *attr; if (attr->extra) { tmp.extra = &tmp_extra; memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra)); } /* If reference becomes zero then free attribute object. */ if (attr->refcnt == 0) { ret = hash_release (attrhash, attr); assert (ret != NULL); bgp_attr_extra_free (attr); XFREE (MTYPE_ATTR, attr); *pattr = NULL; } bgp_attr_unintern_sub (&tmp); } void bgp_attr_flush (struct attr *attr) { if (attr->aspath && ! attr->aspath->refcnt) aspath_free (attr->aspath); if (attr->community && ! attr->community->refcnt) community_free (attr->community); if (attr->extra) { struct attr_extra *attre = attr->extra; if (attre->ecommunity && ! attre->ecommunity->refcnt) ecommunity_free (&attre->ecommunity); if (attre->cluster && ! attre->cluster->refcnt) cluster_free (attre->cluster); if (attre->transit && ! attre->transit->refcnt) transit_free (attre->transit); } } /* Implement draft-scudder-idr-optional-transitive behaviour and * avoid resetting sessions for malformed attributes which are * are partial/optional and hence where the error likely was not * introduced by the sending neighbour. */ static bgp_attr_parse_ret_t bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, bgp_size_t length) { struct peer *const peer = args->peer; const u_int8_t flags = args->flags; /* startp and length must be special-cased, as whether or not to * send the attribute data with the NOTIFY depends on the error, * the caller therefore signals this with the seperate length argument */ u_char *notify_datap = (length > 0 ? args->startp : NULL); /* Only relax error handling for eBGP peers */ if (peer->sort != BGP_PEER_EBGP) { bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } /* Adjust the stream getp to the end of the attribute, in case we can * still proceed but the caller hasn't read all the attribute. */ stream_set_getp (BGP_INPUT (peer), (args->startp - STREAM_DATA (BGP_INPUT (peer))) + args->total); switch (args->type) { /* where an attribute is relatively inconsequential, e.g. it does not * affect route selection, and can be safely ignored, then any such * attributes which are malformed should just be ignored and the route * processed as normal. */ case BGP_ATTR_AS4_AGGREGATOR: case BGP_ATTR_AGGREGATOR: case BGP_ATTR_ATOMIC_AGGREGATE: return BGP_ATTR_PARSE_PROCEED; /* Core attributes, particularly ones which may influence route * selection, should always cause session resets */ case BGP_ATTR_ORIGIN: case BGP_ATTR_AS_PATH: case BGP_ATTR_NEXT_HOP: case BGP_ATTR_MULTI_EXIT_DISC: case BGP_ATTR_LOCAL_PREF: case BGP_ATTR_COMMUNITIES: case BGP_ATTR_ORIGINATOR_ID: case BGP_ATTR_CLUSTER_LIST: case BGP_ATTR_MP_REACH_NLRI: case BGP_ATTR_MP_UNREACH_NLRI: case BGP_ATTR_EXT_COMMUNITIES: bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; } /* Partial optional attributes that are malformed should not cause * the whole session to be reset. Instead treat it as a withdrawal * of the routes, if possible. */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS) && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) return BGP_ATTR_PARSE_WITHDRAW; /* default to reset */ return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Find out what is wrong with the path attribute flag bits and log the error. "Flag bits" here stand for Optional, Transitive and Partial, but not for Extended Length. Checking O/T/P bits at once implies, that the attribute being diagnosed is defined by RFC as either a "well-known" or an "optional, non-transitive" attribute. */ static void bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args, u_int8_t desired_flags /* how RFC says it must be */ ) { u_char seen = 0, i; u_char real_flags = args->flags; const u_int8_t attr_code = args->type; desired_flags &= ~BGP_ATTR_FLAG_EXTLEN; real_flags &= ~BGP_ATTR_FLAG_EXTLEN; for (i = 0; i <= 2; i++) /* O,T,P, but not E */ if ( CHECK_FLAG (desired_flags, attr_flag_str[i].key) != CHECK_FLAG (real_flags, attr_flag_str[i].key) ) { zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"", LOOKUP (attr_str, attr_code), CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not", attr_flag_str[i].str); seen = 1; } if (!seen) { zlog (args->peer->log, LOG_DEBUG, "Strange, %s called for attr %s, but no problem found with flags" " (real flags 0x%x, desired 0x%x)", __func__, LOOKUP (attr_str, attr_code), real_flags, desired_flags); } } /* Required flags for attributes. EXTLEN will be masked off when testing, * as will PARTIAL for optional+transitive attributes. */ const u_int8_t attr_flags_values [] = { [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL, [BGP_ATTR_EXT_COMMUNITIES] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, }; static const size_t attr_flags_values_max = sizeof (attr_flags_values) / sizeof (attr_flags_values[0]); static int bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) { u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; const u_int8_t flags = args->flags; const u_int8_t attr_code = args->type; struct peer *const peer = args->peer; /* there may be attributes we don't know about */ if (attr_code > attr_flags_values_max) return 0; if (attr_flags_values[attr_code] == 0) return 0; /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to * 1." */ if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags) && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags)) { zlog (peer->log, LOG_ERR, "%s well-known attributes must have transitive flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } /* "For well-known attributes and for optional non-transitive attributes, * the Partial bit MUST be set to 0." */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) { if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)) { zlog (peer->log, LOG_ERR, "%s well-known attribute " "must NOT have the partial flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) { zlog (peer->log, LOG_ERR, "%s optional + transitive attribute " "must NOT have the partial flag set (%x)", LOOKUP (attr_str, attr_code), flags); return 1; } } /* Optional transitive attributes may go through speakers that don't * reocgnise them and set the Partial bit. */ if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)) SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL); if ((flags & ~mask) == attr_flags_values[attr_code]) return 0; bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]); return 1; } /* Get origin attribute of the update message. */ static bgp_attr_parse_ret_t bgp_attr_origin (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* If any recognized attribute has Attribute Length that conflicts with the expected length (based on the attribute type code), then the Error Subcode is set to Attribute Length Error. The Data field contains the erroneous attribute (type, length and value). */ if (length != 1) { zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* Fetch origin attribute. */ attr->origin = stream_getc (BGP_INPUT (peer)); /* If the ORIGIN attribute has an undefined value, then the Error Subcode is set to Invalid Origin Attribute. The Data field contains the unrecognized attribute (type, length and value). */ if ((attr->origin != BGP_ORIGIN_IGP) && (attr->origin != BGP_ORIGIN_EGP) && (attr->origin != BGP_ORIGIN_INCOMPLETE)) { zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d", attr->origin); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN, args->total); } /* Set oring attribute flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN); return 0; } /* Parse AS path information. This function is wrapper of aspath_parse. */ static int bgp_attr_aspath (struct bgp_attr_parser_args *args) { struct attr *const attr = args->attr; struct peer *const peer = args->peer; const bgp_size_t length = args->length; /* * peer with AS4 => will get 4Byte ASnums * otherwise, will get 16 Bit */ attr->aspath = aspath_parse (peer->ibuf, length, CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); /* In case of IBGP, length will be zero. */ if (! attr->aspath) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s, length is %d", peer->host, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); return BGP_ATTR_PARSE_PROCEED; } static bgp_attr_parse_ret_t bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr) { /* These checks were part of bgp_attr_aspath, but with * as4 we should to check aspath things when * aspath synthesizing with as4_path has already taken place. * Otherwise we check ASPATH and use the synthesized thing, and that is * not right. * So do the checks later, i.e. here */ struct bgp *bgp = peer->bgp; struct aspath *aspath; /* Confederation sanity check. */ if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) || (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath))) { zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); return BGP_ATTR_PARSE_ERROR; } /* First AS check for EBGP. */ if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) { if (peer->sort == BGP_PEER_EBGP && ! aspath_firstas_check (attr->aspath, peer->as)) { zlog (peer->log, LOG_ERR, "%s incorrect first AS (must be %u)", peer->host, peer->as); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_AS_PATH); return BGP_ATTR_PARSE_ERROR; } } /* local-as prepend */ if (peer->change_local_as && ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) { aspath = aspath_dup (attr->aspath); aspath = aspath_add_seq (aspath, peer->change_local_as); aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (aspath); } return BGP_ATTR_PARSE_PROCEED; } /* Parse AS4 path information. This function is another wrapper of aspath_parse. */ static int bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; *as4_path = aspath_parse (peer->ibuf, length, 1); /* In case of IBGP, length will be zero. */ if (!*as4_path) { zlog (peer->log, LOG_ERR, "Malformed AS4 path from %s, length is %d", peer->host, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0); } /* Set aspath attribute flag. */ if (as4_path) attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); return BGP_ATTR_PARSE_PROCEED; } /* Nexthop attribute. */ static bgp_attr_parse_ret_t bgp_attr_nexthop (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; in_addr_t nexthop_h, nexthop_n; /* Check nexthop attribute length. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP attribute must result in a NOTIFICATION message (this is implemented below). At the same time, semantically incorrect NEXT_HOP is more likely to be just logged locally (this is implemented somewhere else). The UPDATE message gets ignored in any of these cases. */ nexthop_n = stream_get_ipv4 (peer->ibuf); nexthop_h = ntohl (nexthop_n); if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h)) { char buf[INET_ADDRSTRLEN]; inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN); zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total); } attr->nexthop.s_addr = nexthop_n; attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP); return BGP_ATTR_PARSE_PROCEED; } /* MED atrribute. */ static bgp_attr_parse_ret_t bgp_attr_med (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "MED attribute length isn't four [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } attr->med = stream_getl (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); return BGP_ATTR_PARSE_PROCEED; } /* Local preference attribute. */ static bgp_attr_parse_ret_t bgp_attr_local_pref (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ if (peer->sort == BGP_PEER_EBGP) { stream_forward_getp (peer->ibuf, length); return BGP_ATTR_PARSE_PROCEED; } attr->local_pref = stream_getl (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); return BGP_ATTR_PARSE_PROCEED; } /* Atomic aggregate. */ static int bgp_attr_atomic (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 0) { zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); return BGP_ATTR_PARSE_PROCEED; } /* Aggregator attribute */ static int bgp_attr_aggregator (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; int wantedlen = 6; struct attr_extra *attre = bgp_attr_extra_get (attr); /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) wantedlen = 8; if (length != wantedlen) { zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) attre->aggregator_as = stream_getl (peer->ibuf); else attre->aggregator_as = stream_getw (peer->ibuf); attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf); /* Set atomic aggregate flag. */ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); return BGP_ATTR_PARSE_PROCEED; } /* New Aggregator attribute */ static bgp_attr_parse_ret_t bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args, as_t *as4_aggregator_as, struct in_addr *as4_aggregator_addr) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length != 8) { zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, 0); } *as4_aggregator_as = stream_getl (peer->ibuf); as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); return BGP_ATTR_PARSE_PROCEED; } /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. */ static bgp_attr_parse_ret_t bgp_attr_munge_as4_attrs (struct peer *const peer, struct attr *const attr, struct aspath *as4_path, as_t as4_aggregator, struct in_addr *as4_aggregator_addr) { int ignore_as4_path = 0; struct aspath *newpath; struct attr_extra *attre = attr->extra; if (!attr->aspath) { /* NULL aspath shouldn't be possible as bgp_attr_parse should have * checked that all well-known, mandatory attributes were present. * * Can only be a problem with peer itself - hard error */ return BGP_ATTR_PARSE_ERROR; } if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) { /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR * if given. * It is worth a warning though, because the peer really * should not send them */ if (BGP_DEBUG(as4, AS4)) { if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH))) zlog_debug ("[AS4] %s %s AS4_PATH", peer->host, "AS4 capable peer, yet it sent"); if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) zlog_debug ("[AS4] %s %s AS4_AGGREGATOR", peer->host, "AS4 capable peer, yet it sent"); } return BGP_ATTR_PARSE_PROCEED; } /* We have a asn16 peer. First, look for AS4_AGGREGATOR * because that may override AS4_PATH */ if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) ) { if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) { assert (attre); /* received both. * if the as_number in aggregator is not AS_TRANS, * then AS4_AGGREGATOR and AS4_PATH shall be ignored * and the Aggregator shall be taken as * info on the aggregating node, and the AS_PATH * shall be taken as the AS_PATH * otherwise * the Aggregator shall be ignored and the * AS4_AGGREGATOR shall be taken as the * Aggregating node and the AS_PATH is to be * constructed "as in all other cases" */ if (attre->aggregator_as != BGP_AS_TRANS) { /* ignore */ if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] %s BGP not AS4 capable peer" " send AGGREGATOR != AS_TRANS and" " AS4_AGGREGATOR, so ignore" " AS4_AGGREGATOR and AS4_PATH", peer->host); ignore_as4_path = 1; } else { /* "New_aggregator shall be taken as aggregator" */ attre->aggregator_as = as4_aggregator; attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr; } } else { /* We received a AS4_AGGREGATOR but no AGGREGATOR. * That is bogus - but reading the conditions * we have to handle AS4_AGGREGATOR as if it were * AGGREGATOR in that case */ if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] %s BGP not AS4 capable peer send" " AS4_AGGREGATOR but no AGGREGATOR, will take" " it as if AGGREGATOR with AS_TRANS had been there", peer->host); (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator; /* sweep it under the carpet and simulate a "good" AGGREGATOR */ attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)); } } /* need to reconcile NEW_AS_PATH and AS_PATH */ if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH)))) { newpath = aspath_reconcile_as4 (attr->aspath, as4_path); aspath_unintern (&attr->aspath); attr->aspath = aspath_intern (newpath); } return BGP_ATTR_PARSE_PROCEED; } /* Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_community (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length == 0) { attr->community = NULL; return BGP_ATTR_PARSE_PROCEED; } attr->community = community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length); /* XXX: fix community_parse to use stream API and remove this */ stream_forward_getp (peer->ibuf, length); if (!attr->community) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; } /* Originator ID attribute. */ static bgp_attr_parse_ret_t bgp_attr_originator_id (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Length check. */ if (length != 4) { zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } (bgp_attr_extra_get (attr))->originator_id.s_addr = stream_get_ipv4 (peer->ibuf); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); return BGP_ATTR_PARSE_PROCEED; } /* Cluster list attribute. */ static bgp_attr_parse_ret_t bgp_attr_cluster_list (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; /* Check length. */ if (length % 4) { zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, args->total); } (bgp_attr_extra_get (attr))->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); /* XXX: Fix cluster_parse to use stream API and then remove this */ stream_forward_getp (peer->ibuf, length); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); return BGP_ATTR_PARSE_PROCEED; } /* Multiprotocol reachability information parse. */ int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update) { afi_t afi; safi_t safi; bgp_size_t nlri_len; size_t start; int ret; struct stream *s; struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; struct attr_extra *attre = bgp_attr_extra_get(attr); /* Set end of packet. */ s = BGP_INPUT(peer); start = stream_get_getp(s); /* safe to read statically sized header? */ #define BGP_MP_REACH_MIN_SIZE 5 #define LEN_LEFT (length - (stream_get_getp(s) - start)) if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) { zlog_info ("%s: %s sent invalid length, %lu", __func__, peer->host, (unsigned long)length); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Load AFI, SAFI. */ afi = stream_getw (s); safi = stream_getc (s); /* Get nexthop length. */ attre->mp_nexthop_len = stream_getc (s); if (LEN_LEFT < attre->mp_nexthop_len) { zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } /* Nexthop length check. */ switch (attre->mp_nexthop_len) { case 4: stream_get (&attre->mp_nexthop_global_in, s, 4); /* Probably needed for RFC 2283 */ if (attr->nexthop.s_addr == 0) memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4); break; case 12: stream_getl (s); /* RD high */ stream_getl (s); /* RD low */ stream_get (&attre->mp_nexthop_global_in, s, 4); break; #ifdef HAVE_IPV6 case 16: stream_get (&attre->mp_nexthop_global, s, 16); break; case 32: stream_get (&attre->mp_nexthop_global, s, 16); stream_get (&attre->mp_nexthop_local, s, 16); if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local)) { char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; if (BGP_DEBUG (update, UPDATE_IN)) zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host, inet_ntop (AF_INET6, &attre->mp_nexthop_global, buf1, INET6_ADDRSTRLEN), inet_ntop (AF_INET6, &attre->mp_nexthop_local, buf2, INET6_ADDRSTRLEN)); attre->mp_nexthop_len = 16; } break; #endif /* HAVE_IPV6 */ default: zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", __func__, peer->host, attre->mp_nexthop_len); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (!LEN_LEFT) { zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)", __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } { u_char val; if ((val = stream_getc (s))) zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field", peer->host, val); } /* must have nrli_len, what is left of the attribute */ nlri_len = LEN_LEFT; if ((!nlri_len) || (nlri_len > STREAM_READABLE(s))) { zlog_info ("%s: (%s) Failed to read NLRI", __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } if (safi != SAFI_MPLS_LABELED_VPN) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); if (ret < 0) { zlog_info ("%s: (%s) NLRI doesn't pass sanity check", __func__, peer->host); return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } } mp_update->afi = afi; mp_update->safi = safi; mp_update->nlri = stream_pnt (s); mp_update->length = nlri_len; stream_forward_getp (s, nlri_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI); return BGP_ATTR_PARSE_PROCEED; #undef LEN_LEFT } /* Multiprotocol unreachable parse */ int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_withdraw) { struct stream *s; afi_t afi; safi_t safi; u_int16_t withdraw_len; int ret; struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; s = peer->ibuf; #define BGP_MP_UNREACH_MIN_SIZE 3 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE)) return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; afi = stream_getw (s); safi = stream_getc (s); withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE; if (safi != SAFI_MPLS_LABELED_VPN) { ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len); if (ret < 0) return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; } mp_withdraw->afi = afi; mp_withdraw->safi = safi; mp_withdraw->nlri = stream_pnt (s); mp_withdraw->length = withdraw_len; stream_forward_getp (s, withdraw_len); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI); return BGP_ATTR_PARSE_PROCEED; } /* Extended Community attribute. */ static bgp_attr_parse_ret_t bgp_attr_ext_communities (struct bgp_attr_parser_args *args) { struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; if (length == 0) { if (attr->extra) attr->extra->ecommunity = NULL; /* Empty extcomm doesn't seem to be invalid per se */ return BGP_ATTR_PARSE_PROCEED; } (bgp_attr_extra_get (attr))->ecommunity = ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length); /* XXX: fix ecommunity_parse to use stream API */ stream_forward_getp (peer->ibuf, length); if (!attr->extra->ecommunity) return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); return BGP_ATTR_PARSE_PROCEED; } /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) { bgp_size_t total = args->total; struct transit *transit; struct attr_extra *attre; struct peer *const peer = args->peer; struct attr *const attr = args->attr; u_char *const startp = args->startp; const u_char type = args->type; const u_char flag = args->flags; const bgp_size_t length = args->length; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s Unknown attribute is received (type %d, length %d)", peer->host, type, length); if (BGP_DEBUG (events, EVENTS)) zlog (peer->log, LOG_DEBUG, "Unknown attribute type %d length %d is received", type, length); /* Forward read pointer of input stream. */ stream_forward_getp (peer->ibuf, length); /* If any of the mandatory well-known attributes are not recognized, then the Error Subcode is set to Unrecognized Well-known Attribute. The Data field contains the unrecognized attribute (type, length and value). */ if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) { return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_UNREC_ATTR, args->total); } /* Unrecognized non-transitive optional attributes must be quietly ignored and not passed along to other BGP peers. */ if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) return BGP_ATTR_PARSE_PROCEED; /* If a path with recognized transitive optional attribute is accepted and passed along to other BGP peers and the Partial bit in the Attribute Flags octet is set to 1 by some previous AS, it is not set back to 0 by the current AS. */ SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL); /* Store transitive attribute to the end of attr->transit. */ if (! ((attre = bgp_attr_extra_get(attr))->transit) ) attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit)); transit = attre->transit; if (transit->val) transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, transit->length + total); else transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total); memcpy (transit->val + transit->length, startp, total); transit->length += total; return BGP_ATTR_PARSE_PROCEED; } /* Well-known attribute check. */ static int bgp_attr_check (struct peer *peer, struct attr *attr) { u_char type = 0; /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an * empty UPDATE. */ if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag) return BGP_ATTR_PARSE_PROCEED; /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required to carry any other path attributes.", though if MP_REACH_NLRI or NLRI are present, it should. Check for any other attribute being present instead. */ if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI)) return BGP_ATTR_PARSE_PROCEED; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) type = BGP_ATTR_ORIGIN; if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))) type = BGP_ATTR_AS_PATH; /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and * NLRI is empty. We can't easily check NLRI empty here though. */ if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)) && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI))) type = BGP_ATTR_NEXT_HOP; if (peer->sort == BGP_PEER_IBGP && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))) type = BGP_ATTR_LOCAL_PREF; if (type) { zlog (peer->log, LOG_WARNING, "%s Missing well-known attribute %d / %s", peer->host, type, LOOKUP (attr_str, type)); bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MISS_ATTR, &type, 1); return BGP_ATTR_PARSE_ERROR; } return BGP_ATTR_PARSE_PROCEED; } /* Read attribute of update packet. This function is called from bgp_update_receive() in bgp_packet.c. */ bgp_attr_parse_ret_t bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw) { int ret; u_char flag = 0; u_char type = 0; bgp_size_t length; u_char *startp, *endp; u_char *attr_endp; u_char seen[BGP_ATTR_BITMAP_SIZE]; /* we need the as4_path only until we have synthesized the as_path with it */ /* same goes for as4_aggregator */ struct aspath *as4_path = NULL; as_t as4_aggregator = 0; struct in_addr as4_aggregator_addr = { 0 }; /* Initialize bitmap. */ memset (seen, 0, BGP_ATTR_BITMAP_SIZE); /* End pointer of BGP attribute. */ endp = BGP_INPUT_PNT (peer) + size; /* Get attributes to the end of attribute length. */ while (BGP_INPUT_PNT (peer) < endp) { /* Check remaining length check.*/ if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN) { /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, "%s: error BGP attribute length %lu is smaller than min len", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } /* Fetch attribute flag and type. */ startp = BGP_INPUT_PNT (peer); /* "The lower-order four bits of the Attribute Flags octet are unused. They MUST be zero when sent and MUST be ignored when received." */ flag = 0xF0 & stream_getc (BGP_INPUT (peer)); type = stream_getc (BGP_INPUT (peer)); /* Check whether Extended-Length applies and is in bounds */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) { zlog (peer->log, LOG_WARNING, "%s: Extended length set, but just %lu bytes of attr header", peer->host, (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer)))); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } /* Check extended attribue length bit. */ if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)) length = stream_getw (BGP_INPUT (peer)); else length = stream_getc (BGP_INPUT (peer)); /* If any attribute appears more than once in the UPDATE message, then the Error Subcode is set to Malformed Attribute List. */ if (CHECK_BITMAP (seen, type)) { zlog (peer->log, LOG_WARNING, "%s: error BGP attribute type %d appears twice in a message", peer->host, type); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); return BGP_ATTR_PARSE_ERROR; } /* Set type to bitmap to check duplicate attribute. `type' is unsigned char so it never overflow bitmap range. */ SET_BITMAP (seen, type); /* Overflow check. */ attr_endp = BGP_INPUT_PNT (peer) + length; if (attr_endp > endp) { zlog (peer->log, LOG_WARNING, "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); return BGP_ATTR_PARSE_ERROR; } struct bgp_attr_parser_args attr_args = { .peer = peer, .length = length, .attr = attr, .type = type, .flags = flag, .startp = startp, .total = attr_endp - startp, }; /* If any recognized attribute has Attribute Flags that conflict with the Attribute Type Code, then the Error Subcode is set to Attribute Flags Error. The Data field contains the erroneous attribute (type, length and value). */ if (bgp_attr_flag_invalid (&attr_args)) { bgp_attr_parse_ret_t ret; ret = bgp_attr_malformed (&attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, attr_args.total); if (ret == BGP_ATTR_PARSE_PROCEED) continue; return ret; } /* OK check attribute and store it's value. */ switch (type) { case BGP_ATTR_ORIGIN: ret = bgp_attr_origin (&attr_args); break; case BGP_ATTR_AS_PATH: ret = bgp_attr_aspath (&attr_args); break; case BGP_ATTR_AS4_PATH: ret = bgp_attr_as4_path (&attr_args, &as4_path); break; case BGP_ATTR_NEXT_HOP: ret = bgp_attr_nexthop (&attr_args); break; case BGP_ATTR_MULTI_EXIT_DISC: ret = bgp_attr_med (&attr_args); break; case BGP_ATTR_LOCAL_PREF: ret = bgp_attr_local_pref (&attr_args); break; case BGP_ATTR_ATOMIC_AGGREGATE: ret = bgp_attr_atomic (&attr_args); break; case BGP_ATTR_AGGREGATOR: ret = bgp_attr_aggregator (&attr_args); break; case BGP_ATTR_AS4_AGGREGATOR: ret = bgp_attr_as4_aggregator (&attr_args, &as4_aggregator, &as4_aggregator_addr); break; case BGP_ATTR_COMMUNITIES: ret = bgp_attr_community (&attr_args); break; case BGP_ATTR_ORIGINATOR_ID: ret = bgp_attr_originator_id (&attr_args); break; case BGP_ATTR_CLUSTER_LIST: ret = bgp_attr_cluster_list (&attr_args); break; case BGP_ATTR_MP_REACH_NLRI: ret = bgp_mp_reach_parse (&attr_args, mp_update); break; case BGP_ATTR_MP_UNREACH_NLRI: ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw); break; case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (&attr_args); break; default: ret = bgp_attr_unknown (&attr_args); break; } if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) { bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); ret = BGP_ATTR_PARSE_ERROR; } /* If hard error occured immediately return to the caller. */ if (ret == BGP_ATTR_PARSE_ERROR) { zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error", peer->host, LOOKUP (attr_str, type)); if (as4_path) aspath_unintern (&as4_path); return ret; } if (ret == BGP_ATTR_PARSE_WITHDRAW) { zlog (peer->log, LOG_WARNING, "%s: Attribute %s, parse error - treating as withdrawal", peer->host, LOOKUP (attr_str, type)); if (as4_path) aspath_unintern (&as4_path); return ret; } /* Check the fetched length. */ if (BGP_INPUT_PNT (peer) != attr_endp) { zlog (peer->log, LOG_WARNING, "%s: BGP attribute %s, fetch error", peer->host, LOOKUP (attr_str, type)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } } /* Check final read pointer is same as end pointer. */ if (BGP_INPUT_PNT (peer) != endp) { zlog (peer->log, LOG_WARNING, "%s: BGP attribute %s, length mismatch", peer->host, LOOKUP (attr_str, type)); bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } /* Check all mandatory well-known attributes are present */ { bgp_attr_parse_ret_t ret; if ((ret = bgp_attr_check (peer, attr)) < 0) { if (as4_path) aspath_unintern (&as4_path); return ret; } } /* * At this place we can see whether we got AS4_PATH and/or * AS4_AGGREGATOR from a 16Bit peer and act accordingly. * We can not do this before we've read all attributes because * the as4 handling does not say whether AS4_PATH has to be sent * after AS_PATH or not - and when AS4_AGGREGATOR will be send * in relationship to AGGREGATOR. * So, to be defensive, we are not relying on any order and read * all attributes first, including these 32bit ones, and now, * afterwards, we look what and if something is to be done for as4. * * It is possible to not have AS_PATH, e.g. GR EoR and sole * MP_UNREACH_NLRI. */ /* actually... this doesn't ever return failure currently, but * better safe than sorry */ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)) && bgp_attr_munge_as4_attrs (peer, attr, as4_path, as4_aggregator, &as4_aggregator_addr)) { bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_MAL_ATTR); if (as4_path) aspath_unintern (&as4_path); return BGP_ATTR_PARSE_ERROR; } /* At this stage, we have done all fiddling with as4, and the * resulting info is in attr->aggregator resp. attr->aspath * so we can chuck as4_aggregator and as4_path alltogether in * order to save memory */ if (as4_path) { aspath_unintern (&as4_path); /* unintern - it is in the hash */ /* The flag that we got this is still there, but that does not * do any trouble */ } /* * The "rest" of the code does nothing with as4_aggregator. * there is no memory attached specifically which is not part * of the attr. * so ignoring just means do nothing. */ /* * Finally do the checks on the aspath we did not do yet * because we waited for a potentially synthesized aspath. */ if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) { ret = bgp_attr_aspath_check (peer, attr); if (ret != BGP_ATTR_PARSE_PROCEED) return ret; } /* Finally intern unknown attribute. */ if (attr->extra && attr->extra->transit) attr->extra->transit = transit_intern (attr->extra->transit); return BGP_ATTR_PARSE_PROCEED; } int stream_put_prefix (struct stream *, struct prefix *); size_t bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi, struct attr *attr) { size_t sizep; /* Set extended bit always to encode the attribute length as 2 bytes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); stream_putw (s, 0); /* Marker: Attribute length. */ stream_putw (s, afi); /* AFI */ stream_putc (s, safi); /* SAFI */ /* Nexthop */ switch (afi) { case AFI_IP: switch (safi) { case SAFI_UNICAST: case SAFI_MULTICAST: stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); break; case SAFI_MPLS_VPN: stream_putc (s, 12); stream_putl (s, 0); stream_putl (s, 0); stream_put (s, &attr->extra->mp_nexthop_global_in, 4); break; default: break; } break; #ifdef HAVE_IPV6 case AFI_IP6: switch (safi) { case SAFI_UNICAST: case SAFI_MULTICAST: { struct attr_extra *attre = attr->extra; assert (attr->extra); stream_putc (s, attre->mp_nexthop_len); stream_put (s, &attre->mp_nexthop_global, 16); if (attre->mp_nexthop_len == 32) stream_put (s, &attre->mp_nexthop_local, 16); } default: break; } break; #endif /*HAVE_IPV6*/ default: break; } /* SNPA */ stream_putc (s, 0); return sizep; } void bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag) { switch (safi) { case SAFI_MPLS_VPN: /* Tag, RD, Prefix write. */ stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); break; default: /* Prefix write. */ stream_put_prefix (s, p); break; } } void bgp_packet_mpattr_end (struct stream *s, size_t sizep) { /* Set MP attribute length. Don't count the (2) bytes used to encode the attr length */ stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2); } /* Make attribute packet. */ bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, u_char *tag) { size_t cp; size_t aspath_sizep; struct aspath *aspath; int send_as4_path = 0; int send_as4_aggregator = 0; int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0; size_t mpattrlen_pos = 0; if (! bgp) bgp = bgp_get_default (); /* Remember current pointer. */ cp = stream_get_endp (s); if (p && !(afi == AFI_IP && safi == SAFI_UNICAST)) { mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr); bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag); bgp_packet_mpattr_end(s, mpattrlen_pos); } /* Origin attribute. */ stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ORIGIN); stream_putc (s, 1); stream_putc (s, attr->origin); /* AS path attribute. */ /* If remote-peer is EBGP */ if (peer->sort == BGP_PEER_EBGP && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || attr->aspath->segments == NULL) && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))) { aspath = aspath_dup (attr->aspath); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { /* Strip the confed info, and then stuff our path CONFED_ID on the front */ aspath = aspath_delete_confed_seq (aspath); aspath = aspath_add_seq (aspath, bgp->confed_id); } else { if (peer->change_local_as) { /* If replace-as is specified, we only use the change_local_as when advertising routes. */ if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) { aspath = aspath_add_seq (aspath, peer->local_as); } aspath = aspath_add_seq (aspath, peer->change_local_as); } else { aspath = aspath_add_seq (aspath, peer->local_as); } } } else if (peer->sort == BGP_PEER_CONFED) { /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */ aspath = aspath_dup (attr->aspath); aspath = aspath_add_confed_seq (aspath, peer->local_as); } else aspath = attr->aspath; /* If peer is not AS4 capable, then: * - send the created AS_PATH out as AS4_PATH (optional, transitive), * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment * types are in it (i.e. exclude them if they are there) * AND do this only if there is at least one asnum > 65535 in the path! * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change * all ASnums > 65535 to BGP_AS_TRANS */ stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_sizep = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit)); /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs * in the path */ if (!use32bit && aspath_has_as4 (aspath)) send_as4_path = 1; /* we'll do this later, at the correct place */ /* Nexthop attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_NEXT_HOP); stream_putc (s, 4); if (safi == SAFI_MPLS_VPN) { if (attr->nexthop.s_addr == 0) stream_put_ipv4 (s, peer->nexthop.v4.s_addr); else stream_put_ipv4 (s, attr->nexthop.s_addr); } else stream_put_ipv4 (s, attr->nexthop.s_addr); } /* MED attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); stream_putc (s, 4); stream_putl (s, attr->med); } /* Local preference. */ if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LOCAL_PREF); stream_putc (s, 4); stream_putl (s, attr->local_pref); } /* Atomic aggregate. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); stream_putc (s, 0); } /* Aggregator. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { assert (attr->extra); /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); if (use32bit) { /* AS4 capable peer */ stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); } else { /* 2-byte AS peer */ stream_putc (s, 6); /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */ if ( attr->extra->aggregator_as > 65535 ) { stream_putw (s, BGP_AS_TRANS); /* we have to send AS4_AGGREGATOR, too. * we'll do that later in order to send attributes in ascending * order. */ send_as4_aggregator = 1; } else stream_putw (s, (u_int16_t) attr->extra->aggregator_as); } stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } /* Community attribute. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))) { if (attr->community->size * 4 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putw (s, attr->community->size * 4); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putc (s, attr->community->size * 4); } stream_put (s, attr->community->val, attr->community->size * 4); } /* Route Reflector. */ if (peer->sort == BGP_PEER_IBGP && from && from->sort == BGP_PEER_IBGP) { /* Originator ID. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_ORIGINATOR_ID); stream_putc (s, 4); if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) stream_put_in_addr (s, &attr->extra->originator_id); else stream_put_in_addr (s, &from->remote_id); /* Cluster list. */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_CLUSTER_LIST); if (attr->extra && attr->extra->cluster) { stream_putc (s, attr->extra->cluster->length + 4); /* If this peer configuration's parent BGP has cluster_id. */ if (bgp->config & BGP_CONFIG_CLUSTER_ID) stream_put_in_addr (s, &bgp->cluster_id); else stream_put_in_addr (s, &bgp->router_id); stream_put (s, attr->extra->cluster->list, attr->extra->cluster->length); } else { stream_putc (s, 4); /* If this peer configuration's parent BGP has cluster_id. */ if (bgp->config & BGP_CONFIG_CLUSTER_ID) stream_put_in_addr (s, &bgp->cluster_id); else stream_put_in_addr (s, &bgp->router_id); } } /* Extended Communities attribute. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES))) { struct attr_extra *attre = attr->extra; assert (attre); if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { if (attre->ecommunity->size * 8 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putw (s, attre->ecommunity->size * 8); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putc (s, attre->ecommunity->size * 8); } stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8); } else { u_int8_t *pnt; int tbit; int ecom_tr_size = 0; int i; for (i = 0; i < attre->ecommunity->size; i++) { pnt = attre->ecommunity->val + (i * 8); tbit = *pnt; if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) continue; ecom_tr_size++; } if (ecom_tr_size) { if (ecom_tr_size * 8 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putw (s, ecom_tr_size * 8); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_EXT_COMMUNITIES); stream_putc (s, ecom_tr_size * 8); } for (i = 0; i < attre->ecommunity->size; i++) { pnt = attre->ecommunity->val + (i * 8); tbit = *pnt; if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) continue; stream_put (s, pnt, 8); } } } } if ( send_as4_path ) { /* If the peer is NOT As4 capable, AND */ /* there are ASnums > 65535 in path THEN * give out AS4_PATH */ /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET * path segments! * Hm, I wonder... confederation things *should* only be at * the beginning of an aspath, right? Then we should use * aspath_delete_confed_seq for this, because it is already * there! (JK) * Folks, talk to me: what is reasonable here!? */ aspath = aspath_delete_confed_seq (aspath); stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS4_PATH); aspath_sizep = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1)); } if (aspath != attr->aspath) aspath_free (aspath); if ( send_as4_aggregator ) { assert (attr->extra); /* send AS4_AGGREGATOR, at this place */ /* this section of code moved here in order to ensure the correct * *ascending* order of attributes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AS4_AGGREGATOR); stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); /* Return total size of attribute. */ return stream_get_endp (s) - cp; } size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi) { unsigned long attrlen_pnt; /* Set extended bit always to encode the attribute length as 2 bytes */ stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI); attrlen_pnt = stream_get_endp (s); stream_putw (s, 0); /* Length of this attribute. */ stream_putw (s, afi); safi = (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi; stream_putc (s, safi); return attrlen_pnt; } void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag) { if (safi == SAFI_MPLS_VPN) { stream_putc (s, p->prefixlen + 88); stream_put (s, tag, 3); stream_put (s, prd->val, 8); stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); } else stream_put_prefix (s, p); } void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt) { bgp_size_t size; /* Set MP attribute length. Don't count the (2) bytes used to encode the attr length */ size = stream_get_endp (s) - attrlen_pnt - 2; stream_putw_at (s, attrlen_pnt, size); } /* Initialization of attribute. */ void bgp_attr_init (void) { aspath_init (); attrhash_init (); community_init (); ecommunity_init (); cluster_init (); transit_init (); } void bgp_attr_finish (void) { aspath_finish (); attrhash_finish (); community_finish (); ecommunity_finish (); cluster_finish (); transit_finish (); } /* Make attribute packet. */ void bgp_dump_routes_attr (struct stream *s, struct attr *attr, struct prefix *prefix) { unsigned long cp; unsigned long len; size_t aspath_lenp; struct aspath *aspath; /* Remember current pointer. */ cp = stream_get_endp (s); /* Place holder of length. */ stream_putw (s, 0); /* Origin attribute. */ stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ORIGIN); stream_putc (s, 1); stream_putc (s, attr->origin); aspath = attr->aspath; stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_AS_PATH); aspath_lenp = stream_get_endp (s); stream_putw (s, 0); stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1)); /* Nexthop attribute. */ /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */ if(prefix != NULL #ifdef HAVE_IPV6 && prefix->family != AF_INET6 #endif /* HAVE_IPV6 */ ) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_NEXT_HOP); stream_putc (s, 4); stream_put_ipv4 (s, attr->nexthop.s_addr); } /* MED attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC); stream_putc (s, 4); stream_putl (s, attr->med); } /* Local preference. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_LOCAL_PREF); stream_putc (s, 4); stream_putl (s, attr->local_pref); } /* Atomic aggregate. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE)) { stream_putc (s, BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE); stream_putc (s, 0); } /* Aggregator. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR)) { assert (attr->extra); stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_AGGREGATOR); stream_putc (s, 8); stream_putl (s, attr->extra->aggregator_as); stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr); } /* Community attribute. */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)) { if (attr->community->size * 4 > 255) { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putw (s, attr->community->size * 4); } else { stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); stream_putc (s, BGP_ATTR_COMMUNITIES); stream_putc (s, attr->community->size * 4); } stream_put (s, attr->community->val, attr->community->size * 4); } #ifdef HAVE_IPV6 /* Add a MP_NLRI attribute to dump the IPv6 next hop */ if (prefix != NULL && prefix->family == AF_INET6 && attr->extra && (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) ) { int sizep; struct attr_extra *attre = attr->extra; stream_putc(s, BGP_ATTR_FLAG_OPTIONAL); stream_putc(s, BGP_ATTR_MP_REACH_NLRI); sizep = stream_get_endp (s); /* MP header */ stream_putc (s, 0); /* Marker: Attribute length. */ stream_putw(s, AFI_IP6); /* AFI */ stream_putc(s, SAFI_UNICAST); /* SAFI */ /* Next hop */ stream_putc(s, attre->mp_nexthop_len); stream_put(s, &attre->mp_nexthop_global, 16); if (attre->mp_nexthop_len == 32) stream_put(s, &attre->mp_nexthop_local, 16); /* SNPA */ stream_putc(s, 0); /* Prefix */ stream_put_prefix(s, prefix); /* Set MP attribute length. */ stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } #endif /* HAVE_IPV6 */ /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); } quagga-0.99.24.1/bgpd/bgp_community.c0000644000175000017500000003212312476520570014171 00000000000000/* Community attribute related functions. Copyright (C) 1998, 2001 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "hash.h" #include "memory.h" #include "bgpd/bgp_community.h" /* Hash of community attribute. */ static struct hash *comhash; /* Allocate a new communities value. */ static struct community * community_new (void) { return (struct community *) XCALLOC (MTYPE_COMMUNITY, sizeof (struct community)); } /* Free communities value. */ void community_free (struct community *com) { if (com->val) XFREE (MTYPE_COMMUNITY_VAL, com->val); if (com->str) XFREE (MTYPE_COMMUNITY_STR, com->str); XFREE (MTYPE_COMMUNITY, com); } /* Add one community value to the community. */ static void community_add_val (struct community *com, u_int32_t val) { com->size++; if (com->val) com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); else com->val = XMALLOC (MTYPE_COMMUNITY_VAL, com_length (com)); val = htonl (val); memcpy (com_lastval (com), &val, sizeof (u_int32_t)); } /* Delete one community. */ void community_del_val (struct community *com, u_int32_t *val) { int i = 0; int c = 0; if (! com->val) return; while (i < com->size) { if (memcmp (com->val + i, val, sizeof (u_int32_t)) == 0) { c = com->size -i -1; if (c > 0) memmove (com->val + i, com->val + (i + 1), c * sizeof (*val)); com->size--; if (com->size > 0) com->val = XREALLOC (MTYPE_COMMUNITY_VAL, com->val, com_length (com)); else { XFREE (MTYPE_COMMUNITY_VAL, com->val); com->val = NULL; } return; } i++; } } /* Delete all communities listed in com2 from com1 */ struct community * community_delete (struct community *com1, struct community *com2) { int i = 0; while(i < com2->size) { community_del_val (com1, com2->val + i); i++; } return com1; } /* Callback function from qsort(). */ static int community_compare (const void *a1, const void *a2) { u_int32_t v1; u_int32_t v2; memcpy (&v1, a1, sizeof (u_int32_t)); memcpy (&v2, a2, sizeof (u_int32_t)); v1 = ntohl (v1); v2 = ntohl (v2); if (v1 < v2) return -1; if (v1 > v2) return 1; return 0; } int community_include (struct community *com, u_int32_t val) { int i; val = htonl (val); for (i = 0; i < com->size; i++) if (memcmp (&val, com_nthval (com, i), sizeof (u_int32_t)) == 0) return 1; return 0; } static u_int32_t community_val_get (struct community *com, int i) { u_char *p; u_int32_t val; p = (u_char *) com->val; p += (i * 4); memcpy (&val, p, sizeof (u_int32_t)); return ntohl (val); } /* Sort and uniq given community. */ struct community * community_uniq_sort (struct community *com) { int i; struct community *new; u_int32_t val; if (! com) return NULL; new = community_new ();; for (i = 0; i < com->size; i++) { val = community_val_get (com, i); if (! community_include (new, val)) community_add_val (new, val); } qsort (new->val, new->size, sizeof (u_int32_t), community_compare); return new; } /* Convert communities attribute to string. For Well-known communities value, below keyword is used. 0x0 "internet" 0xFFFFFF01 "no-export" 0xFFFFFF02 "no-advertise" 0xFFFFFF03 "local-AS" For other values, "AS:VAL" format is used. */ static char * community_com2str (struct community *com) { int i; char *str; char *pnt; int len; int first; u_int32_t comval; u_int16_t as; u_int16_t val; if (!com) return NULL; /* When communities attribute is empty. */ if (com->size == 0) { str = XMALLOC (MTYPE_COMMUNITY_STR, 1); str[0] = '\0'; return str; } /* Memory allocation is time consuming work. So we calculate required string length first. */ len = 0; for (i = 0; i < com->size; i++) { memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); comval = ntohl (comval); switch (comval) { case COMMUNITY_INTERNET: len += strlen (" internet"); break; case COMMUNITY_NO_EXPORT: len += strlen (" no-export"); break; case COMMUNITY_NO_ADVERTISE: len += strlen (" no-advertise"); break; case COMMUNITY_LOCAL_AS: len += strlen (" local-AS"); break; default: len += strlen (" 65536:65535"); break; } } /* Allocate memory. */ str = pnt = XMALLOC (MTYPE_COMMUNITY_STR, len); first = 1; /* Fill in string. */ for (i = 0; i < com->size; i++) { memcpy (&comval, com_nthval (com, i), sizeof (u_int32_t)); comval = ntohl (comval); if (first) first = 0; else *pnt++ = ' '; switch (comval) { case COMMUNITY_INTERNET: strcpy (pnt, "internet"); pnt += strlen ("internet"); break; case COMMUNITY_NO_EXPORT: strcpy (pnt, "no-export"); pnt += strlen ("no-export"); break; case COMMUNITY_NO_ADVERTISE: strcpy (pnt, "no-advertise"); pnt += strlen ("no-advertise"); break; case COMMUNITY_LOCAL_AS: strcpy (pnt, "local-AS"); pnt += strlen ("local-AS"); break; default: as = (comval >> 16) & 0xFFFF; val = comval & 0xFFFF; sprintf (pnt, "%u:%d", as, val); pnt += strlen (pnt); break; } } *pnt = '\0'; return str; } /* Intern communities attribute. */ struct community * community_intern (struct community *com) { struct community *find; /* Assert this community structure is not interned. */ assert (com->refcnt == 0); /* Lookup community hash. */ find = (struct community *) hash_get (comhash, com, hash_alloc_intern); /* Arguemnt com is allocated temporary. So when it is not used in hash, it should be freed. */ if (find != com) community_free (com); /* Increment refrence counter. */ find->refcnt++; /* Make string. */ if (! find->str) find->str = community_com2str (find); return find; } /* Free community attribute. */ void community_unintern (struct community **com) { struct community *ret; if ((*com)->refcnt) (*com)->refcnt--; /* Pull off from hash. */ if ((*com)->refcnt == 0) { /* Community value com must exist in hash. */ ret = (struct community *) hash_release (comhash, *com); assert (ret != NULL); community_free (*com); *com = NULL; } } /* Create new community attribute. */ struct community * community_parse (u_int32_t *pnt, u_short length) { struct community tmp; struct community *new; /* If length is malformed return NULL. */ if (length % 4) return NULL; /* Make temporary community for hash look up. */ tmp.size = length / 4; tmp.val = pnt; new = community_uniq_sort (&tmp); return community_intern (new); } struct community * community_dup (struct community *com) { struct community *new; new = XCALLOC (MTYPE_COMMUNITY, sizeof (struct community)); new->size = com->size; if (new->size) { new->val = XMALLOC (MTYPE_COMMUNITY_VAL, com->size * 4); memcpy (new->val, com->val, com->size * 4); } else new->val = NULL; return new; } /* Retrun string representation of communities attribute. */ char * community_str (struct community *com) { if (!com) return NULL; if (! com->str) com->str = community_com2str (com); return com->str; } /* Make hash value of community attribute. This function is used by hash package.*/ unsigned int community_hash_make (struct community *com) { unsigned char *pnt = (unsigned char *)com->val; int size = com->size * 4; unsigned int key = 0; int c; for (c = 0; c < size; c += 4) { key += pnt[c]; key += pnt[c + 1]; key += pnt[c + 2]; key += pnt[c + 3]; } return key; } int community_match (const struct community *com1, const struct community *com2) { int i = 0; int j = 0; if (com1 == NULL && com2 == NULL) return 1; if (com1 == NULL || com2 == NULL) return 0; if (com1->size < com2->size) return 0; /* Every community on com2 needs to be on com1 for this to match */ while (i < com1->size && j < com2->size) { if (memcmp (com1->val + i, com2->val + j, sizeof (u_int32_t)) == 0) j++; i++; } if (j == com2->size) return 1; else return 0; } /* If two aspath have same value then return 1 else return 0. This function is used by hash package. */ int community_cmp (const struct community *com1, const struct community *com2) { if (com1 == NULL && com2 == NULL) return 1; if (com1 == NULL || com2 == NULL) return 0; if (com1->size == com2->size) if (memcmp (com1->val, com2->val, com1->size * 4) == 0) return 1; return 0; } /* Add com2 to the end of com1. */ struct community * community_merge (struct community *com1, struct community *com2) { if (com1->val) com1->val = XREALLOC (MTYPE_COMMUNITY_VAL, com1->val, (com1->size + com2->size) * 4); else com1->val = XMALLOC (MTYPE_COMMUNITY_VAL, (com1->size + com2->size) * 4); memcpy (com1->val + com1->size, com2->val, com2->size * 4); com1->size += com2->size; return com1; } /* Community token enum. */ enum community_token { community_token_val, community_token_no_export, community_token_no_advertise, community_token_local_as, community_token_unknown }; /* Get next community token from string. */ static const char * community_gettoken (const char *buf, enum community_token *token, u_int32_t *val) { const char *p = buf; /* Skip white space. */ while (isspace ((int) *p)) p++; /* Check the end of the line. */ if (*p == '\0') return NULL; /* Well known community string check. */ if (isalpha ((int) *p)) { if (strncmp (p, "internet", strlen ("internet")) == 0) { *val = COMMUNITY_INTERNET; *token = community_token_no_export; p += strlen ("internet"); return p; } if (strncmp (p, "no-export", strlen ("no-export")) == 0) { *val = COMMUNITY_NO_EXPORT; *token = community_token_no_export; p += strlen ("no-export"); return p; } if (strncmp (p, "no-advertise", strlen ("no-advertise")) == 0) { *val = COMMUNITY_NO_ADVERTISE; *token = community_token_no_advertise; p += strlen ("no-advertise"); return p; } if (strncmp (p, "local-AS", strlen ("local-AS")) == 0) { *val = COMMUNITY_LOCAL_AS; *token = community_token_local_as; p += strlen ("local-AS"); return p; } /* Unknown string. */ *token = community_token_unknown; return NULL; } /* Community value. */ if (isdigit ((int) *p)) { int separator = 0; int digit = 0; u_int32_t community_low = 0; u_int32_t community_high = 0; while (isdigit ((int) *p) || *p == ':') { if (*p == ':') { if (separator) { *token = community_token_unknown; return NULL; } else { separator = 1; digit = 0; community_high = community_low << 16; community_low = 0; } } else { digit = 1; community_low *= 10; community_low += (*p - '0'); } p++; } if (! digit) { *token = community_token_unknown; return NULL; } *val = community_high + community_low; *token = community_token_val; return p; } *token = community_token_unknown; return NULL; } /* convert string to community structure */ struct community * community_str2com (const char *str) { struct community *com = NULL; struct community *com_sort = NULL; u_int32_t val = 0; enum community_token token = community_token_unknown; do { str = community_gettoken (str, &token, &val); switch (token) { case community_token_val: case community_token_no_export: case community_token_no_advertise: case community_token_local_as: if (com == NULL) com = community_new(); community_add_val (com, val); break; case community_token_unknown: default: if (com) community_free (com); return NULL; } } while (str); if (! com) return NULL; com_sort = community_uniq_sort (com); community_free (com); return com_sort; } /* Return communities hash entry count. */ unsigned long community_count (void) { return comhash->count; } /* Return communities hash. */ struct hash * community_hash (void) { return comhash; } /* Initialize comminity related hash. */ void community_init (void) { comhash = hash_create ((unsigned int (*) (void *))community_hash_make, (int (*) (const void *, const void *))community_cmp); } void community_finish (void) { hash_free (comhash); comhash = NULL; } quagga-0.99.24.1/bgpd/bgp_aspath.c0000644000175000017500000013540512476520570013434 00000000000000/* AS path management routines. Copyright (C) 1996, 97, 98, 99 Kunihiro Ishiguro Copyright (C) 2005 Sun Microsystems, Inc. This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "hash.h" #include "memory.h" #include "vector.h" #include "vty.h" #include "str.h" #include "log.h" #include "stream.h" #include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" /* Attr. Flags and Attr. Type Code. */ #define AS_HEADER_SIZE 2 /* Now FOUR octets are used for AS value. */ #define AS_VALUE_SIZE sizeof (as_t) /* This is the old one */ #define AS16_VALUE_SIZE sizeof (as16_t) /* Maximum protocol segment length value */ #define AS_SEGMENT_MAX 255 /* The following length and size macros relate specifically to Quagga's * internal representation of AS-Segments, not per se to the on-wire * sizes and lengths. At present (200508) they sort of match, however * the ONLY functions which should now about the on-wire syntax are * aspath_put, assegment_put and assegment_parse. * * aspath_put returns bytes written, the only definitive record of * size of wire-format attribute.. */ /* Calculated size in bytes of ASN segment data to hold N ASN's */ #define ASSEGMENT_DATA_SIZE(N,S) \ ((N) * ( (S) ? AS_VALUE_SIZE : AS16_VALUE_SIZE) ) /* Calculated size of segment struct to hold N ASN's */ #define ASSEGMENT_SIZE(N,S) (AS_HEADER_SIZE + ASSEGMENT_DATA_SIZE (N,S)) /* AS segment octet length. */ #define ASSEGMENT_LEN(X,S) ASSEGMENT_SIZE((X)->length,S) /* AS_SEQUENCE segments can be packed together */ /* Can the types of X and Y be considered for packing? */ #define ASSEGMENT_TYPES_PACKABLE(X,Y) \ ( ((X)->type == (Y)->type) \ && ((X)->type == AS_SEQUENCE)) /* Types and length of X,Y suitable for packing? */ #define ASSEGMENTS_PACKABLE(X,Y) \ ( ASSEGMENT_TYPES_PACKABLE( (X), (Y)) \ && ( ((X)->length + (Y)->length) <= AS_SEGMENT_MAX ) ) /* As segment header - the on-wire representation * NOT the internal representation! */ struct assegment_header { u_char type; u_char length; }; /* Hash for aspath. This is the top level structure of AS path. */ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; /* Callers are required to initialize the memory */ static as_t * assegment_data_new (int num) { return (XMALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1))); } /* Get a new segment. Note that 0 is an allowed length, * and will result in a segment with no allocated data segment. * the caller should immediately assign data to the segment, as the segment * otherwise is not generally valid */ static struct assegment * assegment_new (u_char type, u_short length) { struct assegment *new; new = XCALLOC (MTYPE_AS_SEG, sizeof (struct assegment)); if (length) new->as = assegment_data_new (length); new->length = length; new->type = type; return new; } static void assegment_free (struct assegment *seg) { if (!seg) return; if (seg->as) XFREE (MTYPE_AS_SEG_DATA, seg->as); memset (seg, 0xfe, sizeof(struct assegment)); XFREE (MTYPE_AS_SEG, seg); return; } /* free entire chain of segments */ static void assegment_free_all (struct assegment *seg) { struct assegment *prev; while (seg) { prev = seg; seg = seg->next; assegment_free (prev); } } /* Duplicate just the given assegment and its data */ static struct assegment * assegment_dup (struct assegment *seg) { struct assegment *new; new = assegment_new (seg->type, seg->length); memcpy (new->as, seg->as, ASSEGMENT_DATA_SIZE (new->length, 1) ); return new; } /* Duplicate entire chain of assegments, return the head */ static struct assegment * assegment_dup_all (struct assegment *seg) { struct assegment *new = NULL; struct assegment *head = NULL; while (seg) { if (head) { new->next = assegment_dup (seg); new = new->next; } else head = new = assegment_dup (seg); seg = seg->next; } return head; } /* prepend the as number to given segment, given num of times */ static struct assegment * assegment_prepend_asns (struct assegment *seg, as_t asnum, int num) { as_t *newas; int i; if (!num) return seg; if (num >= AS_SEGMENT_MAX) return seg; /* we don't do huge prepends */ newas = assegment_data_new (seg->length + num); for (i = 0; i < num; i++) newas[i] = asnum; memcpy (newas + num, seg->as, ASSEGMENT_DATA_SIZE (seg->length, 1)); XFREE (MTYPE_AS_SEG_DATA, seg->as); seg->as = newas; seg->length += num; return seg; } /* append given array of as numbers to the segment */ static struct assegment * assegment_append_asns (struct assegment *seg, as_t *asnos, int num) { as_t *newas; newas = XREALLOC (MTYPE_AS_SEG_DATA, seg->as, ASSEGMENT_DATA_SIZE (seg->length + num, 1)); if (newas) { seg->as = newas; memcpy (seg->as + seg->length, asnos, ASSEGMENT_DATA_SIZE(num, 1)); seg->length += num; return seg; } assegment_free_all (seg); return NULL; } static int int_cmp (const void *p1, const void *p2) { const as_t *as1 = p1; const as_t *as2 = p2; return (*as1 == *as2) ? 0 : ( (*as1 > *as2) ? 1 : -1); } /* normalise the segment. * In particular, merge runs of AS_SEQUENCEs into one segment * Internally, we do not care about the wire segment length limit, and * we want each distinct AS_PATHs to have the exact same internal * representation - eg, so that our hashing actually works.. */ static struct assegment * assegment_normalise (struct assegment *head) { struct assegment *seg = head, *pin; struct assegment *tmp; if (!head) return head; while (seg) { pin = seg; /* Sort values SET segments, for determinism in paths to aid * creation of hash values / path comparisons * and because it helps other lesser implementations ;) */ if (seg->type == AS_SET || seg->type == AS_CONFED_SET) { int tail = 0; int i; qsort (seg->as, seg->length, sizeof(as_t), int_cmp); /* weed out dupes */ for (i=1; i < seg->length; i++) { if (seg->as[tail] == seg->as[i]) continue; tail++; if (tail < i) seg->as[tail] = seg->as[i]; } /* seg->length can be 0.. */ if (seg->length) seg->length = tail + 1; } /* read ahead from the current, pinned segment while the segments * are packable/mergeable. Append all following packable segments * to the segment we have pinned and remove these appended * segments. */ while (pin->next && ASSEGMENT_TYPES_PACKABLE(pin, pin->next)) { tmp = pin->next; seg = pin->next; /* append the next sequence to the pinned sequence */ pin = assegment_append_asns (pin, seg->as, seg->length); /* bypass the next sequence */ pin->next = seg->next; /* get rid of the now referenceless segment */ assegment_free (tmp); } seg = pin->next; } return head; } static struct aspath * aspath_new (void) { return XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); } /* Free AS path structure. */ void aspath_free (struct aspath *aspath) { if (!aspath) return; if (aspath->segments) assegment_free_all (aspath->segments); if (aspath->str) XFREE (MTYPE_AS_STR, aspath->str); XFREE (MTYPE_AS_PATH, aspath); } /* Unintern aspath from AS path bucket. */ void aspath_unintern (struct aspath **aspath) { struct aspath *ret; struct aspath *asp = *aspath; if (asp->refcnt) asp->refcnt--; if (asp->refcnt == 0) { /* This aspath must exist in aspath hash table. */ ret = hash_release (ashash, asp); assert (ret != NULL); aspath_free (asp); *aspath = NULL; } } /* Return the start or end delimiters for a particular Segment type */ #define AS_SEG_START 0 #define AS_SEG_END 1 static char aspath_delimiter_char (u_char type, u_char which) { int i; struct { int type; char start; char end; } aspath_delim_char [] = { { AS_SET, '{', '}' }, { AS_CONFED_SET, '[', ']' }, { AS_CONFED_SEQUENCE, '(', ')' }, { 0 } }; for (i = 0; aspath_delim_char[i].type != 0; i++) { if (aspath_delim_char[i].type == type) { if (which == AS_SEG_START) return aspath_delim_char[i].start; else if (which == AS_SEG_END) return aspath_delim_char[i].end; } } return ' '; } /* countup asns from this segment and index onward */ static int assegment_count_asns (struct assegment *seg, int from) { int count = 0; while (seg) { if (!from) count += seg->length; else { count += (seg->length - from); from = 0; } seg = seg->next; } return count; } unsigned int aspath_count_confeds (struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; while (seg) { if (seg->type == AS_CONFED_SEQUENCE) count += seg->length; else if (seg->type == AS_CONFED_SET) count++; seg = seg->next; } return count; } unsigned int aspath_count_hops (struct aspath *aspath) { int count = 0; struct assegment *seg = aspath->segments; while (seg) { if (seg->type == AS_SEQUENCE) count += seg->length; else if (seg->type == AS_SET) count++; seg = seg->next; } return count; } /* Estimate size aspath /might/ take if encoded into an * ASPATH attribute. * * This is a quick estimate, not definitive! aspath_put() * may return a different number!! */ unsigned int aspath_size (struct aspath *aspath) { int size = 0; struct assegment *seg = aspath->segments; while (seg) { size += ASSEGMENT_SIZE(seg->length, 1); seg = seg->next; } return size; } /* Return highest public ASN in path */ as_t aspath_highest (struct aspath *aspath) { struct assegment *seg = aspath->segments; as_t highest = 0; unsigned int i; while (seg) { for (i = 0; i < seg->length; i++) if (seg->as[i] > highest && (seg->as[i] < BGP_PRIVATE_AS_MIN || seg->as[i] > BGP_PRIVATE_AS_MAX)) highest = seg->as[i]; seg = seg->next; } return highest; } /* Return the left-most ASN in path */ as_t aspath_leftmost (struct aspath *aspath) { struct assegment *seg = aspath->segments; as_t leftmost = 0; if (seg && seg->length && seg->type == AS_SEQUENCE) leftmost = seg->as[0]; return leftmost; } /* Return 1 if there are any 4-byte ASes in the path */ unsigned int aspath_has_as4 (struct aspath *aspath) { struct assegment *seg = aspath->segments; unsigned int i; while (seg) { for (i = 0; i < seg->length; i++) if (seg->as[i] > BGP_AS_MAX) return 1; seg = seg->next; } return 0; } /* Convert aspath structure to string expression. */ static void aspath_make_str_count (struct aspath *as) { struct assegment *seg; int str_size; int len = 0; char *str_buf; /* Empty aspath. */ if (!as->segments) { as->str = XMALLOC (MTYPE_AS_STR, 1); as->str[0] = '\0'; as->str_len = 0; return; } seg = as->segments; /* ASN takes 5 to 10 chars plus seperator, see below. * If there is one differing segment type, we need an additional * 2 chars for segment delimiters, and the final '\0'. * Hopefully this is large enough to avoid hitting the realloc * code below for most common sequences. * * This was changed to 10 after the well-known BGP assertion, which * had hit some parts of the Internet in May of 2009. */ #define ASN_STR_LEN (10 + 1) str_size = MAX (assegment_count_asns (seg, 0) * ASN_STR_LEN + 2 + 1, ASPATH_STR_DEFAULT_LEN); str_buf = XMALLOC (MTYPE_AS_STR, str_size); while (seg) { int i; char seperator; /* Check AS type validity. Set seperator for segment */ switch (seg->type) { case AS_SET: case AS_CONFED_SET: seperator = ','; break; case AS_SEQUENCE: case AS_CONFED_SEQUENCE: seperator = ' '; break; default: XFREE (MTYPE_AS_STR, str_buf); as->str = NULL; as->str_len = 0; return; } /* We might need to increase str_buf, particularly if path has * differing segments types, our initial guesstimate above will * have been wrong. Need 10 chars for ASN, a seperator each and * potentially two segment delimiters, plus a space between each * segment and trailing zero. * * This definitely didn't work with the value of 5 bytes and * 32-bit ASNs. */ #define SEGMENT_STR_LEN(X) (((X)->length * ASN_STR_LEN) + 2 + 1 + 1) if ( (len + SEGMENT_STR_LEN(seg)) > str_size) { str_size = len + SEGMENT_STR_LEN(seg); str_buf = XREALLOC (MTYPE_AS_STR, str_buf, str_size); } #undef ASN_STR_LEN #undef SEGMENT_STR_LEN if (seg->type != AS_SEQUENCE) len += snprintf (str_buf + len, str_size - len, "%c", aspath_delimiter_char (seg->type, AS_SEG_START)); /* write out the ASNs, with their seperators, bar the last one*/ for (i = 0; i < seg->length; i++) { len += snprintf (str_buf + len, str_size - len, "%u", seg->as[i]); if (i < (seg->length - 1)) len += snprintf (str_buf + len, str_size - len, "%c", seperator); } if (seg->type != AS_SEQUENCE) len += snprintf (str_buf + len, str_size - len, "%c", aspath_delimiter_char (seg->type, AS_SEG_END)); if (seg->next) len += snprintf (str_buf + len, str_size - len, " "); seg = seg->next; } assert (len < str_size); str_buf[len] = '\0'; as->str = str_buf; as->str_len = len; return; } static void aspath_str_update (struct aspath *as) { if (as->str) XFREE (MTYPE_AS_STR, as->str); aspath_make_str_count (as); } /* Intern allocated AS path. */ struct aspath * aspath_intern (struct aspath *aspath) { struct aspath *find; /* Assert this AS path structure is not interned and has the string representation built. */ assert (aspath->refcnt == 0); assert (aspath->str); /* Check AS path hash. */ find = hash_get (ashash, aspath, hash_alloc_intern); if (find != aspath) aspath_free (aspath); find->refcnt++; return find; } /* Duplicate aspath structure. Created same aspath structure but reference count and AS path string is cleared. */ struct aspath * aspath_dup (struct aspath *aspath) { unsigned short buflen = aspath->str_len + 1; struct aspath *new; new = XCALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); if (aspath->segments) new->segments = assegment_dup_all (aspath->segments); if (!aspath->str) return new; new->str = XMALLOC (MTYPE_AS_STR, buflen); new->str_len = aspath->str_len; /* copy the string data */ if (aspath->str_len > 0) memcpy (new->str, aspath->str, buflen); else new->str[0] = '\0'; return new; } static void * aspath_hash_alloc (void *arg) { const struct aspath *aspath = arg; struct aspath *new; /* Malformed AS path value. */ assert (aspath->str); if (! aspath->str) return NULL; /* New aspath structure is needed. */ new = XMALLOC (MTYPE_AS_PATH, sizeof (struct aspath)); /* Reuse segments and string representation */ new->refcnt = 0; new->segments = aspath->segments; new->str = aspath->str; new->str_len = aspath->str_len; return new; } /* parse as-segment byte stream in struct assegment */ static int assegments_parse (struct stream *s, size_t length, struct assegment **result, int use32bit) { struct assegment_header segh; struct assegment *seg, *prev = NULL, *head = NULL; size_t bytes = 0; /* empty aspath (ie iBGP or somesuch) */ if (length == 0) return 0; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu", (unsigned long) length); /* basic checks */ if ((STREAM_READABLE(s) < length) || (STREAM_READABLE(s) < AS_HEADER_SIZE) || (length % AS16_VALUE_SIZE )) return -1; while (bytes < length) { int i; size_t seg_size; if ((length - bytes) <= AS_HEADER_SIZE) { if (head) assegment_free_all (head); return -1; } /* softly softly, get the header first on its own */ segh.type = stream_getc (s); segh.length = stream_getc (s); seg_size = ASSEGMENT_SIZE(segh.length, use32bit); if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d", segh.type, segh.length); /* check it.. */ if ( ((bytes + seg_size) > length) /* 1771bis 4.3b: seg length contains one or more */ || (segh.length == 0) /* Paranoia in case someone changes type of segment length. * Shift both values by 0x10 to make the comparison operate * on more, than 8 bits (otherwise it's a warning, bug #564). */ || ((sizeof segh.length > 1) && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) { if (head) assegment_free_all (head); return -1; } switch (segh.type) { case AS_SEQUENCE: case AS_SET: case AS_CONFED_SEQUENCE: case AS_CONFED_SET: break; default: if (head) assegment_free_all (head); return -1; } /* now its safe to trust lengths */ seg = assegment_new (segh.type, segh.length); if (head) prev->next = seg; else /* it's the first segment */ head = prev = seg; for (i = 0; i < segh.length; i++) seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); bytes += seg_size; if (BGP_DEBUG (as4, AS4_SEGMENT)) zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", (unsigned long) bytes); prev = seg; } *result = assegment_normalise (head); return 0; } /* AS path parse function. pnt is a pointer to byte stream and length is length of byte stream. If there is same AS path in the the AS path hash then return it else make new AS path structure. On error NULL is returned. */ struct aspath * aspath_parse (struct stream *s, size_t length, int use32bit) { struct aspath as; struct aspath *find; /* If length is odd it's malformed AS path. */ /* Nit-picking: if (use32bit == 0) it is malformed if odd, * otherwise its malformed when length is larger than 2 and (length-2) * is not dividable by 4. * But... this time we're lazy */ if (length % AS16_VALUE_SIZE ) return NULL; memset (&as, 0, sizeof (struct aspath)); if (assegments_parse (s, length, &as.segments, use32bit) < 0) return NULL; /* If already same aspath exist then return it. */ find = hash_get (ashash, &as, aspath_hash_alloc); /* bug! should not happen, let the daemon crash below */ assert (find); /* if the aspath was already hashed free temporary memory. */ if (find->refcnt) { assegment_free_all (as.segments); /* aspath_key_make() always updates the string */ XFREE (MTYPE_AS_STR, as.str); } find->refcnt++; return find; } static void assegment_data_put (struct stream *s, as_t *as, int num, int use32bit) { int i; assert (num <= AS_SEGMENT_MAX); for (i = 0; i < num; i++) if ( use32bit ) stream_putl (s, as[i]); else { if ( as[i] <= BGP_AS_MAX ) stream_putw(s, as[i]); else stream_putw(s, BGP_AS_TRANS); } } static size_t assegment_header_put (struct stream *s, u_char type, int length) { size_t lenp; assert (length <= AS_SEGMENT_MAX); stream_putc (s, type); lenp = stream_get_endp (s); stream_putc (s, length); return lenp; } /* write aspath data to stream */ size_t aspath_put (struct stream *s, struct aspath *as, int use32bit ) { struct assegment *seg = as->segments; size_t bytes = 0; if (!seg || seg->length == 0) return 0; if (seg) { /* * Hey, what do we do when we have > STREAM_WRITABLE(s) here? * At the moment, we would write out a partial aspath, and our peer * will complain and drop the session :-/ * * The general assumption here is that many things tested will * never happen. And, in real live, up to now, they have not. */ while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) { struct assegment *next = seg->next; int written = 0; int asns_packed = 0; size_t lenp; /* Overlength segments have to be split up */ while ( (seg->length - written) > AS_SEGMENT_MAX) { assegment_header_put (s, seg->type, AS_SEGMENT_MAX); assegment_data_put (s, seg->as, AS_SEGMENT_MAX, use32bit); written += AS_SEGMENT_MAX; bytes += ASSEGMENT_SIZE (written, use32bit); } /* write the final segment, probably is also the first */ lenp = assegment_header_put (s, seg->type, seg->length - written); assegment_data_put (s, (seg->as + written), seg->length - written, use32bit); /* Sequence-type segments can be 'packed' together * Case of a segment which was overlength and split up * will be missed here, but that doesn't matter. */ while (next && ASSEGMENTS_PACKABLE (seg, next)) { /* NB: We should never normally get here given we * normalise aspath data when parse them. However, better * safe than sorry. We potentially could call * assegment_normalise here instead, but it's cheaper and * easier to do it on the fly here rather than go through * the segment list twice every time we write out * aspath's. */ /* Next segment's data can fit in this one */ assegment_data_put (s, next->as, next->length, use32bit); /* update the length of the segment header */ stream_putc_at (s, lenp, seg->length - written + next->length); asns_packed += next->length; next = next->next; } bytes += ASSEGMENT_SIZE (seg->length - written + asns_packed, use32bit); seg = next; } } return bytes; } /* This is for SNMP BGP4PATHATTRASPATHSEGMENT * We have no way to manage the storage, so we use a static stream * wrapper around aspath_put. */ u_char * aspath_snmp_pathseg (struct aspath *as, size_t *varlen) { #define SNMP_PATHSEG_MAX 1024 if (!snmp_stream) snmp_stream = stream_new (SNMP_PATHSEG_MAX); else stream_reset (snmp_stream); if (!as) { *varlen = 0; return NULL; } aspath_put (snmp_stream, as, 0); /* use 16 bit for now here */ *varlen = stream_get_endp (snmp_stream); return stream_pnt(snmp_stream); } #define min(A,B) ((A) < (B) ? (A) : (B)) static struct assegment * aspath_aggregate_as_set_add (struct aspath *aspath, struct assegment *asset, as_t as) { int i; /* If this is first AS set member, create new as-set segment. */ if (asset == NULL) { asset = assegment_new (AS_SET, 1); if (! aspath->segments) aspath->segments = asset; else { struct assegment *seg = aspath->segments; while (seg->next) seg = seg->next; seg->next = asset; } asset->type = AS_SET; asset->length = 1; asset->as[0] = as; } else { /* Check this AS value already exists or not. */ for (i = 0; i < asset->length; i++) if (asset->as[i] == as) return asset; asset->length++; asset->as = XREALLOC (MTYPE_AS_SEG_DATA, asset->as, asset->length * AS_VALUE_SIZE); asset->as[asset->length - 1] = as; } return asset; } /* Modify as1 using as2 for aggregation. */ struct aspath * aspath_aggregate (struct aspath *as1, struct aspath *as2) { int i; int minlen; int match; int from; struct assegment *seg1 = as1->segments; struct assegment *seg2 = as2->segments; struct aspath *aspath = NULL; struct assegment *asset; struct assegment *prevseg = NULL; match = 0; minlen = 0; aspath = NULL; asset = NULL; /* First of all check common leading sequence. */ while (seg1 && seg2) { /* Check segment type. */ if (seg1->type != seg2->type) break; /* Minimum segment length. */ minlen = min (seg1->length, seg2->length); for (match = 0; match < minlen; match++) if (seg1->as[match] != seg2->as[match]) break; if (match) { struct assegment *seg = assegment_new (seg1->type, 0); seg = assegment_append_asns (seg, seg1->as, match); if (! aspath) { aspath = aspath_new (); aspath->segments = seg; } else prevseg->next = seg; prevseg = seg; } if (match != minlen || match != seg1->length || seg1->length != seg2->length) break; seg1 = seg1->next; seg2 = seg2->next; } if (! aspath) aspath = aspath_new(); /* Make as-set using rest of all information. */ from = match; while (seg1) { for (i = from; i < seg1->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg1->as[i]); from = 0; seg1 = seg1->next; } from = match; while (seg2) { for (i = from; i < seg2->length; i++) asset = aspath_aggregate_as_set_add (aspath, asset, seg2->as[i]); from = 0; seg2 = seg2->next; } assegment_normalise (aspath->segments); aspath_str_update (aspath); return aspath; } /* When a BGP router receives an UPDATE with an MP_REACH_NLRI attribute, check the leftmost AS number in the AS_PATH attribute is or not the peer's AS number. */ int aspath_firstas_check (struct aspath *aspath, as_t asno) { if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; if (aspath->segments && (aspath->segments->type == AS_SEQUENCE) && (aspath->segments->as[0] == asno )) return 1; return 0; } /* AS path loop check. If aspath contains asno then return >= 1. */ int aspath_loop_check (struct aspath *aspath, as_t asno) { struct assegment *seg; int count = 0; if ( (aspath == NULL) || (aspath->segments == NULL) ) return 0; seg = aspath->segments; while (seg) { int i; for (i = 0; i < seg->length; i++) if (seg->as[i] == asno) count++; seg = seg->next; } return count; } /* When all of AS path is private AS return 1. */ int aspath_private_as_check (struct aspath *aspath) { struct assegment *seg; if ( !(aspath && aspath->segments) ) return 0; seg = aspath->segments; while (seg) { int i; for (i = 0; i < seg->length; i++) { if ( (seg->as[i] < BGP_PRIVATE_AS_MIN) || (seg->as[i] > BGP_PRIVATE_AS_MAX) ) return 0; } seg = seg->next; } return 1; } /* AS path confed check. If aspath contains confed set or sequence then return 1. */ int aspath_confed_check (struct aspath *aspath) { struct assegment *seg; if ( !(aspath && aspath->segments) ) return 0; seg = aspath->segments; while (seg) { if (seg->type == AS_CONFED_SET || seg->type == AS_CONFED_SEQUENCE) return 1; seg = seg->next; } return 0; } /* Leftmost AS path segment confed check. If leftmost AS segment is of type AS_CONFED_SEQUENCE or AS_CONFED_SET then return 1. */ int aspath_left_confed_check (struct aspath *aspath) { if ( !(aspath && aspath->segments) ) return 0; if ( (aspath->segments->type == AS_CONFED_SEQUENCE) || (aspath->segments->type == AS_CONFED_SET) ) return 1; return 0; } /* Merge as1 to as2. as2 should be uninterned aspath. */ static struct aspath * aspath_merge (struct aspath *as1, struct aspath *as2) { struct assegment *last, *new; if (! as1 || ! as2) return NULL; last = new = assegment_dup_all (as1->segments); /* find the last valid segment */ while (last && last->next) last = last->next; last->next = as2->segments; as2->segments = new; aspath_str_update (as2); return as2; } /* Prepend as1 to as2. as2 should be uninterned aspath. */ struct aspath * aspath_prepend (struct aspath *as1, struct aspath *as2) { struct assegment *seg1; struct assegment *seg2; if (! as1 || ! as2) return NULL; seg1 = as1->segments; seg2 = as2->segments; /* If as2 is empty, only need to dupe as1's chain onto as2 */ if (seg2 == NULL) { as2->segments = assegment_dup_all (as1->segments); aspath_str_update (as2); return as2; } /* If as1 is empty AS, no prepending to do. */ if (seg1 == NULL) return as2; /* find the tail as1's segment chain. */ while (seg1 && seg1->next) seg1 = seg1->next; /* Delete any AS_CONFED_SEQUENCE segment from as2. */ if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE) as2 = aspath_delete_confed_seq (as2); /* Compare last segment type of as1 and first segment type of as2. */ if (seg1->type != seg2->type) return aspath_merge (as1, as2); if (seg1->type == AS_SEQUENCE) { /* We have two chains of segments, as1->segments and seg2, * and we have to attach them together, merging the attaching * segments together into one. * * 1. dupe as1->segments onto head of as2 * 2. merge seg2's asns onto last segment of this new chain * 3. attach chain after seg2 */ /* dupe as1 onto as2's head */ seg1 = as2->segments = assegment_dup_all (as1->segments); /* refind the tail of as2, reusing seg1 */ while (seg1 && seg1->next) seg1 = seg1->next; /* merge the old head, seg2, into tail, seg1 */ seg1 = assegment_append_asns (seg1, seg2->as, seg2->length); /* bypass the merged seg2, and attach any chain after it to * chain descending from as2's head */ seg1->next = seg2->next; /* seg2 is now referenceless and useless*/ assegment_free (seg2); /* we've now prepended as1's segment chain to as2, merging * the inbetween AS_SEQUENCE of seg2 in the process */ aspath_str_update (as2); return as2; } else { /* AS_SET merge code is needed at here. */ return aspath_merge (as1, as2); } /* XXX: Ermmm, what if as1 has multiple segments?? */ /* Not reached */ } /* Iterate over AS_PATH segments and wipe all occurences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter * version of aspath_dup(), which allocates memory to hold the new * data, not the original. The new AS path is returned. */ struct aspath * aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) { struct assegment * srcseg, * exclseg, * lastseg; struct aspath * newpath; newpath = aspath_new(); lastseg = NULL; for (srcseg = source->segments; srcseg; srcseg = srcseg->next) { unsigned i, y, newlen = 0, done = 0, skip_as; struct assegment * newseg; /* Find out, how much ASns are we going to pick from this segment. * We can't perform filtering right inline, because the size of * the new segment isn't known at the moment yet. */ for (i = 0; i < srcseg->length; i++) { skip_as = 0; for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) for (y = 0; y < exclseg->length; y++) if (srcseg->as[i] == exclseg->as[y]) { skip_as = 1; // There's no sense in testing the rest of exclusion list, bail out. break; } if (!skip_as) newlen++; } /* newlen is now the number of ASns to copy */ if (!newlen) continue; /* Actual copying. Allocate memory and iterate once more, performing filtering. */ newseg = assegment_new (srcseg->type, newlen); for (i = 0; i < srcseg->length; i++) { skip_as = 0; for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) for (y = 0; y < exclseg->length; y++) if (srcseg->as[i] == exclseg->as[y]) { skip_as = 1; break; } if (skip_as) continue; newseg->as[done++] = srcseg->as[i]; } /* At his point newlen must be equal to done, and both must be positive. Append * the filtered segment to the gross result. */ if (!lastseg) newpath->segments = newseg; else lastseg->next = newseg; lastseg = newseg; } aspath_str_update (newpath); /* We are happy returning even an empty AS_PATH, because the administrator * might expect this very behaviour. There's a mean to avoid this, if necessary, * by having a match rule against certain AS_PATH regexps in the route-map index. */ aspath_free (source); return newpath; } /* Add specified AS to the leftmost of aspath. */ static struct aspath * aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; int i; if (assegment && assegment->type == type) { /* extend existing segment */ aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); } else { /* prepend with new segment */ struct assegment *newsegment = assegment_new (type, num); for (i = 0; i < num; i++) newsegment->as[i] = asno; /* insert potentially replacing empty segment */ if (assegment && assegment->length == 0) { newsegment->next = assegment->next; assegment_free (assegment); } else newsegment->next = assegment; aspath->segments = newsegment; } aspath_str_update (aspath); return aspath; } /* Add specified AS to the leftmost of aspath num times. */ struct aspath * aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num) { return aspath_add_asns (aspath, asno, AS_SEQUENCE, num); } /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and as2's leftmost AS is same return 1. */ int aspath_cmp_left (const struct aspath *aspath1, const struct aspath *aspath2) { const struct assegment *seg1; const struct assegment *seg2; if (!(aspath1 && aspath2)) return 0; seg1 = aspath1->segments; seg2 = aspath2->segments; /* find first non-confed segments for each */ while (seg1 && ((seg1->type == AS_CONFED_SEQUENCE) || (seg1->type == AS_CONFED_SET))) seg1 = seg1->next; while (seg2 && ((seg2->type == AS_CONFED_SEQUENCE) || (seg2->type == AS_CONFED_SET))) seg2 = seg2->next; /* Check as1's */ if (!(seg1 && seg2 && (seg1->type == AS_SEQUENCE) && (seg2->type == AS_SEQUENCE))) return 0; if (seg1->as[0] == seg2->as[0]) return 1; return 0; } /* Truncate an aspath after a number of hops, and put the hops remaining * at the front of another aspath. Needed for AS4 compat. * * Returned aspath is a /new/ aspath, which should either by free'd or * interned by the caller, as desired. */ struct aspath * aspath_reconcile_as4 ( struct aspath *aspath, struct aspath *as4path) { struct assegment *seg, *newseg, *prevseg = NULL; struct aspath *newpath = NULL, *mergedpath; int hops, cpasns = 0; if (!aspath) return NULL; seg = aspath->segments; /* CONFEDs should get reconciled too.. */ hops = (aspath_count_hops (aspath) + aspath_count_confeds (aspath)) - aspath_count_hops (as4path); if (hops < 0) { if (BGP_DEBUG (as4, AS4)) zlog_warn ("[AS4] Fewer hops in AS_PATH than NEW_AS_PATH"); /* Something's gone wrong. The RFC says we should now ignore AS4_PATH, * which is daft behaviour - it contains vital loop-detection * information which must have been removed from AS_PATH. */ hops = aspath_count_hops (aspath); } if (!hops) return aspath_dup (as4path); if ( BGP_DEBUG(as4, AS4)) zlog_debug("[AS4] got AS_PATH %s and AS4_PATH %s synthesizing now", aspath->str, as4path->str); while (seg && hops > 0) { switch (seg->type) { case AS_SET: case AS_CONFED_SET: hops--; cpasns = seg->length; break; case AS_CONFED_SEQUENCE: /* Should never split a confed-sequence, if hop-count * suggests we must then something's gone wrong somewhere. * * Most important goal is to preserve AS_PATHs prime function * as loop-detector, so we fudge the numbers so that the entire * confed-sequence is merged in. */ if (hops < seg->length) { if (BGP_DEBUG (as4, AS4)) zlog_debug ("[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls" " across 2/4 ASN boundary somewhere, broken.."); hops = seg->length; } case AS_SEQUENCE: cpasns = MIN(seg->length, hops); hops -= seg->length; } assert (cpasns <= seg->length); newseg = assegment_new (seg->type, 0); newseg = assegment_append_asns (newseg, seg->as, cpasns); if (!newpath) { newpath = aspath_new (); newpath->segments = newseg; } else prevseg->next = newseg; prevseg = newseg; seg = seg->next; } /* We may be able to join some segments here, and we must * do this because... we want normalised aspaths in out hash * and we do not want to stumble in aspath_put. */ mergedpath = aspath_merge (newpath, aspath_dup(as4path)); aspath_free (newpath); mergedpath->segments = assegment_normalise (mergedpath->segments); aspath_str_update (mergedpath); if ( BGP_DEBUG(as4, AS4)) zlog_debug ("[AS4] result of synthesizing is %s", mergedpath->str); return mergedpath; } /* Compare leftmost AS value for MED check. If as1's leftmost AS and as2's leftmost AS is same return 1. (confederation as-path only). */ int aspath_cmp_left_confed (const struct aspath *aspath1, const struct aspath *aspath2) { if (! (aspath1 && aspath2) ) return 0; if ( !(aspath1->segments && aspath2->segments) ) return 0; if ( (aspath1->segments->type != AS_CONFED_SEQUENCE) || (aspath2->segments->type != AS_CONFED_SEQUENCE) ) return 0; if (aspath1->segments->as[0] == aspath2->segments->as[0]) return 1; return 0; } /* Delete all leading AS_CONFED_SEQUENCE/SET segments from aspath. * See RFC3065, 6.1 c1 */ struct aspath * aspath_delete_confed_seq (struct aspath *aspath) { struct assegment *seg; if (!(aspath && aspath->segments)) return aspath; seg = aspath->segments; /* "if the first path segment of the AS_PATH is * of type AS_CONFED_SEQUENCE," */ if (aspath->segments->type != AS_CONFED_SEQUENCE) return aspath; /* "... that segment and any immediately following segments * of the type AS_CONFED_SET or AS_CONFED_SEQUENCE are removed * from the AS_PATH attribute," */ while (seg && (seg->type == AS_CONFED_SEQUENCE || seg->type == AS_CONFED_SET)) { aspath->segments = seg->next; assegment_free (seg); seg = aspath->segments; } aspath_str_update (aspath); return aspath; } /* Add new AS number to the leftmost part of the aspath as AS_CONFED_SEQUENCE. */ struct aspath* aspath_add_confed_seq (struct aspath *aspath, as_t asno) { return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ static void aspath_as_add (struct aspath *as, as_t asno) { struct assegment *seg = as->segments; if (!seg) return; /* Last segment search procedure. */ while (seg->next) seg = seg->next; assegment_append_asns (seg, &asno, 1); } /* Add new as segment to the as path. */ static void aspath_segment_add (struct aspath *as, int type) { struct assegment *seg = as->segments; struct assegment *new = assegment_new (type, 0); if (seg) { while (seg->next) seg = seg->next; seg->next = new; } else as->segments = new; } struct aspath * aspath_empty (void) { return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */ } struct aspath * aspath_empty_get (void) { struct aspath *aspath; aspath = aspath_new (); aspath_make_str_count (aspath); return aspath; } unsigned long aspath_count (void) { return ashash->count; } /* Theoretically, one as path can have: One BGP packet size should be less than 4096. One BGP attribute size should be less than 4096 - BGP header size. One BGP aspath size should be less than 4096 - BGP header size - BGP mandantry attribute size. */ /* AS path string lexical token enum. */ enum as_token { as_token_asval, as_token_set_start, as_token_set_end, as_token_confed_seq_start, as_token_confed_seq_end, as_token_confed_set_start, as_token_confed_set_end, as_token_unknown }; /* Return next token and point for string parse. */ static const char * aspath_gettoken (const char *buf, enum as_token *token, u_long *asno) { const char *p = buf; /* Skip seperators (space for sequences, ',' for sets). */ while (isspace ((int) *p) || *p == ',') p++; /* Check the end of the string and type specify characters (e.g. {}()). */ switch (*p) { case '\0': return NULL; case '{': *token = as_token_set_start; p++; return p; case '}': *token = as_token_set_end; p++; return p; case '(': *token = as_token_confed_seq_start; p++; return p; case ')': *token = as_token_confed_seq_end; p++; return p; case '[': *token = as_token_confed_set_start; p++; return p; case ']': *token = as_token_confed_set_end; p++; return p; } /* Check actual AS value. */ if (isdigit ((int) *p)) { as_t asval; *token = as_token_asval; asval = (*p - '0'); p++; while (isdigit ((int) *p)) { asval *= 10; asval += (*p - '0'); p++; } *asno = asval; return p; } /* There is no match then return unknown token. */ *token = as_token_unknown; return p++; } struct aspath * aspath_str2aspath (const char *str) { enum as_token token = as_token_unknown; u_short as_type; u_long asno = 0; struct aspath *aspath; int needtype; aspath = aspath_new (); /* We start default type as AS_SEQUENCE. */ as_type = AS_SEQUENCE; needtype = 1; while ((str = aspath_gettoken (str, &token, &asno)) != NULL) { switch (token) { case as_token_asval: if (needtype) { aspath_segment_add (aspath, as_type); needtype = 0; } aspath_as_add (aspath, asno); break; case as_token_set_start: as_type = AS_SET; aspath_segment_add (aspath, as_type); needtype = 0; break; case as_token_set_end: as_type = AS_SEQUENCE; needtype = 1; break; case as_token_confed_seq_start: as_type = AS_CONFED_SEQUENCE; aspath_segment_add (aspath, as_type); needtype = 0; break; case as_token_confed_seq_end: as_type = AS_SEQUENCE; needtype = 1; break; case as_token_confed_set_start: as_type = AS_CONFED_SET; aspath_segment_add (aspath, as_type); needtype = 0; break; case as_token_confed_set_end: as_type = AS_SEQUENCE; needtype = 1; break; case as_token_unknown: default: aspath_free (aspath); return NULL; } } aspath_make_str_count (aspath); return aspath; } /* Make hash value by raw aspath data. */ unsigned int aspath_key_make (void *p) { struct aspath *aspath = (struct aspath *) p; unsigned int key = 0; if (!aspath->str) aspath_str_update (aspath); key = jhash (aspath->str, aspath->str_len, 2334325); return key; } /* If two aspath have same value then return 1 else return 0 */ int aspath_cmp (const void *arg1, const void *arg2) { const struct assegment *seg1 = ((const struct aspath *)arg1)->segments; const struct assegment *seg2 = ((const struct aspath *)arg2)->segments; while (seg1 || seg2) { int i; if ((!seg1 && seg2) || (seg1 && !seg2)) return 0; if (seg1->type != seg2->type) return 0; if (seg1->length != seg2->length) return 0; for (i = 0; i < seg1->length; i++) if (seg1->as[i] != seg2->as[i]) return 0; seg1 = seg1->next; seg2 = seg2->next; } return 1; } /* AS path hash initialize. */ void aspath_init (void) { ashash = hash_create_size (32768, aspath_key_make, aspath_cmp); } void aspath_finish (void) { hash_free (ashash); ashash = NULL; if (snmp_stream) stream_free (snmp_stream); } /* return and as path value */ const char * aspath_print (struct aspath *as) { return (as ? as->str : NULL); } /* Printing functions */ /* Feed the AS_PATH to the vty; the suffix string follows it only in case * AS_PATH wasn't empty. */ void aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix) { assert (format); vty_out (vty, format, as->str); if (as->str_len && strlen (suffix)) vty_out (vty, "%s", suffix); } static void aspath_show_all_iterator (struct hash_backet *backet, struct vty *vty) { struct aspath *as; as = (struct aspath *) backet->data; vty_out (vty, "[%p:%u] (%ld) ", backet, backet->key, as->refcnt); vty_out (vty, "%s%s", as->str, VTY_NEWLINE); } /* Print all aspath and hash information. This function is used from `show ip bgp paths' command. */ void aspath_print_all_vty (struct vty *vty) { hash_iterate (ashash, (void (*) (struct hash_backet *, void *)) aspath_show_all_iterator, vty); } quagga-0.99.24.1/bgpd/bgp_fsm.c0000644000175000017500000010140112476520570012726 00000000000000/* BGP-4 Finite State Machine From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] Copyright (C) 1996, 97, 98 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "linklist.h" #include "prefix.h" #include "vty.h" #include "sockunion.h" #include "thread.h" #include "log.h" #include "stream.h" #include "memory.h" #include "plist.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ /* BGP FSM (finite state machine) has three types of functions. Type one is thread functions. Type two is event functions. Type three is FSM functions. Timer functions are set by bgp_timer_set function. */ /* BGP event function. */ int bgp_event (struct thread *); /* BGP thread functions. */ static int bgp_start_timer (struct thread *); static int bgp_connect_timer (struct thread *); static int bgp_holdtime_timer (struct thread *); static int bgp_keepalive_timer (struct thread *); /* BGP FSM functions. */ static int bgp_start (struct peer *); /* BGP start timer jitter. */ static int bgp_start_jitter (int time) { return ((rand () % (time + 1)) - (time / 2)); } /* Check if suppress start/restart of sessions to peer. */ #define BGP_PEER_START_SUPPRESSED(P) \ (CHECK_FLAG ((P)->flags, PEER_FLAG_SHUTDOWN) \ || CHECK_FLAG ((P)->sflags, PEER_STATUS_PREFIX_OVERFLOW)) /* Hook function called after bgp event is occered. And vty's neighbor command invoke this function after making neighbor structure. */ void bgp_timer_set (struct peer *peer) { int jitter = 0; switch (peer->status) { case Idle: /* First entry point of peer's finite state machine. In Idle status start timer is on unless peer is shutdown or peer is inactive. All other timer must be turned off */ if (BGP_PEER_START_SUPPRESSED (peer) || ! peer_active (peer)) { BGP_TIMER_OFF (peer->t_start); } else { jitter = bgp_start_jitter (peer->v_start); BGP_TIMER_ON (peer->t_start, bgp_start_timer, peer->v_start + jitter); } BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case Connect: /* After start timer is expired, the peer moves to Connnect status. Make sure start timer is off and connect timer is on. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case Active: /* Active is waiting connection from remote peer. And if connect timer is expired, change status to Connect. */ BGP_TIMER_OFF (peer->t_start); /* If peer is passive mode, do not set connect timer. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE) || CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { BGP_TIMER_OFF (peer->t_connect); } else { BGP_TIMER_ON (peer->t_connect, bgp_connect_timer, peer->v_connect); } BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case OpenSent: /* OpenSent status. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); if (peer->v_holdtime != 0) { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); } else { BGP_TIMER_OFF (peer->t_holdtime); } BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case OpenConfirm: /* OpenConfirm status. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); /* If the negotiated Hold Time value is zero, then the Hold Time timer and KeepAlive timers are not started. */ if (peer->v_holdtime == 0) { BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); } else { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); break; case Established: /* In Established status start and connect timer is turned off. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); /* Same as OpenConfirm, if holdtime is zero then both holdtime and keepalive must be turned off. */ if (peer->v_holdtime == 0) { BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); } else { BGP_TIMER_ON (peer->t_holdtime, bgp_holdtime_timer, peer->v_holdtime); BGP_TIMER_ON (peer->t_keepalive, bgp_keepalive_timer, peer->v_keepalive); } BGP_TIMER_OFF (peer->t_asorig); break; case Deleted: BGP_TIMER_OFF (peer->t_gr_restart); BGP_TIMER_OFF (peer->t_gr_stale); BGP_TIMER_OFF (peer->t_pmax_restart); case Clearing: BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); } } /* BGP start timer. This function set BGP_Start event to thread value and process event. */ static int bgp_start_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_start = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (start timer expire).", peer->host); THREAD_VAL (thread) = BGP_Start; bgp_event (thread); /* bgp_event unlocks peer */ return 0; } /* BGP connect retry timer. */ static int bgp_connect_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_connect = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (connect timer expire)", peer->host); THREAD_VAL (thread) = ConnectRetry_timer_expired; bgp_event (thread); /* bgp_event unlocks peer */ return 0; } /* BGP holdtime timer. */ static int bgp_holdtime_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_holdtime = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (holdtime timer expire)", peer->host); THREAD_VAL (thread) = Hold_Timer_expired; bgp_event (thread); /* bgp_event unlocks peer */ return 0; } /* BGP keepalive fire ! */ static int bgp_keepalive_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_keepalive = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (keepalive timer expire)", peer->host); THREAD_VAL (thread) = KeepAlive_timer_expired; bgp_event (thread); /* bgp_event unlocks peer */ return 0; } static int bgp_routeadv_timer (struct thread *thread) { struct peer *peer; peer = THREAD_ARG (thread); peer->t_routeadv = NULL; if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] Timer (routeadv timer expire)", peer->host); peer->synctime = bgp_clock (); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, peer->v_routeadv); return 0; } /* BGP Peer Down Cause */ const char *peer_down_str[] = { "", "Router ID changed", "Remote AS changed", "Local AS change", "Cluster ID changed", "Confederation identifier changed", "Confederation peer changed", "RR client config change", "RS client config change", "Update source change", "Address family activated", "Admin. shutdown", "User reset", "BGP Notification received", "BGP Notification send", "Peer closed the session", "Neighbor deleted", "Peer-group add member", "Peer-group delete member", "Capability changed", "Passive config change", "Multihop config change", "NSF peer closed the session" }; static int bgp_graceful_restart_timer_expire (struct thread *thread) { struct peer *peer; afi_t afi; safi_t safi; peer = THREAD_ARG (thread); peer->t_gr_restart = NULL; /* NSF delete stale route */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) { zlog_debug ("%s graceful restart timer expired", peer->host); zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } bgp_timer_set (peer); return 0; } static int bgp_graceful_stale_timer_expire (struct thread *thread) { struct peer *peer; afi_t afi; safi_t safi; peer = THREAD_ARG (thread); peer->t_gr_stale = NULL; if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer expired", peer->host); /* NSF delete stale route */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); return 0; } /* Called after event occured, this function change status and reset read/write and timer thread. */ void bgp_fsm_change_status (struct peer *peer, int status) { bgp_dump_state (peer, peer->status, status); /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ if (status >= Clearing) bgp_clear_route_all (peer); /* Preserve old status and change into new status. */ peer->ostatus = peer->status; peer->status = status; if (BGP_DEBUG (normal, NORMAL)) zlog_debug ("%s went from %s to %s", peer->host, LOOKUP (bgp_status_msg, peer->ostatus), LOOKUP (bgp_status_msg, peer->status)); } /* Flush the event queue and ensure the peer is shut down */ static int bgp_clearing_completed (struct peer *peer) { int rc = bgp_stop(peer); BGP_EVENT_FLUSH (peer); return rc; } /* Administrative BGP peer stop event. */ /* May be called multiple times for the same peer */ int bgp_stop (struct peer *peer) { afi_t afi; safi_t safi; char orf_name[BUFSIZ]; /* Can't do this in Clearing; events are used for state transitions */ if (peer->status != Clearing) { /* Delete all existing events of the peer */ BGP_EVENT_FLUSH (peer); } /* Increment Dropped count. */ if (peer->status == Established) { peer->dropped++; /* bgp log-neighbor-changes of neighbor Down */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%ADJCHANGE: neighbor %s Down %s", peer->host, peer_down_str [(int) peer->last_reset]); /* graceful restart */ if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) { if (BGP_DEBUG (events, EVENTS)) { zlog_debug ("%s graceful restart timer started for %d sec", peer->host, peer->v_gr_restart); zlog_debug ("%s graceful restart stalepath timer started for %d sec", peer->host, peer->bgp->stalepath_time); } BGP_TIMER_ON (peer->t_gr_restart, bgp_graceful_restart_timer_expire, peer->v_gr_restart); BGP_TIMER_ON (peer->t_gr_stale, bgp_graceful_stale_timer_expire, peer->bgp->stalepath_time); } else { UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; } /* set last reset time */ peer->resettime = peer->uptime = bgp_clock (); #ifdef HAVE_SNMP bgpTrapBackwardTransition (peer); #endif /* HAVE_SNMP */ /* Reset peer synctime */ peer->synctime = 0; } /* Stop read and write threads when exists. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Stop all timers. */ BGP_TIMER_OFF (peer->t_start); BGP_TIMER_OFF (peer->t_connect); BGP_TIMER_OFF (peer->t_holdtime); BGP_TIMER_OFF (peer->t_keepalive); BGP_TIMER_OFF (peer->t_asorig); BGP_TIMER_OFF (peer->t_routeadv); /* Stream reset. */ peer->packet_size = 0; /* Clear input and output buffer. */ if (peer->ibuf) stream_reset (peer->ibuf); if (peer->work) stream_reset (peer->work); if (peer->obuf) stream_fifo_clean (peer->obuf); /* Close of file descriptor. */ if (peer->fd >= 0) { close (peer->fd); peer->fd = -1; } for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) { /* Reset all negotiated variables */ peer->afc_nego[afi][safi] = 0; peer->afc_adv[afi][safi] = 0; peer->afc_recv[afi][safi] = 0; /* peer address family capability flags*/ peer->af_cap[afi][safi] = 0; /* peer address family status flags*/ peer->af_sflags[afi][safi] = 0; /* Received ORF prefix-filter */ peer->orf_plist[afi][safi] = NULL; /* ORF received prefix-filter pnt */ sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); } /* Reset keepalive and holdtime */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) { peer->v_keepalive = peer->keepalive; peer->v_holdtime = peer->holdtime; } else { peer->v_keepalive = peer->bgp->default_keepalive; peer->v_holdtime = peer->bgp->default_holdtime; } peer->update_time = 0; /* Until we are sure that there is no problem about prefix count this should be commented out.*/ #if 0 /* Reset prefix count */ peer->pcount[AFI_IP][SAFI_UNICAST] = 0; peer->pcount[AFI_IP][SAFI_MULTICAST] = 0; peer->pcount[AFI_IP][SAFI_MPLS_VPN] = 0; peer->pcount[AFI_IP6][SAFI_UNICAST] = 0; peer->pcount[AFI_IP6][SAFI_MULTICAST] = 0; #endif /* 0 */ return 0; } /* BGP peer is stoped by the error. */ static int bgp_stop_with_error (struct peer *peer) { /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); bgp_stop (peer); return 0; } /* something went wrong, send notify and tear down */ static int bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) { /* Send notify to remote peer */ bgp_notify_send (peer, code, sub_code); /* Sweep if it is temporary peer. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { zlog_info ("%s [Event] Accepting BGP peer is deleted", peer->host); peer_delete (peer); return -1; } /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; /* bgp_stop needs to be invoked while in Established state */ bgp_stop(peer); return 0; } /* TCP connection open. Next we send open message to remote peer. And add read thread for reading open message. */ static int bgp_connect_success (struct peer *peer) { if (peer->fd < 0) { zlog_err ("bgp_connect_success peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_getsockname (peer); if (BGP_DEBUG (normal, NORMAL)) { char buf1[SU_ADDRSTRLEN]; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) zlog_debug ("%s open active, local address %s", peer->host, sockunion2str (peer->su_local, buf1, SU_ADDRSTRLEN)); else zlog_debug ("%s passive open", peer->host); } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_open_send (peer); return 0; } /* TCP connect fail */ static int bgp_connect_fail (struct peer *peer) { bgp_stop (peer); return 0; } /* This function is the first starting point of all BGP connection. It try to connect to remote peer with non-blocking IO. */ int bgp_start (struct peer *peer) { int status; if (BGP_PEER_START_SUPPRESSED (peer)) { if (BGP_DEBUG (fsm, FSM)) plog_err (peer->log, "%s [FSM] Trying to start suppressed peer" " - this is never supposed to happen!", peer->host); return -1; } /* Scrub some information that might be left over from a previous, * session */ /* Connection information. */ if (peer->su_local) { sockunion_free (peer->su_local); peer->su_local = NULL; } if (peer->su_remote) { sockunion_free (peer->su_remote); peer->su_remote = NULL; } /* Clear remote router-id. */ peer->remote_id.s_addr = 0; /* Clear peer capability flag. */ peer->cap = 0; /* If the peer is passive mode, force to move to Active mode. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) { BGP_EVENT_ADD (peer, TCP_connection_open_failed); return 0; } status = bgp_connect (peer); switch (status) { case connect_error: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect error", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open_failed); break; case connect_success: if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Connect immediately success", peer->host); BGP_EVENT_ADD (peer, TCP_connection_open); break; case connect_in_progress: /* To check nonblocking connect, we wait until socket is readable or writable. */ if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Non blocking connect waiting result", peer->host); if (peer->fd < 0) { zlog_err ("bgp_start peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); break; } return 0; } /* Connect retry timer is expired when the peer status is Connect. */ static int bgp_reconnect (struct peer *peer) { bgp_stop (peer); bgp_start (peer); return 0; } static int bgp_fsm_open (struct peer *peer) { /* Send keepalive and make keepalive timer */ bgp_keepalive_send (peer); /* Reset holdtimer value. */ BGP_TIMER_OFF (peer->t_holdtime); return 0; } /* Keepalive send to peer. */ static int bgp_fsm_keepalive_expire (struct peer *peer) { bgp_keepalive_send (peer); return 0; } /* FSM error, unexpected event. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_event_error (struct peer *peer) { plog_err (peer->log, "%s [FSM] unexpected packet received in state %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); return bgp_stop_with_notify (peer, BGP_NOTIFY_FSM_ERR, 0); } /* Hold timer expire. This is error of BGP connection. So cut the peer and change to Idle status. */ static int bgp_fsm_holdtime_expire (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) plog_debug (peer->log, "%s [FSM] Hold timer expire", peer->host); return bgp_stop_with_notify (peer, BGP_NOTIFY_HOLD_ERR, 0); } /* Status goes to Established. Send keepalive packet then make first update information. */ static int bgp_establish (struct peer *peer) { struct bgp_notify *notify; afi_t afi; safi_t safi; int nsf_af_count = 0; /* Reset capability open status flag. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Clear last notification data. */ notify = &peer->notify; if (notify->data) XFREE (MTYPE_TMP, notify->data); memset (notify, 0, sizeof (struct bgp_notify)); /* Clear start timer value to default. */ peer->v_start = BGP_INIT_START_TIMER; /* Increment established count. */ peer->established++; bgp_fsm_change_status (peer, Established); /* bgp log-neighbor-changes of neighbor Up */ if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host); /* graceful restart */ UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) { if (peer->afc_nego[afi][safi] && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV) && CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV)) { if (peer->nsf[afi][safi] && ! CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_PRESERVE_RCV)) bgp_clear_stale_route (peer, afi, safi); peer->nsf[afi][safi] = 1; nsf_af_count++; } else { if (peer->nsf[afi][safi]) bgp_clear_stale_route (peer, afi, safi); peer->nsf[afi][safi] = 0; } } if (nsf_af_count) SET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); else { UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } } if (peer->t_gr_restart) { BGP_TIMER_OFF (peer->t_gr_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart timer stopped", peer->host); } #ifdef HAVE_SNMP bgpTrapEstablished (peer); #endif /* HAVE_SNMP */ /* Reset uptime, send keepalive, send current table. */ peer->uptime = bgp_clock (); /* Send route-refresh when ORF is enabled */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)) { if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX, REFRESH_IMMEDIATE, 0); else if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) bgp_route_refresh_send (peer, afi, safi, ORF_TYPE_PREFIX_OLD, REFRESH_IMMEDIATE, 0); } if (peer->v_keepalive) bgp_keepalive_send (peer); /* First update is deferred until ORF or ROUTE-REFRESH is received */ for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)) if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV) || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); bgp_announce_route_all (peer); BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 1); return 0; } /* Keepalive packet is received. */ static int bgp_fsm_keepalive (struct peer *peer) { /* peer count update */ peer->keepalive_in++; BGP_TIMER_OFF (peer->t_holdtime); return 0; } /* Update packet is received. */ static int bgp_fsm_update (struct peer *peer) { BGP_TIMER_OFF (peer->t_holdtime); return 0; } /* This is empty event. */ static int bgp_ignore (struct peer *peer) { if (BGP_DEBUG (fsm, FSM)) zlog (peer->log, LOG_DEBUG, "%s [FSM] bgp_ignore called", peer->host); return 0; } /* Finite State Machine structure */ static const struct { int (*func) (struct peer *); int next_state; } FSM [BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = { { /* Idle state: In Idle state, all events other than BGP_Start is ignored. With BGP_Start event, finite state machine calls bgp_start(). */ {bgp_start, Connect}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* TCP_connection_open */ {bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_ignore, Idle}, /* TCP_connection_open_failed */ {bgp_stop, Idle}, /* TCP_fatal_error */ {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ {bgp_ignore, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_ignore, Idle}, /* Receive_OPEN_message */ {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Connect */ {bgp_ignore, Connect}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_connect_success, OpenSent}, /* TCP_connection_open */ {bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_connect_fail, Active}, /* TCP_connection_open_failed */ {bgp_connect_fail, Idle}, /* TCP_fatal_error */ {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */ {bgp_ignore, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_ignore, Idle}, /* Receive_OPEN_message */ {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Active, */ {bgp_ignore, Active}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_connect_success, OpenSent}, /* TCP_connection_open */ {bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_ignore, Active}, /* TCP_connection_open_failed */ {bgp_ignore, Idle}, /* TCP_fatal_error */ {bgp_start, Connect}, /* ConnectRetry_timer_expired */ {bgp_ignore, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_ignore, Idle}, /* Receive_OPEN_message */ {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* OpenSent, */ {bgp_ignore, OpenSent}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Active}, /* TCP_connection_open */ {bgp_stop, Active}, /* TCP_connection_closed */ {bgp_stop, Active}, /* TCP_connection_open_failed */ {bgp_stop, Active}, /* TCP_fatal_error */ {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* OpenConfirm, */ {bgp_ignore, OpenConfirm}, /* BGP_Start */ {bgp_stop, Idle}, /* BGP_Stop */ {bgp_stop, Idle}, /* TCP_connection_open */ {bgp_stop, Idle}, /* TCP_connection_closed */ {bgp_stop, Idle}, /* TCP_connection_open_failed */ {bgp_stop, Idle}, /* TCP_fatal_error */ {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */ {bgp_ignore, Idle}, /* Receive_OPEN_message */ {bgp_establish, Established}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Idle}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Established, */ {bgp_ignore, Established}, /* BGP_Start */ {bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* TCP_connection_open */ {bgp_stop, Clearing}, /* TCP_connection_closed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ {bgp_fsm_keepalive_expire, Established}, /* KeepAlive_timer_expired */ {bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_fsm_keepalive, Established}, /* Receive_KEEPALIVE_message */ {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ {bgp_stop_with_error, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Idle}, /* Clearing_Completed */ }, { /* Clearing, */ {bgp_ignore, Clearing}, /* BGP_Start */ {bgp_stop, Clearing}, /* BGP_Stop */ {bgp_stop, Clearing}, /* TCP_connection_open */ {bgp_stop, Clearing}, /* TCP_connection_closed */ {bgp_stop, Clearing}, /* TCP_connection_open_failed */ {bgp_stop, Clearing}, /* TCP_fatal_error */ {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ {bgp_stop, Clearing}, /* Hold_Timer_expired */ {bgp_stop, Clearing}, /* KeepAlive_timer_expired */ {bgp_stop, Clearing}, /* Receive_OPEN_message */ {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ {bgp_stop, Clearing}, /* Receive_UPDATE_message */ {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ {bgp_clearing_completed, Idle}, /* Clearing_Completed */ }, { /* Deleted, */ {bgp_ignore, Deleted}, /* BGP_Start */ {bgp_ignore, Deleted}, /* BGP_Stop */ {bgp_ignore, Deleted}, /* TCP_connection_open */ {bgp_ignore, Deleted}, /* TCP_connection_closed */ {bgp_ignore, Deleted}, /* TCP_connection_open_failed */ {bgp_ignore, Deleted}, /* TCP_fatal_error */ {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */ {bgp_ignore, Deleted}, /* Hold_Timer_expired */ {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */ {bgp_ignore, Deleted}, /* Receive_OPEN_message */ {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */ {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ {bgp_ignore, Deleted}, /* Clearing_Completed */ }, }; static const char *bgp_event_str[] = { NULL, "BGP_Start", "BGP_Stop", "TCP_connection_open", "TCP_connection_closed", "TCP_connection_open_failed", "TCP_fatal_error", "ConnectRetry_timer_expired", "Hold_Timer_expired", "KeepAlive_timer_expired", "Receive_OPEN_message", "Receive_KEEPALIVE_message", "Receive_UPDATE_message", "Receive_NOTIFICATION_message", "Clearing_Completed", }; /* Execute event process. */ int bgp_event (struct thread *thread) { int ret = 0; int event; int next; struct peer *peer; peer = THREAD_ARG (thread); event = THREAD_VAL (thread); /* Logging this event. */ next = FSM [peer->status -1][event - 1].next_state; if (BGP_DEBUG (fsm, FSM) && peer->status != next) plog_debug (peer->log, "%s [FSM] %s (%s->%s)", peer->host, bgp_event_str[event], LOOKUP (bgp_status_msg, peer->status), LOOKUP (bgp_status_msg, next)); /* Call function. */ if (FSM [peer->status -1][event - 1].func) ret = (*(FSM [peer->status - 1][event - 1].func))(peer); /* When function do not want proceed next job return -1. */ if (ret >= 0) { /* If status is changed. */ if (next != peer->status) bgp_fsm_change_status (peer, next); /* Make sure timer is set. */ bgp_timer_set (peer); } return ret; } quagga-0.99.24.1/bgpd/bgpd.c0000644000175000017500000043766112476520570012251 00000000000000/* BGP-4, BGP-4+ daemon program Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "thread.h" #include "buffer.h" #include "stream.h" #include "command.h" #include "sockunion.h" #include "network.h" #include "memory.h" #include "filter.h" #include "routemap.h" #include "str.h" #include "log.h" #include "plist.h" #include "linklist.h" #include "workqueue.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_community.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_regex.h" #include "bgpd/bgp_clist.h" #include "bgpd/bgp_fsm.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_filter.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_damp.h" #include "bgpd/bgp_mplsvpn.h" #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_network.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #ifdef HAVE_SNMP #include "bgpd/bgp_snmp.h" #endif /* HAVE_SNMP */ /* BGP process wide configuration. */ static struct bgp_master bgp_master; extern struct in_addr router_id_zebra; /* BGP process wide configuration pointer to export. */ struct bgp_master *bm; /* BGP community-list. */ struct community_list_handler *bgp_clist; /* BGP global flag manipulation. */ int bgp_option_set (int flag) { switch (flag) { case BGP_OPT_NO_FIB: case BGP_OPT_MULTIPLE_INSTANCE: case BGP_OPT_CONFIG_CISCO: case BGP_OPT_NO_LISTEN: SET_FLAG (bm->options, flag); break; default: return BGP_ERR_INVALID_FLAG; } return 0; } int bgp_option_unset (int flag) { switch (flag) { case BGP_OPT_MULTIPLE_INSTANCE: if (listcount (bm->bgp) > 1) return BGP_ERR_MULTIPLE_INSTANCE_USED; /* Fall through. */ case BGP_OPT_NO_FIB: case BGP_OPT_CONFIG_CISCO: UNSET_FLAG (bm->options, flag); break; default: return BGP_ERR_INVALID_FLAG; } return 0; } int bgp_option_check (int flag) { return CHECK_FLAG (bm->options, flag); } /* BGP flag manipulation. */ int bgp_flag_set (struct bgp *bgp, int flag) { SET_FLAG (bgp->flags, flag); return 0; } int bgp_flag_unset (struct bgp *bgp, int flag) { UNSET_FLAG (bgp->flags, flag); return 0; } int bgp_flag_check (struct bgp *bgp, int flag) { return CHECK_FLAG (bgp->flags, flag); } /* Internal function to set BGP structure configureation flag. */ static void bgp_config_set (struct bgp *bgp, int config) { SET_FLAG (bgp->config, config); } static void bgp_config_unset (struct bgp *bgp, int config) { UNSET_FLAG (bgp->config, config); } static int bgp_config_check (struct bgp *bgp, int config) { return CHECK_FLAG (bgp->config, config); } /* Set BGP router identifier. */ int bgp_router_id_set (struct bgp *bgp, struct in_addr *id) { struct peer *peer; struct listnode *node, *nnode; if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID) && IPV4_ADDR_SAME (&bgp->router_id, id)) return 0; IPV4_ADDR_COPY (&bgp->router_id, id); bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID); /* Set all peer's local identifier with this value. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY (&peer->local_id, id); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } /* BGP's cluster-id control. */ int bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id) { struct peer *peer; struct listnode *node, *nnode; if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID) && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id)) return 0; IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id); bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID); /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort != BGP_PEER_IBGP) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } int bgp_cluster_id_unset (struct bgp *bgp) { struct peer *peer; struct listnode *node, *nnode; if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)) return 0; bgp->cluster_id.s_addr = 0; bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID); /* Clear all IBGP peer. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->sort != BGP_PEER_IBGP) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0; } /* time_t value that is monotonicly increasing * and uneffected by adjustments to system clock */ time_t bgp_clock (void) { struct timeval tv; quagga_gettime(QUAGGA_CLK_MONOTONIC, &tv); return tv.tv_sec; } /* BGP timer configuration. */ int bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime) { bgp->default_keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); bgp->default_holdtime = holdtime; return 0; } int bgp_timers_unset (struct bgp *bgp) { bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; return 0; } /* BGP confederation configuration. */ int bgp_confederation_id_set (struct bgp *bgp, as_t as) { struct peer *peer; struct listnode *node, *nnode; int already_confed; if (as == 0) return BGP_ERR_INVALID_AS; /* Remember - were we doing confederation before? */ already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION); bgp->confed_id = as; bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION); /* If we were doing confederation already, this is just an external AS change. Just Reset EBGP sessions, not CONFED sessions. If we were not doing confederation before, reset all EBGP sessions. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { /* We're looking for peers who's AS is not local or part of our confederation. */ if (already_confed) { if (peer_sort (peer) == BGP_PEER_EBGP) { peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } else { /* Not doign confederation before, so reset every non-local session */ if (peer_sort (peer) != BGP_PEER_IBGP) { /* Reset the local_as to be our EBGP one */ if (peer_sort (peer) == BGP_PEER_EBGP) peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } int bgp_confederation_id_unset (struct bgp *bgp) { struct peer *peer; struct listnode *node, *nnode; bgp->confed_id = 0; bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION); for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { /* We're looking for peers who's AS is not local */ if (peer_sort (peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } return 0; } /* Is an AS part of the confed or not? */ int bgp_confederation_peers_check (struct bgp *bgp, as_t as) { int i; if (! bgp) return 0; for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i] == as) return 1; return 0; } /* Add an AS to the confederation set. */ int bgp_confederation_peers_add (struct bgp *bgp, as_t as) { struct peer *peer; struct listnode *node, *nnode; if (! bgp) return BGP_ERR_INVALID_BGP; if (bgp->as == as) return BGP_ERR_INVALID_AS; if (bgp_confederation_peers_check (bgp, as)) return -1; if (bgp->confed_peers) bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, bgp->confed_peers, (bgp->confed_peers_cnt + 1) * sizeof (as_t)); else bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST, (bgp->confed_peers_cnt + 1) * sizeof (as_t)); bgp->confed_peers[bgp->confed_peers_cnt] = as; bgp->confed_peers_cnt++; if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as == as) { peer->local_as = bgp->as; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } /* Delete an AS from the confederation set. */ int bgp_confederation_peers_remove (struct bgp *bgp, as_t as) { int i; int j; struct peer *peer; struct listnode *node, *nnode; if (! bgp) return -1; if (! bgp_confederation_peers_check (bgp, as)) return -1; for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i] == as) for(j = i + 1; j < bgp->confed_peers_cnt; j++) bgp->confed_peers[j - 1] = bgp->confed_peers[j]; bgp->confed_peers_cnt--; if (bgp->confed_peers_cnt == 0) { if (bgp->confed_peers) XFREE (MTYPE_BGP_CONFED_LIST, bgp->confed_peers); bgp->confed_peers = NULL; } else bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, bgp->confed_peers, bgp->confed_peers_cnt * sizeof (as_t)); /* Now reset any peer who's remote AS has just been removed from the CONFED */ if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->as == as) { peer->local_as = bgp->confed_id; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } /* Local preference configuration. */ int bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref) { if (! bgp) return -1; bgp->default_local_pref = local_pref; return 0; } int bgp_default_local_preference_unset (struct bgp *bgp) { if (! bgp) return -1; bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; return 0; } /* If peer is RSERVER_CLIENT in at least one address family and is not member of a peer_group for that family, return 1. Used to check wether the peer is included in list bgp->rsclient. */ int peer_rsclient_active (struct peer *peer) { int i; int j; for (i=AFI_IP; i < AFI_MAX; i++) for (j=SAFI_UNICAST; j < SAFI_MAX; j++) if (CHECK_FLAG(peer->af_flags[i][j], PEER_FLAG_RSERVER_CLIENT) && ! peer->af_group[i][j]) return 1; return 0; } /* Peer comparison function for sorting. */ static int peer_cmp (struct peer *p1, struct peer *p2) { return sockunion_cmp (&p1->su, &p2->su); } int peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) { return CHECK_FLAG (peer->af_flags[afi][safi], flag); } /* Reset all address family specific configuration. */ static void peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi) { int i; struct bgp_filter *filter; char orf_name[BUFSIZ]; filter = &peer->filter[afi][safi]; /* Clear neighbor filter and route-map */ for (i = FILTER_IN; i < FILTER_MAX; i++) { if (filter->dlist[i].name) { free (filter->dlist[i].name); filter->dlist[i].name = NULL; } if (filter->plist[i].name) { free (filter->plist[i].name); filter->plist[i].name = NULL; } if (filter->aslist[i].name) { free (filter->aslist[i].name); filter->aslist[i].name = NULL; } } for (i = RMAP_IN; i < RMAP_MAX; i++) { if (filter->map[i].name) { free (filter->map[i].name); filter->map[i].name = NULL; } } /* Clear unsuppress map. */ if (filter->usmap.name) free (filter->usmap.name); filter->usmap.name = NULL; filter->usmap.map = NULL; /* Clear neighbor's all address family flags. */ peer->af_flags[afi][safi] = 0; /* Clear neighbor's all address family sflags. */ peer->af_sflags[afi][safi] = 0; /* Clear neighbor's all address family capabilities. */ peer->af_cap[afi][safi] = 0; /* Clear ORF info */ peer->orf_plist[afi][safi] = NULL; sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi); prefix_bgp_orf_remove_all (orf_name); /* Set default neighbor send-community. */ if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); } /* Clear neighbor default_originate_rmap */ if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; /* Clear neighbor maximum-prefix */ peer->pmax[afi][safi] = 0; peer->pmax_threshold[afi][safi] = MAXIMUM_PREFIX_THRESHOLD_DEFAULT; } /* peer global config reset */ static void peer_global_config_reset (struct peer *peer) { peer->weight = 0; peer->change_local_as = 0; peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? 255 : 1); if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; peer->flags = 0; peer->config = 0; peer->holdtime = 0; peer->keepalive = 0; peer->connect = 0; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; } /* Check peer's AS number and determines if this peer is IBGP or EBGP */ static bgp_peer_sort_t peer_calc_sort (struct peer *peer) { struct bgp *bgp; bgp = peer->bgp; /* Peer-group */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->as) return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP); else { struct peer *peer1; peer1 = listnode_head (peer->group->peer); if (peer1) return (peer1->local_as == peer1->as ? BGP_PEER_IBGP : BGP_PEER_EBGP); } return BGP_PEER_INTERNAL; } /* Normal peer */ if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) { if (peer->local_as == 0) return BGP_PEER_INTERNAL; if (peer->local_as == peer->as) { if (peer->local_as == bgp->confed_id) return BGP_PEER_EBGP; else return BGP_PEER_IBGP; } if (bgp_confederation_peers_check (bgp, peer->as)) return BGP_PEER_CONFED; return BGP_PEER_EBGP; } else { return (peer->local_as == 0 ? BGP_PEER_INTERNAL : peer->local_as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP); } } /* Calculate and cache the peer "sort" */ bgp_peer_sort_t peer_sort (struct peer *peer) { peer->sort = peer_calc_sort (peer); return peer->sort; } static void peer_free (struct peer *peer) { assert (peer->status == Deleted); bgp_unlock(peer->bgp); /* this /ought/ to have been done already through bgp_stop earlier, * but just to be sure.. */ bgp_timer_set (peer); BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); BGP_EVENT_FLUSH (peer); if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); /* Free allocated host character. */ if (peer->host) XFREE (MTYPE_BGP_PEER_HOST, peer->host); /* Update source configuration. */ if (peer->update_source) sockunion_free (peer->update_source); if (peer->update_if) XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); if (peer->clear_node_queue) work_queue_free (peer->clear_node_queue); bgp_sync_delete (peer); memset (peer, 0, sizeof (struct peer)); XFREE (MTYPE_BGP_PEER, peer); } /* increase reference count on a struct peer */ struct peer * peer_lock (struct peer *peer) { assert (peer && (peer->lock >= 0)); peer->lock++; return peer; } /* decrease reference count on a struct peer * struct peer is freed and NULL returned if last reference */ struct peer * peer_unlock (struct peer *peer) { assert (peer && (peer->lock > 0)); peer->lock--; if (peer->lock == 0) { #if 0 zlog_debug ("unlocked and freeing"); zlog_backtrace (LOG_DEBUG); #endif peer_free (peer); return NULL; } #if 0 if (peer->lock == 1) { zlog_debug ("unlocked to 1"); zlog_backtrace (LOG_DEBUG); } #endif return peer; } /* Allocate new peer object, implicitely locked. */ static struct peer * peer_new (struct bgp *bgp) { afi_t afi; safi_t safi; struct peer *peer; struct servent *sp; /* bgp argument is absolutely required */ assert (bgp); if (!bgp) return NULL; /* Allocate new peer. */ peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer)); /* Set default value. */ peer->fd = -1; peer->v_start = BGP_INIT_START_TIMER; peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; peer->v_asorig = BGP_DEFAULT_ASORIGINATE; peer->status = Idle; peer->ostatus = Idle; peer->weight = 0; peer->password = NULL; peer->bgp = bgp; peer = peer_lock (peer); /* initial reference */ bgp_lock (bgp); /* Set default flags. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (! bgp_option_check (BGP_OPT_CONFIG_CISCO)) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY); SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); } peer->orf_plist[afi][safi] = NULL; } SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN); /* Create buffers. */ peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE); peer->obuf = stream_fifo_new (); peer->work = stream_new (BGP_MAX_PACKET_SIZE); peer->scratch = stream_new (BGP_MAX_PACKET_SIZE); bgp_sync_init (peer); /* Get service port number. */ sp = getservbyname ("bgp", "tcp"); peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port); return peer; } /* Create new BGP peer. */ static struct peer * peer_create (union sockunion *su, struct bgp *bgp, as_t local_as, as_t remote_as, afi_t afi, safi_t safi) { int active; struct peer *peer; char buf[SU_ADDRSTRLEN]; peer = peer_new (bgp); peer->su = *su; peer->local_as = local_as; peer->as = remote_as; peer->local_id = bgp->router_id; peer->v_holdtime = bgp->default_holdtime; peer->v_keepalive = bgp->default_keepalive; if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); active = peer_active (peer); if (afi && safi) peer->afc[afi][safi] = 1; /* Last read and reset time set */ peer->readtime = peer->resettime = bgp_clock (); /* Default TTL set. */ peer->ttl = (peer->sort == BGP_PEER_IBGP) ? 255 : 1; /* Make peer's address string. */ sockunion2str (su, buf, SU_ADDRSTRLEN); peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf); /* Set up peer's events and timers. */ if (! active && peer_active (peer)) bgp_timer_set (peer); return peer; } /* Make accept BGP peer. Called from bgp_accept (). */ struct peer * peer_create_accept (struct bgp *bgp) { struct peer *peer; peer = peer_new (bgp); peer = peer_lock (peer); /* bgp peer list reference */ listnode_add_sort (bgp->peer, peer); return peer; } /* Change peer's AS number. */ static void peer_as_change (struct peer *peer, as_t as) { bgp_peer_sort_t type; /* Stop peer. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } type = peer_sort (peer); peer->as = as; if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION) && ! bgp_confederation_peers_check (peer->bgp, as) && peer->bgp->as != as) peer->local_as = peer->bgp->confed_id; else peer->local_as = peer->bgp->as; /* Advertisement-interval reset */ if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* TTL reset */ if (peer_sort (peer) == BGP_PEER_IBGP) peer->ttl = 255; else if (type == BGP_PEER_IBGP) peer->ttl = 1; /* reflector-client reset */ if (peer_sort (peer) != BGP_PEER_IBGP) { UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST], PEER_FLAG_REFLECTOR_CLIENT); } /* local-as reset */ if (peer_sort (peer) != BGP_PEER_EBGP) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as, afi_t afi, safi_t safi) { struct peer *peer; as_t local_as; peer = peer_lookup (bgp, su); if (peer) { /* When this peer is a member of peer-group. */ if (peer->group) { if (peer->group->conf->as) { /* Return peer group's AS number. */ *as = peer->group->conf->as; return BGP_ERR_PEER_GROUP_MEMBER; } if (peer_sort (peer->group->conf) == BGP_PEER_IBGP) { if (bgp->as != *as) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } } else { if (bgp->as == *as) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } } } /* Existing peer's AS number change. */ if (peer->as != *as) peer_as_change (peer, *as); } else { /* If the peer is not part of our confederation, and its not an iBGP peer then spoof the source AS */ if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION) && ! bgp_confederation_peers_check (bgp, *as) && bgp->as != *as) local_as = bgp->confed_id; else local_as = bgp->as; /* If this is IPv4 unicast configuration and "no bgp default ipv4-unicast" is specified. */ if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4) && afi == AFI_IP && safi == SAFI_UNICAST) peer_create (su, bgp, local_as, *as, 0, 0); else peer_create (su, bgp, local_as, *as, afi, safi); } return 0; } /* Activate the peer or peer group for specified AFI and SAFI. */ int peer_activate (struct peer *peer, afi_t afi, safi_t safi) { int active; if (peer->afc[afi][safi]) return 0; /* Activate the address family configuration. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) peer->afc[afi][safi] = 1; else { active = peer_active (peer); peer->afc[afi][safi] = 1; if (! active && peer_active (peer)) bgp_timer_set (peer); else { if (peer->status == Established) { if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; bgp_capability_send (peer, afi, safi, CAPABILITY_CODE_MP, CAPABILITY_ACTION_SET); if (peer->afc_recv[afi][safi]) { peer->afc_nego[afi][safi] = 1; bgp_announce_route (peer, afi, safi); } } else { peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } } } return 0; } int peer_deactivate (struct peer *peer, afi_t afi, safi_t safi) { struct peer_group *group; struct peer *peer1; struct listnode *node, *nnode; if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->af_group[afi][safi]) return BGP_ERR_PEER_GROUP_MEMBER_EXISTS; } } else { if (peer->af_group[afi][safi]) return BGP_ERR_PEER_BELONGS_TO_GROUP; } if (! peer->afc[afi][safi]) return 0; /* De-activate the address family configuration. */ peer->afc[afi][safi] = 0; peer_af_flag_reset (peer, afi, safi); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->status == Established) { if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; if (peer_active_nego (peer)) { bgp_capability_send (peer, afi, safi, CAPABILITY_CODE_MP, CAPABILITY_ACTION_UNSET); bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_NORMAL); peer->pcount[afi][safi] = 0; } else { peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } } return 0; } static void peer_nsf_stop (struct peer *peer) { afi_t afi; safi_t safi; UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT); UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE); for (afi = AFI_IP ; afi < AFI_MAX ; afi++) for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++) peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) { BGP_TIMER_OFF (peer->t_gr_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart timer stopped", peer->host); } if (peer->t_gr_stale) { BGP_TIMER_OFF (peer->t_gr_stale); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s graceful restart stalepath timer stopped", peer->host); } bgp_clear_route_all (peer); } /* Delete peer from confguration. * * The peer is moved to a dead-end "Deleted" neighbour-state, to allow * it to "cool off" and refcounts to hit 0, at which state it is freed. * * This function /should/ take care to be idempotent, to guard against * it being called multiple times through stray events that come in * that happen to result in this function being called again. That * said, getting here for a "Deleted" peer is a bug in the neighbour * FSM. */ int peer_delete (struct peer *peer) { int i; afi_t afi; safi_t safi; struct bgp *bgp; struct bgp_filter *filter; struct listnode *pn; assert (peer->status != Deleted); bgp = peer->bgp; if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) { if ((pn = listnode_lookup (peer->group->peer, peer))) { peer = peer_unlock (peer); /* group->peer list reference */ list_delete_node (peer->group->peer, pn); } peer->group = NULL; } /* Withdraw all information from routing table. We can not use * BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is * executed after peer structure is deleted. */ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_stop (peer); bgp_fsm_change_status (peer, Deleted); /* Password configuration */ if (peer->password) { XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) bgp_md5_set (peer); } bgp_timer_set (peer); /* stops all timers for Deleted */ /* Delete from all peer list. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && (pn = listnode_lookup (bgp->peer, peer))) { peer_unlock (peer); /* bgp peer list reference */ list_delete_node (bgp->peer, pn); } if (peer_rsclient_active (peer) && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* rsclient list reference */ list_delete_node (bgp->rsclient, pn); /* Clear our own rsclient ribs. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } /* Free RIB for any family in which peer is RSERVER_CLIENT, and is not member of a peer_group. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (peer->rib[afi][safi] && ! peer->af_group[afi][safi]) bgp_table_finish (&peer->rib[afi][safi]); /* Buffers. */ if (peer->ibuf) stream_free (peer->ibuf); if (peer->obuf) stream_fifo_free (peer->obuf); if (peer->work) stream_free (peer->work); if (peer->scratch) stream_free(peer->scratch); peer->obuf = NULL; peer->work = peer->scratch = peer->ibuf = NULL; /* Local and remote addresses. */ if (peer->su_local) sockunion_free (peer->su_local); if (peer->su_remote) sockunion_free (peer->su_remote); peer->su_local = peer->su_remote = NULL; /* Free filter related memory. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (i = FILTER_IN; i < FILTER_MAX; i++) { if (filter->dlist[i].name) free (filter->dlist[i].name); if (filter->plist[i].name) free (filter->plist[i].name); if (filter->aslist[i].name) free (filter->aslist[i].name); filter->dlist[i].name = NULL; filter->plist[i].name = NULL; filter->aslist[i].name = NULL; } for (i = RMAP_IN; i < RMAP_MAX; i++) { if (filter->map[i].name) free (filter->map[i].name); filter->map[i].name = NULL; } if (filter->usmap.name) free (filter->usmap.name); if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); filter->usmap.name = NULL; peer->default_rmap[afi][safi].name = NULL; } peer_unlock (peer); /* initial reference */ return 0; } static int peer_group_cmp (struct peer_group *g1, struct peer_group *g2) { return strcmp (g1->name, g2->name); } /* If peer is configured at least one address family return 1. */ static int peer_group_active (struct peer *peer) { if (peer->af_group[AFI_IP][SAFI_UNICAST] || peer->af_group[AFI_IP][SAFI_MULTICAST] || peer->af_group[AFI_IP][SAFI_MPLS_VPN] || peer->af_group[AFI_IP6][SAFI_UNICAST] || peer->af_group[AFI_IP6][SAFI_MULTICAST]) return 1; return 0; } /* Peer group cofiguration. */ static struct peer_group * peer_group_new (void) { return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP, sizeof (struct peer_group)); } static void peer_group_free (struct peer_group *group) { XFREE (MTYPE_PEER_GROUP, group); } struct peer_group * peer_group_lookup (struct bgp *bgp, const char *name) { struct peer_group *group; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { if (strcmp (group->name, name) == 0) return group; } return NULL; } struct peer_group * peer_group_get (struct bgp *bgp, const char *name) { struct peer_group *group; group = peer_group_lookup (bgp, name); if (group) return group; group = peer_group_new (); group->bgp = bgp; group->name = strdup (name); group->peer = list_new (); group->conf = peer_new (bgp); if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) group->conf->afc[AFI_IP][SAFI_UNICAST] = 1; group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; group->conf->ttl = 1; group->conf->gtsm_hops = 0; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER); UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT); group->conf->keepalive = 0; group->conf->holdtime = 0; group->conf->connect = 0; SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP); listnode_add_sort (bgp->group, group); return 0; } static void peer_group2peer_config_copy (struct peer_group *group, struct peer *peer, afi_t afi, safi_t safi) { int in = FILTER_IN; int out = FILTER_OUT; struct peer *conf; struct bgp_filter *pfilter; struct bgp_filter *gfilter; conf = group->conf; pfilter = &peer->filter[afi][safi]; gfilter = &conf->filter[afi][safi]; /* remote-as */ if (conf->as) peer->as = conf->as; /* remote-as */ if (conf->change_local_as) peer->change_local_as = conf->change_local_as; /* TTL */ peer->ttl = conf->ttl; /* GTSM hops */ peer->gtsm_hops = conf->gtsm_hops; /* Weight */ peer->weight = conf->weight; /* peer flags apply */ peer->flags = conf->flags; /* peer af_flags apply */ peer->af_flags[afi][safi] = conf->af_flags[afi][safi]; /* peer config apply */ peer->config = conf->config; /* peer timers apply */ peer->holdtime = conf->holdtime; peer->keepalive = conf->keepalive; peer->connect = conf->connect; if (CHECK_FLAG (conf->config, PEER_CONFIG_CONNECT)) peer->v_connect = conf->connect; else peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; /* advertisement-interval reset */ if (peer_sort (peer) == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* password apply */ if (conf->password && !peer->password) peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password); bgp_md5_set (peer); /* maximum-prefix */ peer->pmax[afi][safi] = conf->pmax[afi][safi]; peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi]; peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi]; /* allowas-in */ peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi]; /* route-server-client */ if (CHECK_FLAG(conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { /* Make peer's RIB point to group's RIB. */ peer->rib[afi][safi] = group->conf->rib[afi][safi]; /* Import policy. */ if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); if (gfilter->map[RMAP_IMPORT].name) { pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map = NULL; } /* Export policy. */ if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } } /* default-originate route-map */ if (conf->default_rmap[afi][safi].name) { if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = strdup (conf->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].map = conf->default_rmap[afi][safi].map; } /* update-source apply */ if (conf->update_source) { if (peer->update_source) sockunion_free (peer->update_source); if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } peer->update_source = sockunion_dup (conf->update_source); } else if (conf->update_if) { if (peer->update_if) XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, conf->update_if); } /* inbound filter apply */ if (gfilter->dlist[in].name && ! pfilter->dlist[in].name) { if (pfilter->dlist[in].name) free (pfilter->dlist[in].name); pfilter->dlist[in].name = strdup (gfilter->dlist[in].name); pfilter->dlist[in].alist = gfilter->dlist[in].alist; } if (gfilter->plist[in].name && ! pfilter->plist[in].name) { if (pfilter->plist[in].name) free (pfilter->plist[in].name); pfilter->plist[in].name = strdup (gfilter->plist[in].name); pfilter->plist[in].plist = gfilter->plist[in].plist; } if (gfilter->aslist[in].name && ! pfilter->aslist[in].name) { if (pfilter->aslist[in].name) free (pfilter->aslist[in].name); pfilter->aslist[in].name = strdup (gfilter->aslist[in].name); pfilter->aslist[in].aslist = gfilter->aslist[in].aslist; } if (gfilter->map[RMAP_IN].name && ! pfilter->map[RMAP_IN].name) { if (pfilter->map[RMAP_IN].name) free (pfilter->map[RMAP_IN].name); pfilter->map[RMAP_IN].name = strdup (gfilter->map[RMAP_IN].name); pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map; } /* outbound filter apply */ if (gfilter->dlist[out].name) { if (pfilter->dlist[out].name) free (pfilter->dlist[out].name); pfilter->dlist[out].name = strdup (gfilter->dlist[out].name); pfilter->dlist[out].alist = gfilter->dlist[out].alist; } else { if (pfilter->dlist[out].name) free (pfilter->dlist[out].name); pfilter->dlist[out].name = NULL; pfilter->dlist[out].alist = NULL; } if (gfilter->plist[out].name) { if (pfilter->plist[out].name) free (pfilter->plist[out].name); pfilter->plist[out].name = strdup (gfilter->plist[out].name); pfilter->plist[out].plist = gfilter->plist[out].plist; } else { if (pfilter->plist[out].name) free (pfilter->plist[out].name); pfilter->plist[out].name = NULL; pfilter->plist[out].plist = NULL; } if (gfilter->aslist[out].name) { if (pfilter->aslist[out].name) free (pfilter->aslist[out].name); pfilter->aslist[out].name = strdup (gfilter->aslist[out].name); pfilter->aslist[out].aslist = gfilter->aslist[out].aslist; } else { if (pfilter->aslist[out].name) free (pfilter->aslist[out].name); pfilter->aslist[out].name = NULL; pfilter->aslist[out].aslist = NULL; } if (gfilter->map[RMAP_OUT].name) { if (pfilter->map[RMAP_OUT].name) free (pfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].name = strdup (gfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map; } else { if (pfilter->map[RMAP_OUT].name) free (pfilter->map[RMAP_OUT].name); pfilter->map[RMAP_OUT].name = NULL; pfilter->map[RMAP_OUT].map = NULL; } /* RS-client's import/export route-maps. */ if (gfilter->map[RMAP_IMPORT].name) { if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].name = strdup (gfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].map = gfilter->map[RMAP_IMPORT].map; } else { if (pfilter->map[RMAP_IMPORT].name) free (pfilter->map[RMAP_IMPORT].name); pfilter->map[RMAP_IMPORT].name = NULL; pfilter->map[RMAP_IMPORT].map = NULL; } if (gfilter->map[RMAP_EXPORT].name && ! pfilter->map[RMAP_EXPORT].name) { if (pfilter->map[RMAP_EXPORT].name) free (pfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].name = strdup (gfilter->map[RMAP_EXPORT].name); pfilter->map[RMAP_EXPORT].map = gfilter->map[RMAP_EXPORT].map; } if (gfilter->usmap.name) { if (pfilter->usmap.name) free (pfilter->usmap.name); pfilter->usmap.name = strdup (gfilter->usmap.name); pfilter->usmap.map = gfilter->usmap.map; } else { if (pfilter->usmap.name) free (pfilter->usmap.name); pfilter->usmap.name = NULL; pfilter->usmap.map = NULL; } } /* Peer group's remote AS configuration. */ int peer_group_remote_as (struct bgp *bgp, const char *group_name, as_t *as) { struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; group = peer_group_lookup (bgp, group_name); if (! group) return -1; if (group->conf->as == *as) return 0; /* When we setup peer-group AS number all peer group member's AS number must be updated to same number. */ peer_as_change (group->conf, *as); for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->as != *as) peer_as_change (peer, *as); } return 0; } int peer_group_delete (struct peer_group *group) { struct bgp *bgp; struct peer *peer; struct listnode *node, *nnode; bgp = group->bgp; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->group = NULL; peer_delete (peer); } list_delete (group->peer); free (group->name); group->name = NULL; group->conf->group = NULL; peer_delete (group->conf); /* Delete from all peer_group list. */ listnode_delete (bgp->group, group); peer_group_free (group); return 0; } int peer_group_remote_as_delete (struct peer_group *group) { struct peer *peer; struct listnode *node, *nnode; if (! group->conf->as) return 0; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->group = NULL; peer_delete (peer); } list_delete_all_node (group->peer); group->conf->as = 0; return 0; } /* Bind specified peer to peer group. */ int peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer_group *group, afi_t afi, safi_t safi, as_t *as) { struct peer *peer; int first_member = 0; /* Check peer group's address family. */ if (! group->conf->afc[afi][safi]) return BGP_ERR_PEER_GROUP_AF_UNCONFIGURED; /* Lookup the peer. */ peer = peer_lookup (bgp, su); /* Create a new peer. */ if (! peer) { if (! group->conf->as) return BGP_ERR_PEER_GROUP_NO_REMOTE_AS; peer = peer_create (su, bgp, bgp->as, group->conf->as, afi, safi); peer->group = group; peer->af_group[afi][safi] = 1; peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); peer_group2peer_config_copy (group, peer, afi, safi); return 0; } /* When the peer already belongs to peer group, check the consistency. */ if (peer->af_group[afi][safi]) { if (strcmp (peer->group->name, group->name) != 0) return BGP_ERR_PEER_GROUP_CANT_CHANGE; return 0; } /* Check current peer group configuration. */ if (peer_group_active (peer) && strcmp (peer->group->name, group->name) != 0) return BGP_ERR_PEER_GROUP_MISMATCH; if (! group->conf->as) { if (peer_sort (group->conf) != BGP_PEER_INTERNAL && peer_sort (group->conf) != peer_sort (peer)) { if (as) *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } if (peer_sort (group->conf) == BGP_PEER_INTERNAL) first_member = 1; } peer->af_group[afi][safi] = 1; peer->afc[afi][safi] = 1; if (! peer->group) { peer->group = group; peer = peer_lock (peer); /* group->peer list reference */ listnode_add (group->peer, peer); } else assert (group && peer->group == group); if (first_member) { /* Advertisement-interval reset */ if (peer_sort (group->conf) == BGP_PEER_IBGP) group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; /* ebgp-multihop reset */ if (peer_sort (group->conf) == BGP_PEER_IBGP) group->conf->ttl = 255; /* local-as reset */ if (peer_sort (group->conf) != BGP_PEER_EBGP) { group->conf->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); } } if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) { struct listnode *pn; /* If it's not configured as RSERVER_CLIENT in any other address family, without being member of a peer_group, remove it from list bgp->rsclient.*/ if (! peer_rsclient_active (peer) && (pn = listnode_lookup (bgp->rsclient, peer))) { peer_unlock (peer); /* peer rsclient reference */ list_delete_node (bgp->rsclient, pn); /* Clear our own rsclient rib for this afi/safi. */ bgp_clear_route (peer, afi, safi, BGP_CLEAR_ROUTE_MY_RSCLIENT); } bgp_table_finish (&peer->rib[afi][safi]); /* Import policy. */ if (peer->filter[afi][safi].map[RMAP_IMPORT].name) { free (peer->filter[afi][safi].map[RMAP_IMPORT].name); peer->filter[afi][safi].map[RMAP_IMPORT].name = NULL; peer->filter[afi][safi].map[RMAP_IMPORT].map = NULL; } /* Export policy. */ if (! CHECK_FLAG(group->conf->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && peer->filter[afi][safi].map[RMAP_EXPORT].name) { free (peer->filter[afi][safi].map[RMAP_EXPORT].name); peer->filter[afi][safi].map[RMAP_EXPORT].name = NULL; peer->filter[afi][safi].map[RMAP_EXPORT].map = NULL; } } peer_group2peer_config_copy (group, peer, afi, safi); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_BIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } int peer_group_unbind (struct bgp *bgp, struct peer *peer, struct peer_group *group, afi_t afi, safi_t safi) { if (! peer->af_group[afi][safi]) return 0; if (group != peer->group) return BGP_ERR_PEER_GROUP_MISMATCH; peer->af_group[afi][safi] = 0; peer->afc[afi][safi] = 0; peer_af_flag_reset (peer, afi, safi); if (peer->rib[afi][safi]) peer->rib[afi][safi] = NULL; if (! peer_group_active (peer)) { assert (listnode_lookup (group->peer, peer)); peer_unlock (peer); /* peer group list reference */ listnode_delete (group->peer, peer); peer->group = NULL; if (group->conf->as) { peer_delete (peer); return 0; } peer_global_config_reset (peer); } if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_RMAP_UNBIND; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } static int bgp_startup_timer_expire (struct thread *thread) { struct bgp *bgp; bgp = THREAD_ARG (thread); bgp->t_startup = NULL; return 0; } /* BGP instance creation by `router bgp' commands. */ static struct bgp * bgp_create (as_t *as, const char *name) { struct bgp *bgp; afi_t afi; safi_t safi; if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL) return NULL; bgp_lock (bgp); bgp->peer_self = peer_new (bgp); bgp->peer_self->host = XSTRDUP (MTYPE_BGP_PEER_HOST, "Static announcement"); bgp->peer = list_new (); bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; bgp->group = list_new (); bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; bgp->rsclient = list_new (); bgp->rsclient->cmp = (int (*)(void*, void*)) peer_cmp; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { bgp->route[afi][safi] = bgp_table_init (afi, safi); bgp->aggregate[afi][safi] = bgp_table_init (afi, safi); bgp->rib[afi][safi] = bgp_table_init (afi, safi); bgp->maxpaths[afi][safi].maxpaths_ebgp = BGP_DEFAULT_MAXPATHS; bgp->maxpaths[afi][safi].maxpaths_ibgp = BGP_DEFAULT_MAXPATHS; } bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->restart_time = BGP_DEFAULT_RESTART_TIME; bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; bgp->as = *as; if (name) bgp->name = strdup (name); THREAD_TIMER_ON (master, bgp->t_startup, bgp_startup_timer_expire, bgp, bgp->restart_time); return bgp; } /* Return first entry of BGP. */ struct bgp * bgp_get_default (void) { if (bm->bgp->head) return (listgetdata (listhead (bm->bgp))); return NULL; } /* Lookup BGP entry. */ struct bgp * bgp_lookup (as_t as, const char *name) { struct bgp *bgp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) if (bgp->as == as && ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp (bgp->name, name) == 0))) return bgp; return NULL; } /* Lookup BGP structure by view name. */ struct bgp * bgp_lookup_by_name (const char *name) { struct bgp *bgp; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) if ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp (bgp->name, name) == 0)) return bgp; return NULL; } /* Called from VTY commands. */ int bgp_get (struct bgp **bgp_val, as_t *as, const char *name) { struct bgp *bgp; /* Multiple instance check. */ if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) { if (name) bgp = bgp_lookup_by_name (name); else bgp = bgp_get_default (); /* Already exists. */ if (bgp) { if (bgp->as != *as) { *as = bgp->as; return BGP_ERR_INSTANCE_MISMATCH; } *bgp_val = bgp; return 0; } } else { /* BGP instance name can not be specified for single instance. */ if (name) return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET; /* Get default BGP structure if exists. */ bgp = bgp_get_default (); if (bgp) { if (bgp->as != *as) { *as = bgp->as; return BGP_ERR_AS_MISMATCH; } *bgp_val = bgp; return 0; } } bgp = bgp_create (as, name); bgp_router_id_set(bgp, &router_id_zebra); *bgp_val = bgp; /* Create BGP server socket, if first instance. */ if (list_isempty(bm->bgp) && !bgp_option_check (BGP_OPT_NO_LISTEN)) { if (bgp_socket (bm->port, bm->address) < 0) return BGP_ERR_INVALID_VALUE; } listnode_add (bm->bgp, bgp); return 0; } /* Delete BGP instance. */ int bgp_delete (struct bgp *bgp) { struct peer *peer; struct peer_group *group; struct listnode *node; struct listnode *next; afi_t afi; int i; THREAD_OFF (bgp->t_startup); /* Delete static route. */ bgp_static_delete (bgp); /* Unset redistribution. */ for (afi = AFI_IP; afi < AFI_MAX; afi++) for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (i != ZEBRA_ROUTE_BGP) bgp_redistribute_unset (bgp, afi, i); for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } peer_delete (peer); } for (ALL_LIST_ELEMENTS (bgp->group, node, next, group)) { for (ALL_LIST_ELEMENTS (group->peer, node, next, peer)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { /* Send notify to remote peer. */ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); } } peer_group_delete (group); } assert (listcount (bgp->rsclient) == 0); if (bgp->peer_self) { peer_delete(bgp->peer_self); bgp->peer_self = NULL; } /* Remove visibility via the master list - there may however still be * routes to be processed still referencing the struct bgp. */ listnode_delete (bm->bgp, bgp); if (list_isempty(bm->bgp)) bgp_close (); bgp_unlock(bgp); /* initial reference */ return 0; } static void bgp_free (struct bgp *); void bgp_lock (struct bgp *bgp) { ++bgp->lock; } void bgp_unlock(struct bgp *bgp) { assert(bgp->lock > 0); if (--bgp->lock == 0) bgp_free (bgp); } static void bgp_free (struct bgp *bgp) { afi_t afi; safi_t safi; list_delete (bgp->group); list_delete (bgp->peer); list_delete (bgp->rsclient); if (bgp->name) free (bgp->name); for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { if (bgp->route[afi][safi]) bgp_table_finish (&bgp->route[afi][safi]); if (bgp->aggregate[afi][safi]) bgp_table_finish (&bgp->aggregate[afi][safi]) ; if (bgp->rib[afi][safi]) bgp_table_finish (&bgp->rib[afi][safi]); } XFREE (MTYPE_BGP, bgp); } struct peer * peer_lookup (struct bgp *bgp, union sockunion *su) { struct peer *peer; struct listnode *node, *nnode; if (bgp != NULL) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) if (sockunion_same (&peer->su, su) && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) return peer; } else if (bm->bgp != NULL) { struct listnode *bgpnode, *nbgpnode; for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp)) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) if (sockunion_same (&peer->su, su) && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) return peer; } return NULL; } struct peer * peer_lookup_with_open (union sockunion *su, as_t remote_as, struct in_addr *remote_id, int *as) { struct peer *peer; struct listnode *node; struct listnode *bgpnode; struct bgp *bgp; if (! bm->bgp) return NULL; for (ALL_LIST_ELEMENTS_RO (bm->bgp, bgpnode, bgp)) { for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { if (sockunion_same (&peer->su, su) && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (peer->as == remote_as && peer->remote_id.s_addr == remote_id->s_addr) return peer; if (peer->as == remote_as) *as = 1; } } for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer)) { if (sockunion_same (&peer->su, su) && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (peer->as == remote_as && peer->remote_id.s_addr == 0) return peer; if (peer->as == remote_as) *as = 1; } } } return NULL; } /* If peer is configured at least one address family return 1. */ int peer_active (struct peer *peer) { if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_UNICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST]) return 1; return 0; } /* If peer is negotiated at least one address family return 1. */ int peer_active_nego (struct peer *peer) { if (peer->afc_nego[AFI_IP][SAFI_UNICAST] || peer->afc_nego[AFI_IP][SAFI_MULTICAST] || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] || peer->afc_nego[AFI_IP6][SAFI_UNICAST] || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) return 1; return 0; } /* peer_flag_change_type. */ enum peer_change_type { peer_change_none, peer_change_reset, peer_change_reset_in, peer_change_reset_out, }; static void peer_change_action (struct peer *peer, afi_t afi, safi_t safi, enum peer_change_type type) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return; if (peer->status != Established) return; if (type == peer_change_reset) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else if (type == peer_change_reset_in) { if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); else bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else if (type == peer_change_reset_out) bgp_announce_route (peer, afi, safi); } struct peer_flag_action { /* Peer's flag. */ u_int32_t flag; /* This flag can be set for peer-group member. */ u_char not_for_member; /* Action when the flag is changed. */ enum peer_change_type type; /* Peer down cause */ u_char peer_down; }; static const struct peer_flag_action peer_flag_action_list[] = { { PEER_FLAG_PASSIVE, 0, peer_change_reset }, { PEER_FLAG_SHUTDOWN, 0, peer_change_reset }, { PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none }, { PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none }, { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none }, { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset }, { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset }, { 0, 0, 0 } }; static const struct peer_flag_action peer_af_flag_action_list[] = { { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out }, { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out }, { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out }, { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in }, { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset }, { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset }, { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out }, { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out }, { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out }, { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out }, { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in }, { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset }, { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset }, { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out }, { PEER_FLAG_NEXTHOP_SELF_ALL, 1, peer_change_reset_out }, { 0, 0, 0 } }; /* Proper action set. */ static int peer_flag_action_set (const struct peer_flag_action *action_list, int size, struct peer_flag_action *action, u_int32_t flag) { int i; int found = 0; int reset_in = 0; int reset_out = 0; const struct peer_flag_action *match = NULL; /* Check peer's frag action. */ for (i = 0; i < size; i++) { match = &action_list[i]; if (match->flag == 0) break; if (match->flag & flag) { found = 1; if (match->type == peer_change_reset_in) reset_in = 1; if (match->type == peer_change_reset_out) reset_out = 1; if (match->type == peer_change_reset) { reset_in = 1; reset_out = 1; } if (match->not_for_member) action->not_for_member = 1; } } /* Set peer clear type. */ if (reset_in && reset_out) action->type = peer_change_reset; else if (reset_in) action->type = peer_change_reset_in; else if (reset_out) action->type = peer_change_reset_out; else action->type = peer_change_none; return found; } static void peer_flag_modify_action (struct peer *peer, u_int32_t flag) { if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG (peer->flags, flag)) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); if (peer->t_pmax_restart) { BGP_TIMER_OFF (peer->t_pmax_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Maximum-prefix restart timer canceled", peer->host); } if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); else BGP_EVENT_ADD (peer, BGP_Stop); } else { peer->v_start = BGP_INIT_START_TIMER; BGP_EVENT_ADD (peer, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_PASSIVE) peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } /* Change specified peer flag. */ static int peer_flag_modify (struct peer *peer, u_int32_t flag, int set) { int found; int size; struct peer_group *group; struct listnode *node, *nnode; struct peer_flag_action action; memset (&action, 0, sizeof (struct peer_flag_action)); size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action); found = peer_flag_action_set (peer_flag_action_list, size, &action, flag); /* No flag action is found. */ if (! found) return BGP_ERR_INVALID_FLAG; /* Not for peer-group member. */ if (action.not_for_member && peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* When unset the peer-group member's flag we have to check peer-group configuration. */ if (! set && peer_group_active (peer)) if (CHECK_FLAG (peer->group->conf->flags, flag)) { if (flag == PEER_FLAG_SHUTDOWN) return BGP_ERR_PEER_GROUP_SHUTDOWN; else return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; } /* Flag conflict check. */ if (set && CHECK_FLAG (peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH) && CHECK_FLAG (peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY)) return BGP_ERR_PEER_FLAG_CONFLICT; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (set && CHECK_FLAG (peer->flags, flag) == flag) return 0; if (! set && ! CHECK_FLAG (peer->flags, flag)) return 0; } if (set) SET_FLAG (peer->flags, flag); else UNSET_FLAG (peer->flags, flag); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (action.type == peer_change_reset) peer_flag_modify_action (peer, flag); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (set && CHECK_FLAG (peer->flags, flag) == flag) continue; if (! set && ! CHECK_FLAG (peer->flags, flag)) continue; if (set) SET_FLAG (peer->flags, flag); else UNSET_FLAG (peer->flags, flag); if (action.type == peer_change_reset) peer_flag_modify_action (peer, flag); } return 0; } int peer_flag_set (struct peer *peer, u_int32_t flag) { return peer_flag_modify (peer, flag, 1); } int peer_flag_unset (struct peer *peer, u_int32_t flag) { return peer_flag_modify (peer, flag, 0); } static int peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi) { if (peer->af_group[afi][safi]) return 1; return 0; } static int peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag, int set) { int found; int size; struct listnode *node, *nnode; struct peer_group *group; struct peer_flag_action action; memset (&action, 0, sizeof (struct peer_flag_action)); size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action); found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag); /* No flag action is found. */ if (! found) return BGP_ERR_INVALID_FLAG; /* Adress family must be activated. */ if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; /* Not for peer-group member. */ if (action.not_for_member && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* Spcecial check for reflector client. */ if (flag & PEER_FLAG_REFLECTOR_CLIENT && peer_sort (peer) != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Spcecial check for remove-private-AS. */ if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && peer_sort (peer) == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* When unset the peer-group member's flag we have to check peer-group configuration. */ if (! set && peer->af_group[afi][safi]) if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], flag)) return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; /* When current flag configuration is same as requested one. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) return 0; if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) return 0; } if (set) SET_FLAG (peer->af_flags[afi][safi], flag); else UNSET_FLAG (peer->af_flags[afi][safi], flag); /* Execute action when peer is established. */ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && peer->status == Established) { if (! set && flag == PEER_FLAG_SOFT_RECONFIG) bgp_clear_adj_in (peer, afi, safi); else { if (flag == PEER_FLAG_REFLECTOR_CLIENT) peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE; else if (flag == PEER_FLAG_RSERVER_CLIENT) peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE; else if (flag == PEER_FLAG_ORF_PREFIX_SM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_ORF_PREFIX_RM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; peer_change_action (peer, afi, safi, action.type); } } /* Peer group member updates. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[afi][safi]) continue; if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag) continue; if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag)) continue; if (set) SET_FLAG (peer->af_flags[afi][safi], flag); else UNSET_FLAG (peer->af_flags[afi][safi], flag); if (peer->status == Established) { if (! set && flag == PEER_FLAG_SOFT_RECONFIG) bgp_clear_adj_in (peer, afi, safi); else { if (flag == PEER_FLAG_REFLECTOR_CLIENT) peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE; else if (flag == PEER_FLAG_RSERVER_CLIENT) peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE; else if (flag == PEER_FLAG_ORF_PREFIX_SM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; else if (flag == PEER_FLAG_ORF_PREFIX_RM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; peer_change_action (peer, afi, safi, action.type); } } } } return 0; } int peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify (peer, afi, safi, flag, 1); } int peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag) { return peer_af_flag_modify (peer, afi, safi, flag, 0); } /* EBGP multihop configuration. */ int peer_ebgp_multihop_set (struct peer *peer, int ttl) { struct peer_group *group; struct listnode *node, *nnode; struct peer *peer1; if (peer->sort == BGP_PEER_IBGP) return 0; /* see comment in peer_ttl_security_hops_set() */ if (ttl != MAXTTL) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; if (group->conf->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if (peer1->sort == BGP_PEER_IBGP) continue; if (peer1->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } else { if (peer->gtsm_hops != 0) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; } } peer->ttl = ttl; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = group->conf->ttl; if (peer->fd >= 0) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } } return 0; } int peer_ebgp_multihop_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer->sort == BGP_PEER_IBGP) return 0; if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; if (peer_group_active (peer)) peer->ttl = peer->group->conf->ttl; else peer->ttl = 1; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->sort == BGP_PEER_IBGP) continue; peer->ttl = 1; if (peer->fd >= 0) sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl); } } return 0; } /* Neighbor description. */ int peer_description_set (struct peer *peer, char *desc) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc); return 0; } int peer_description_unset (struct peer *peer) { if (peer->desc) XFREE (MTYPE_PEER_DESC, peer->desc); peer->desc = NULL; return 0; } /* Neighbor update-source. */ int peer_update_source_if_set (struct peer *peer, const char *ifname) { struct peer_group *group; struct listnode *node, *nnode; if (peer->update_if) { if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && strcmp (peer->update_if, ifname) == 0) return 0; XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->update_if) { if (strcmp (peer->update_if, ifname) == 0) continue; XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_update_source_addr_set (struct peer *peer, union sockunion *su) { struct peer_group *group; struct listnode *node, *nnode; if (peer->update_source) { if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && sockunion_cmp (peer->update_source, su) == 0) return 0; sockunion_free (peer->update_source); peer->update_source = NULL; } if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } peer->update_source = sockunion_dup (su); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->update_source) { if (sockunion_cmp (peer->update_source, su) == 0) continue; sockunion_free (peer->update_source); peer->update_source = NULL; } if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } peer->update_source = sockunion_dup (su); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_update_source_unset (struct peer *peer) { union sockunion *su; struct peer_group *group; struct listnode *node, *nnode; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP) && ! peer->update_source && ! peer->update_if) return 0; if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } if (peer_group_active (peer)) { group = peer->group; if (group->conf->update_source) { su = sockunion_dup (group->conf->update_source); peer->update_source = su; } else if (group->conf->update_if) peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if); } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->update_source && ! peer->update_if) continue; if (peer->update_source) { sockunion_free (peer->update_source); peer->update_source = NULL; } if (peer->update_if) { XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if); peer->update_if = NULL; } if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi, const char *rmap) { struct peer_group *group; struct listnode *node, *nnode; /* Adress family must be activated. */ if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; /* Default originate can't be used for peer group memeber. */ if (peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE) || (rmap && ! peer->default_rmap[afi][safi].name) || (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0)) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); if (rmap) { if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = strdup (rmap); peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); } } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->status == Established && peer->afc_nego[afi][safi]) bgp_default_originate (peer, afi, safi, 0); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); if (rmap) { if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = strdup (rmap); peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap); } if (peer->status == Established && peer->afc_nego[afi][safi]) bgp_default_originate (peer, afi, safi, 0); } return 0; } int peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi) { struct peer_group *group; struct listnode *node, *nnode; /* Adress family must be activated. */ if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; /* Default originate can't be used for peer group memeber. */ if (peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) { UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->status == Established && peer->afc_nego[afi][safi]) bgp_default_originate (peer, afi, safi, 1); return 0; } /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE); if (peer->default_rmap[afi][safi].name) free (peer->default_rmap[afi][safi].name); peer->default_rmap[afi][safi].name = NULL; peer->default_rmap[afi][safi].map = NULL; if (peer->status == Established && peer->afc_nego[afi][safi]) bgp_default_originate (peer, afi, safi, 1); } return 0; } int peer_port_set (struct peer *peer, u_int16_t port) { peer->port = port; return 0; } int peer_port_unset (struct peer *peer) { peer->port = BGP_PORT_DEFAULT; return 0; } /* neighbor weight. */ int peer_weight_set (struct peer *peer, u_int16_t weight) { struct peer_group *group; struct listnode *node, *nnode; SET_FLAG (peer->config, PEER_CONFIG_WEIGHT); peer->weight = weight; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->weight = group->conf->weight; } return 0; } int peer_weight_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; /* Set default weight. */ if (peer_group_active (peer)) peer->weight = peer->group->conf->weight; else peer->weight = 0; UNSET_FLAG (peer->config, PEER_CONFIG_WEIGHT); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->weight = 0; } return 0; } int peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime) { struct peer_group *group; struct listnode *node, *nnode; /* Not for peer group memeber. */ if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* keepalive value check. */ if (keepalive > 65535) return BGP_ERR_INVALID_VALUE; /* Holdtime value check. */ if (holdtime > 65535) return BGP_ERR_INVALID_VALUE; /* Holdtime value must be either 0 or greater than 3. */ if (holdtime < 3 && holdtime != 0) return BGP_ERR_INVALID_VALUE; /* Set value to the configuration. */ SET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->holdtime = holdtime; peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { SET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->holdtime = group->conf->holdtime; peer->keepalive = group->conf->keepalive; } return 0; } int peer_timers_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* Clear configuration. */ UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->keepalive = 0; peer->holdtime = 0; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; /* peer-group member updates. */ group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { UNSET_FLAG (peer->config, PEER_CONFIG_TIMER); peer->holdtime = 0; peer->keepalive = 0; } return 0; } int peer_timers_connect_set (struct peer *peer, u_int32_t connect) { if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (connect > 65535) return BGP_ERR_INVALID_VALUE; /* Set value to the configuration. */ SET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = connect; /* Set value to timer setting. */ peer->v_connect = connect; return 0; } int peer_timers_connect_unset (struct peer *peer) { if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; /* Clear configuration. */ UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT); peer->connect = 0; /* Set timer setting to default value. */ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY; return 0; } int peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv) { if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (routeadv > 600) return BGP_ERR_INVALID_VALUE; SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = routeadv; peer->v_routeadv = routeadv; return 0; } int peer_advertise_interval_unset (struct peer *peer) { if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV); peer->routeadv = 0; if (peer->sort == BGP_PEER_IBGP) peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV; else peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; return 0; } /* neighbor interface */ int peer_interface_set (struct peer *peer, const char *str) { if (peer->ifname) free (peer->ifname); peer->ifname = strdup (str); return 0; } int peer_interface_unset (struct peer *peer) { if (peer->ifname) free (peer->ifname); peer->ifname = NULL; return 0; } /* Allow-as in. */ int peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num) { struct peer_group *group; struct listnode *node, *nnode; if (allow_num < 1 || allow_num > 10) return BGP_ERR_INVALID_VALUE; if (peer->allowas_in[afi][safi] != allow_num) { peer->allowas_in[afi][safi] = allow_num; SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); peer_change_action (peer, afi, safi, peer_change_reset_in); } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (peer->allowas_in[afi][safi] != allow_num) { peer->allowas_in[afi][safi] = allow_num; SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN); peer_change_action (peer, afi, safi, peer_change_reset_in); } } return 0; } int peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi) { struct peer_group *group; struct listnode *node, *nnode; if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) { peer->allowas_in[afi][safi] = 0; peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); } if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) { peer->allowas_in[afi][safi] = 0; peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN); } } return 0; } int peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as) { struct bgp *bgp = peer->bgp; struct peer_group *group; struct listnode *node, *nnode; if (peer_sort (peer) != BGP_PEER_EBGP && peer_sort (peer) != BGP_PEER_INTERNAL) return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP; if (bgp->as == as) return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (peer->as == as) return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS; if (peer->change_local_as == as && ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend) || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)) && ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && replace_as) || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && ! replace_as))) return 0; peer->change_local_as = as; if (no_prepend) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); if (replace_as) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->change_local_as = as; if (no_prepend) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); if (replace_as) SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); else UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_local_as_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; if (peer_group_active (peer)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; if (! peer->change_local_as) return 0; peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); return 0; } group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->change_local_as = 0; UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } /* Set password for authenticating with the peer. */ int peer_password_set (struct peer *peer, const char *password) { struct listnode *nn, *nnode; int len = password ? strlen(password) : 0; int ret = BGP_SUCCESS; if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN)) return BGP_ERR_INVALID_VALUE; if (peer->password && strcmp (peer->password, password) == 0 && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, password); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED; } for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer)) { if (peer->password && strcmp (peer->password, password) == 0) continue; if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); if (bgp_md5_set (peer) < 0) ret = BGP_ERR_TCPSIG_FAILED; } return ret; } int peer_password_unset (struct peer *peer) { struct listnode *nn, *nnode; if (!peer->password && !CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; if (!CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer_group_active (peer) && peer->group->conf->password && strcmp (peer->group->conf->password, peer->password) == 0) return BGP_ERR_PEER_GROUP_HAS_THE_FLAG; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); if (peer->password) XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; bgp_md5_set (peer); return 0; } XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer)) { if (!peer->password) continue; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); else BGP_EVENT_ADD (peer, BGP_Stop); XFREE (MTYPE_PEER_PASSWORD, peer->password); peer->password = NULL; bgp_md5_set (peer); } return 0; } /* Set distribute list to the peer. */ int peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->plist[direct].name) return BGP_ERR_PEER_FILTER_CONFLICT; if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = strdup (name); filter->dlist[direct].alist = access_list_lookup (afi, name); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = strdup (name); filter->dlist[direct].alist = access_list_lookup (afi, name); } return 0; } int peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) { struct bgp_filter *filter; struct bgp_filter *gfilter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->dlist[direct].name) { if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = strdup (gfilter->dlist[direct].name); filter->dlist[direct].alist = gfilter->dlist[direct].alist; return 0; } } if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = NULL; filter->dlist[direct].alist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->dlist[direct].name) free (filter->dlist[direct].name); filter->dlist[direct].name = NULL; filter->dlist[direct].alist = NULL; } return 0; } /* Update distribute list. */ static void peer_distribute_update (struct access_list *access) { afi_t afi; safi_t safi; int direct; struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->dlist[direct].name) filter->dlist[direct].alist = access_list_lookup (afi, filter->dlist[direct].name); else filter->dlist[direct].alist = NULL; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &group->conf->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->dlist[direct].name) filter->dlist[direct].alist = access_list_lookup (afi, filter->dlist[direct].name); else filter->dlist[direct].alist = NULL; } } } } } /* Set prefix list to the peer. */ int peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->dlist[direct].name) return BGP_ERR_PEER_FILTER_CONFLICT; if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = strdup (name); filter->plist[direct].plist = prefix_list_lookup (afi, name); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = strdup (name); filter->plist[direct].plist = prefix_list_lookup (afi, name); } return 0; } int peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) { struct bgp_filter *filter; struct bgp_filter *gfilter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->plist[direct].name) { if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = strdup (gfilter->plist[direct].name); filter->plist[direct].plist = gfilter->plist[direct].plist; return 0; } } if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = NULL; filter->plist[direct].plist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->plist[direct].name) free (filter->plist[direct].name); filter->plist[direct].name = NULL; filter->plist[direct].plist = NULL; } return 0; } /* Update prefix-list list. */ static void peer_prefix_list_update (struct prefix_list *plist) { struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; afi_t afi; safi_t safi; int direct; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->plist[direct].name) filter->plist[direct].plist = prefix_list_lookup (afi, filter->plist[direct].name); else filter->plist[direct].plist = NULL; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &group->conf->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->plist[direct].name) filter->plist[direct].plist = prefix_list_lookup (afi, filter->plist[direct].name); else filter->plist[direct].plist = NULL; } } } } } int peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = strdup (name); filter->aslist[direct].aslist = as_list_lookup (name); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = strdup (name); filter->aslist[direct].aslist = as_list_lookup (name); } return 0; } int peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct) { struct bgp_filter *filter; struct bgp_filter *gfilter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != FILTER_IN && direct != FILTER_OUT) return BGP_ERR_INVALID_VALUE; if (direct == FILTER_OUT && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->aslist[direct].name) { if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = strdup (gfilter->aslist[direct].name); filter->aslist[direct].aslist = gfilter->aslist[direct].aslist; return 0; } } if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = NULL; filter->aslist[direct].aslist = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->aslist[direct].name) free (filter->aslist[direct].name); filter->aslist[direct].name = NULL; filter->aslist[direct].aslist = NULL; } return 0; } static void peer_aslist_update (void) { afi_t afi; safi_t safi; int direct; struct listnode *mnode, *mnnode; struct listnode *node, *nnode; struct bgp *bgp; struct peer *peer; struct peer_group *group; struct bgp_filter *filter; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &peer->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->aslist[direct].name) filter->aslist[direct].aslist = as_list_lookup (filter->aslist[direct].name); else filter->aslist[direct].aslist = NULL; } } } for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { filter = &group->conf->filter[afi][safi]; for (direct = FILTER_IN; direct < FILTER_MAX; direct++) { if (filter->aslist[direct].name) filter->aslist[direct].aslist = as_list_lookup (filter->aslist[direct].name); else filter->aslist[direct].aslist = NULL; } } } } } /* Set route-map to the peer. */ int peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = strdup (name); filter->map[direct].map = route_map_lookup_by_name (name); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = strdup (name); filter->map[direct].map = route_map_lookup_by_name (name); } return 0; } /* Unset route-map from the peer. */ int peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct) { struct bgp_filter *filter; struct bgp_filter *gfilter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (direct != RMAP_IN && direct != RMAP_OUT && direct != RMAP_IMPORT && direct != RMAP_EXPORT) return BGP_ERR_INVALID_VALUE; if ( (direct == RMAP_OUT || direct == RMAP_IMPORT) && peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; /* apply peer-group filter */ if (peer->af_group[afi][safi]) { gfilter = &peer->group->conf->filter[afi][safi]; if (gfilter->map[direct].name) { if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = strdup (gfilter->map[direct].name); filter->map[direct].map = gfilter->map[direct].map; return 0; } } if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = NULL; filter->map[direct].map = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->map[direct].name) free (filter->map[direct].name); filter->map[direct].name = NULL; filter->map[direct].map = NULL; } return 0; } /* Set unsuppress-map to the peer. */ int peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi, const char *name) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->usmap.name) free (filter->usmap.name); filter->usmap.name = strdup (name); filter->usmap.map = route_map_lookup_by_name (name); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->usmap.name) free (filter->usmap.name); filter->usmap.name = strdup (name); filter->usmap.map = route_map_lookup_by_name (name); } return 0; } /* Unset route-map from the peer. */ int peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi) { struct bgp_filter *filter; struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; if (peer_is_group_member (peer, afi, safi)) return BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER; filter = &peer->filter[afi][safi]; if (filter->usmap.name) free (filter->usmap.name); filter->usmap.name = NULL; filter->usmap.map = NULL; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { filter = &peer->filter[afi][safi]; if (! peer->af_group[afi][safi]) continue; if (filter->usmap.name) free (filter->usmap.name); filter->usmap.name = NULL; filter->usmap.map = NULL; } return 0; } int peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t max, u_char threshold, int warning, u_int16_t restart) { struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); peer->pmax[afi][safi] = max; peer->pmax_threshold[afi][safi] = threshold; peer->pmax_restart[afi][safi] = restart; if (warning) SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[afi][safi]) continue; SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); peer->pmax[afi][safi] = max; peer->pmax_threshold[afi][safi] = threshold; peer->pmax_restart[afi][safi] = restart; if (warning) SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); } return 0; } int peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi) { struct peer_group *group; struct listnode *node, *nnode; if (! peer->afc[afi][safi]) return BGP_ERR_PEER_INACTIVE; /* apply peer-group config */ if (peer->af_group[afi][safi]) { if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); else UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi]; peer->pmax_threshold[afi][safi] = peer->group->conf->pmax_threshold[afi][safi]; peer->pmax_restart[afi][safi] = peer->group->conf->pmax_restart[afi][safi]; return 0; } UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); peer->pmax[afi][safi] = 0; peer->pmax_threshold[afi][safi] = 0; peer->pmax_restart[afi][safi] = 0; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) return 0; group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { if (! peer->af_group[afi][safi]) continue; UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX); UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING); peer->pmax[afi][safi] = 0; peer->pmax_threshold[afi][safi] = 0; peer->pmax_restart[afi][safi] = 0; } return 0; } static int is_ebgp_multihop_configured (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; struct peer *peer1; if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { group = peer->group; if ((peer_sort(peer) != BGP_PEER_IBGP) && (group->conf->ttl != 1)) return 1; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1)) { if ((peer_sort (peer1) != BGP_PEER_IBGP) && (peer1->ttl != 1)) return 1; } } else { if ((peer_sort(peer) != BGP_PEER_IBGP) && (peer->ttl != 1)) return 1; } return 0; } /* Set # of hops between us and BGP peer. */ int peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops) { struct peer_group *group; struct listnode *node, *nnode; int ret; zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host); /* We cannot configure ttl-security hops when ebgp-multihop is already set. For non peer-groups, the check is simple. For peer-groups, it's slightly messy, because we need to check both the peer-group structure and all peer-group members for any trace of ebgp-multihop configuration before actually applying the ttl-security rules. Cisco really made a mess of this configuration parameter, and OpenBGPD got it right. */ if (peer->gtsm_hops == 0) { if (is_ebgp_multihop_configured (peer)) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; /* specify MAXTTL on outgoing packets */ /* Routine handles iBGP peers correctly */ ret = peer_ebgp_multihop_set (peer, MAXTTL); if (ret != 0) return ret; } peer->gtsm_hops = gtsm_hops; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->gtsm_hops = group->conf->gtsm_hops; /* Change setting of existing peer * established then change value (may break connectivity) * not established yet (teardown session and restart) * no session then do nothing (will get handled by next connection) */ if (peer->status == Established) { if (peer->fd >= 0 && peer->gtsm_hops != 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops); } else if (peer->status < Established) { if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Min-ttl changed", peer->host); BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0; } int peer_ttl_security_hops_unset (struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; struct peer *opeer; zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host); /* if a peer-group member, then reset to peer-group default rather than 0 */ if (peer_group_active (peer)) peer->gtsm_hops = peer->group->conf->gtsm_hops; else peer->gtsm_hops = 0; opeer = peer; if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) { if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } else { group = peer->group; for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer)) { peer->gtsm_hops = 0; if (peer->fd >= 0) sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0); } } return peer_ebgp_multihop_unset (opeer); } int peer_clear (struct peer *peer) { if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) { UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW); if (peer->t_pmax_restart) { BGP_TIMER_OFF (peer->t_pmax_restart); if (BGP_DEBUG (events, EVENTS)) zlog_debug ("%s Maximum-prefix restart timer canceled", peer->host); } BGP_EVENT_ADD (peer, BGP_Start); return 0; } peer->v_start = BGP_INIT_START_TIMER; if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_RESET); else BGP_EVENT_ADD (peer, BGP_Stop); } return 0; } int peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi, enum bgp_clear_type stype) { if (peer->status != Established) return 0; if (! peer->afc[afi][safi]) return BGP_ERR_AF_UNCONFIGURED; if (stype == BGP_CLEAR_SOFT_RSCLIENT) { if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)) return 0; bgp_check_local_routes_rsclient (peer, afi, safi); bgp_soft_reconfig_rsclient (peer, afi, safi); } if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) bgp_announce_route (peer, afi, safi); if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) { if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV) && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV) || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) { struct bgp_filter *filter = &peer->filter[afi][safi]; u_char prefix_type; if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)) prefix_type = ORF_TYPE_PREFIX; else prefix_type = ORF_TYPE_PREFIX_OLD; if (filter->plist[FILTER_IN].plist) { if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) bgp_route_refresh_send (peer, afi, safi, prefix_type, REFRESH_DEFER, 1); bgp_route_refresh_send (peer, afi, safi, prefix_type, REFRESH_IMMEDIATE, 0); } else { if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND)) bgp_route_refresh_send (peer, afi, safi, prefix_type, REFRESH_IMMEDIATE, 1); else bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); } return 0; } } if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) { /* If neighbor has soft reconfiguration inbound flag. Use Adj-RIB-In database. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) bgp_soft_reconfig_in (peer, afi, safi); else { /* If neighbor has route refresh capability, send route refresh message to the peer. */ if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV) || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) bgp_route_refresh_send (peer, afi, safi, 0, 0, 0); else return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED; } } return 0; } /* Display peer uptime.*/ /* XXX: why does this function return char * when it takes buffer? */ char * peer_uptime (time_t uptime2, char *buf, size_t len) { time_t uptime1; struct tm *tm; /* Check buffer length. */ if (len < BGP_UPTIME_LEN) { zlog_warn ("peer_uptime (): buffer shortage %lu", (u_long)len); /* XXX: should return status instead of buf... */ snprintf (buf, len, " "); return buf; } /* If there is no connection has been done before print `never'. */ if (uptime2 == 0) { snprintf (buf, len, "never "); return buf; } /* Get current time. */ uptime1 = bgp_clock (); uptime1 -= uptime2; tm = gmtime (&uptime1); /* Making formatted timer strings. */ #define ONE_DAY_SECOND 60*60*24 #define ONE_WEEK_SECOND 60*60*24*7 if (uptime1 < ONE_DAY_SECOND) snprintf (buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); else if (uptime1 < ONE_WEEK_SECOND) snprintf (buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); else snprintf (buf, len, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); return buf; } static void bgp_config_write_filter (struct vty *vty, struct peer *peer, afi_t afi, safi_t safi) { struct bgp_filter *filter; struct bgp_filter *gfilter = NULL; char *addr; int in = FILTER_IN; int out = FILTER_OUT; addr = peer->host; filter = &peer->filter[afi][safi]; if (peer->af_group[afi][safi]) gfilter = &peer->group->conf->filter[afi][safi]; /* distribute-list. */ if (filter->dlist[in].name) if (! gfilter || ! gfilter->dlist[in].name || strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0) vty_out (vty, " neighbor %s distribute-list %s in%s", addr, filter->dlist[in].name, VTY_NEWLINE); if (filter->dlist[out].name && ! gfilter) vty_out (vty, " neighbor %s distribute-list %s out%s", addr, filter->dlist[out].name, VTY_NEWLINE); /* prefix-list. */ if (filter->plist[in].name) if (! gfilter || ! gfilter->plist[in].name || strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0) vty_out (vty, " neighbor %s prefix-list %s in%s", addr, filter->plist[in].name, VTY_NEWLINE); if (filter->plist[out].name && ! gfilter) vty_out (vty, " neighbor %s prefix-list %s out%s", addr, filter->plist[out].name, VTY_NEWLINE); /* route-map. */ if (filter->map[RMAP_IN].name) if (! gfilter || ! gfilter->map[RMAP_IN].name || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0) vty_out (vty, " neighbor %s route-map %s in%s", addr, filter->map[RMAP_IN].name, VTY_NEWLINE); if (filter->map[RMAP_OUT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s out%s", addr, filter->map[RMAP_OUT].name, VTY_NEWLINE); if (filter->map[RMAP_IMPORT].name && ! gfilter) vty_out (vty, " neighbor %s route-map %s import%s", addr, filter->map[RMAP_IMPORT].name, VTY_NEWLINE); if (filter->map[RMAP_EXPORT].name) if (! gfilter || ! gfilter->map[RMAP_EXPORT].name || strcmp (filter->map[RMAP_EXPORT].name, gfilter->map[RMAP_EXPORT].name) != 0) vty_out (vty, " neighbor %s route-map %s export%s", addr, filter->map[RMAP_EXPORT].name, VTY_NEWLINE); /* unsuppress-map */ if (filter->usmap.name && ! gfilter) vty_out (vty, " neighbor %s unsuppress-map %s%s", addr, filter->usmap.name, VTY_NEWLINE); /* filter-list. */ if (filter->aslist[in].name) if (! gfilter || ! gfilter->aslist[in].name || strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0) vty_out (vty, " neighbor %s filter-list %s in%s", addr, filter->aslist[in].name, VTY_NEWLINE); if (filter->aslist[out].name && ! gfilter) vty_out (vty, " neighbor %s filter-list %s out%s", addr, filter->aslist[out].name, VTY_NEWLINE); } /* BGP peer configuration display function. */ static void bgp_config_write_peer (struct vty *vty, struct bgp *bgp, struct peer *peer, afi_t afi, safi_t safi) { struct peer *g_peer = NULL; char buf[SU_ADDRSTRLEN]; char *addr; addr = peer->host; if (peer_group_active (peer)) g_peer = peer->group->conf; /************************************ ****** Global to the neighbor ****** ************************************/ if (afi == AFI_IP && safi == SAFI_UNICAST) { /* remote-as. */ if (! peer_group_active (peer)) { if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) vty_out (vty, " neighbor %s peer-group%s", addr, VTY_NEWLINE); if (peer->as) vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as, VTY_NEWLINE); } else { if (! g_peer->as) vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as, VTY_NEWLINE); if (peer->af_group[AFI_IP][SAFI_UNICAST]) vty_out (vty, " neighbor %s peer-group %s%s", addr, peer->group->name, VTY_NEWLINE); } /* local-as. */ if (peer->change_local_as) if (! peer_group_active (peer)) vty_out (vty, " neighbor %s local-as %u%s%s%s", addr, peer->change_local_as, CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ? " no-prepend" : "", CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ? " replace-as" : "", VTY_NEWLINE); /* Description. */ if (peer->desc) vty_out (vty, " neighbor %s description %s%s", addr, peer->desc, VTY_NEWLINE); /* Shutdown. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN)) vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE); /* Password. */ if (peer->password) if (!peer_group_active (peer) || ! g_peer->password || strcmp (peer->password, g_peer->password) != 0) vty_out (vty, " neighbor %s password %s%s", addr, peer->password, VTY_NEWLINE); /* BGP port. */ if (peer->port != BGP_PORT_DEFAULT) vty_out (vty, " neighbor %s port %d%s", addr, peer->port, VTY_NEWLINE); /* Local interface name. */ if (peer->ifname) vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname, VTY_NEWLINE); /* Passive. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE)) vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE); /* EBGP multihop. */ if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) if (! peer_group_active (peer) || g_peer->ttl != peer->ttl) vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl, VTY_NEWLINE); /* ttl-security hops */ if (peer->gtsm_hops != 0) if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops) vty_out (vty, " neighbor %s ttl-security hops %d%s", addr, peer->gtsm_hops, VTY_NEWLINE); /* disable-connected-check. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) vty_out (vty, " neighbor %s disable-connected-check%s", addr, VTY_NEWLINE); /* Update-source. */ if (peer->update_if) if (! peer_group_active (peer) || ! g_peer->update_if || strcmp (g_peer->update_if, peer->update_if) != 0) vty_out (vty, " neighbor %s update-source %s%s", addr, peer->update_if, VTY_NEWLINE); if (peer->update_source) if (! peer_group_active (peer) || ! g_peer->update_source || sockunion_cmp (g_peer->update_source, peer->update_source) != 0) vty_out (vty, " neighbor %s update-source %s%s", addr, sockunion2str (peer->update_source, buf, SU_ADDRSTRLEN), VTY_NEWLINE); /* advertisement-interval */ if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV)) vty_out (vty, " neighbor %s advertisement-interval %d%s", addr, peer->v_routeadv, VTY_NEWLINE); /* timers. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER) && ! peer_group_active (peer)) vty_out (vty, " neighbor %s timers %d %d%s", addr, peer->keepalive, peer->holdtime, VTY_NEWLINE); if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT)) vty_out (vty, " neighbor %s timers connect %d%s", addr, peer->connect, VTY_NEWLINE); /* Default weight. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_WEIGHT)) if (! peer_group_active (peer) || g_peer->weight != peer->weight) vty_out (vty, " neighbor %s weight %d%s", addr, peer->weight, VTY_NEWLINE); /* Dynamic capability. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) vty_out (vty, " neighbor %s capability dynamic%s", addr, VTY_NEWLINE); /* dont capability negotiation. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DONT_CAPABILITY)) vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr, VTY_NEWLINE); /* override capability negotiation. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) vty_out (vty, " neighbor %s override-capability%s", addr, VTY_NEWLINE); /* strict capability negotiation. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) if (! peer_group_active (peer) || ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) vty_out (vty, " neighbor %s strict-capability-match%s", addr, VTY_NEWLINE); if (! peer->af_group[AFI_IP][SAFI_UNICAST]) { if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) { if (peer->afc[AFI_IP][SAFI_UNICAST]) vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); } else { if (! peer->afc[AFI_IP][SAFI_UNICAST]) vty_out (vty, " no neighbor %s activate%s", addr, VTY_NEWLINE); } } } /************************************ ****** Per AF to the neighbor ****** ************************************/ if (! (afi == AFI_IP && safi == SAFI_UNICAST)) { if (peer->af_group[afi][safi]) vty_out (vty, " neighbor %s peer-group %s%s", addr, peer->group->name, VTY_NEWLINE); else vty_out (vty, " neighbor %s activate%s", addr, VTY_NEWLINE); } /* ORF capability. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) if (! peer->af_group[afi][safi]) { vty_out (vty, " neighbor %s capability orf prefix-list", addr); if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) vty_out (vty, " both"); else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_SM)) vty_out (vty, " send"); else vty_out (vty, " receive"); vty_out (vty, "%s", VTY_NEWLINE); } /* Route reflector client. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s route-reflector-client%s", addr, VTY_NEWLINE); /* Nexthop self. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s next-hop-self%s%s", addr, peer_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF_ALL) ? " all" : "", VTY_NEWLINE); /* Remove private AS. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s remove-private-AS%s", addr, VTY_NEWLINE); /* send-community print. */ if (! peer->af_group[afi][safi]) { if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) { if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) && peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " neighbor %s send-community both%s", addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " neighbor %s send-community extended%s", addr, VTY_NEWLINE); else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " neighbor %s send-community%s", addr, VTY_NEWLINE); } else { if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) && ! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " no neighbor %s send-community both%s", addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) vty_out (vty, " no neighbor %s send-community extended%s", addr, VTY_NEWLINE); else if (! peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) vty_out (vty, " no neighbor %s send-community%s", addr, VTY_NEWLINE); } } /* Default information */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE) && ! peer->af_group[afi][safi]) { vty_out (vty, " neighbor %s default-originate", addr); if (peer->default_rmap[afi][safi].name) vty_out (vty, " route-map %s", peer->default_rmap[afi][safi].name); vty_out (vty, "%s", VTY_NEWLINE); } /* Soft reconfiguration inbound. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) if (! peer->af_group[afi][safi] || ! CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)) vty_out (vty, " neighbor %s soft-reconfiguration inbound%s", addr, VTY_NEWLINE); /* maximum-prefix. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) if (! peer->af_group[afi][safi] || g_peer->pmax[afi][safi] != peer->pmax[afi][safi] || g_peer->pmax_threshold[afi][safi] != peer->pmax_threshold[afi][safi] || CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING) != CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) { vty_out (vty, " neighbor %s maximum-prefix %ld", addr, peer->pmax[afi][safi]); if (peer->pmax_threshold[afi][safi] != MAXIMUM_PREFIX_THRESHOLD_DEFAULT) vty_out (vty, " %d", peer->pmax_threshold[afi][safi]); if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)) vty_out (vty, " warning-only"); if (peer->pmax_restart[afi][safi]) vty_out (vty, " restart %d", peer->pmax_restart[afi][safi]); vty_out (vty, "%s", VTY_NEWLINE); } /* Route server client. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); /* Nexthop-local unchanged. */ if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && ! peer->af_group[afi][safi]) vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); /* Allow AS in. */ if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) if (! peer_group_active (peer) || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN) || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi]) { if (peer->allowas_in[afi][safi] == 3) vty_out (vty, " neighbor %s allowas-in%s", addr, VTY_NEWLINE); else vty_out (vty, " neighbor %s allowas-in %d%s", addr, peer->allowas_in[afi][safi], VTY_NEWLINE); } /* Filter. */ bgp_config_write_filter (vty, peer, afi, safi); /* atribute-unchanged. */ if ((CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) && ! peer->af_group[afi][safi]) { if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED) && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) vty_out (vty, " neighbor %s attribute-unchanged%s", addr, VTY_NEWLINE); else vty_out (vty, " neighbor %s attribute-unchanged%s%s%s%s", addr, (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)) ? " as-path" : "", (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)) ? " next-hop" : "", (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) ? " med" : "", VTY_NEWLINE); } } /* Display "address-family" configuration header. */ void bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi, int *write) { if (*write) return; if (afi == AFI_IP && safi == SAFI_UNICAST) return; vty_out (vty, "!%s address-family ", VTY_NEWLINE); if (afi == AFI_IP) { if (safi == SAFI_MULTICAST) vty_out (vty, "ipv4 multicast"); else if (safi == SAFI_MPLS_VPN) vty_out (vty, "vpnv4 unicast"); } else if (afi == AFI_IP6) { vty_out (vty, "ipv6"); if (safi == SAFI_MULTICAST) vty_out (vty, " multicast"); } vty_out (vty, "%s", VTY_NEWLINE); *write = 1; } /* Address family based peer configuration display. */ static int bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi) { int write = 0; struct peer *peer; struct peer_group *group; struct listnode *node, *nnode; bgp_config_write_network (vty, bgp, afi, safi, &write); bgp_config_write_redistribute (vty, bgp, afi, safi, &write); for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { if (group->conf->afc[afi][safi]) { bgp_config_write_family_header (vty, afi, safi, &write); bgp_config_write_peer (vty, bgp, group->conf, afi, safi); } } for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->afc[afi][safi]) { if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { bgp_config_write_family_header (vty, afi, safi, &write); bgp_config_write_peer (vty, bgp, peer, afi, safi); } } } bgp_config_write_maxpaths (vty, bgp, afi, safi, &write); if (write) vty_out (vty, " exit-address-family%s", VTY_NEWLINE); return write; } int bgp_config_write (struct vty *vty) { int write = 0; struct bgp *bgp; struct peer_group *group; struct peer *peer; struct listnode *node, *nnode; struct listnode *mnode, *mnnode; /* BGP Multiple instance. */ if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) { vty_out (vty, "bgp multiple-instance%s", VTY_NEWLINE); write++; } /* BGP Config type. */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) { vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE); write++; } /* BGP configuration. */ for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) { if (write) vty_out (vty, "!%s", VTY_NEWLINE); /* Router bgp ASN */ vty_out (vty, "router bgp %u", bgp->as); if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE)) { if (bgp->name) vty_out (vty, " view %s", bgp->name); } vty_out (vty, "%s", VTY_NEWLINE); /* No Synchronization */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) vty_out (vty, " no synchronization%s", VTY_NEWLINE); /* BGP fast-external-failover. */ if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE); /* BGP router ID. */ if (CHECK_FLAG (bgp->config, BGP_CONFIG_ROUTER_ID)) vty_out (vty, " bgp router-id %s%s", inet_ntoa (bgp->router_id), VTY_NEWLINE); /* BGP log-neighbor-changes. */ if (bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) vty_out (vty, " bgp log-neighbor-changes%s", VTY_NEWLINE); /* BGP configuration. */ if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)) vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE); /* BGP default ipv4-unicast. */ if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)) vty_out (vty, " no bgp default ipv4-unicast%s", VTY_NEWLINE); /* BGP default local-preference. */ if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF) vty_out (vty, " bgp default local-preference %d%s", bgp->default_local_pref, VTY_NEWLINE); /* BGP client-to-client reflection. */ if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT)) vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE); /* BGP cluster ID. */ if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID)) vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id), VTY_NEWLINE); /* Confederation identifier*/ if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION)) vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id, VTY_NEWLINE); /* Confederation peer */ if (bgp->confed_peers_cnt > 0) { int i; vty_out (vty, " bgp confederation peers"); for (i = 0; i < bgp->confed_peers_cnt; i++) vty_out(vty, " %u", bgp->confed_peers[i]); vty_out (vty, "%s", VTY_NEWLINE); } /* BGP enforce-first-as. */ if (bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS)) vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE); /* BGP deterministic-med. */ if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)) vty_out (vty, " bgp deterministic-med%s", VTY_NEWLINE); /* BGP graceful-restart. */ if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) vty_out (vty, " bgp graceful-restart stalepath-time %d%s", bgp->stalepath_time, VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART)) vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE); /* BGP bestpath method. */ if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE)) vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED)) vty_out (vty, " bgp bestpath as-path confed%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE); } if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)) vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE); if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED) || bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) { vty_out (vty, " bgp bestpath med"); if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)) vty_out (vty, " confed"); if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST)) vty_out (vty, " missing-as-worst"); vty_out (vty, "%s", VTY_NEWLINE); } /* BGP network import check. */ if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) vty_out (vty, " bgp network import-check%s", VTY_NEWLINE); /* BGP scan interval. */ bgp_config_write_scan_time (vty); /* BGP flag dampening. */ if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST], BGP_CONFIG_DAMPENING)) bgp_config_write_damp (vty); /* BGP static route configuration. */ bgp_config_write_network (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* BGP redistribute configuration. */ bgp_config_write_redistribute (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* BGP timers configuration. */ if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME) vty_out (vty, " timers bgp %d %d%s", bgp->default_keepalive, bgp->default_holdtime, VTY_NEWLINE); /* peer-group */ for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) { bgp_config_write_peer (vty, bgp, group->conf, AFI_IP, SAFI_UNICAST); } /* Normal neighbor configuration. */ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) bgp_config_write_peer (vty, bgp, peer, AFI_IP, SAFI_UNICAST); } /* maximum-paths */ bgp_config_write_maxpaths (vty, bgp, AFI_IP, SAFI_UNICAST, &write); /* Distance configuration. */ bgp_config_write_distance (vty, bgp); /* No auto-summary */ if (bgp_option_check (BGP_OPT_CONFIG_CISCO)) vty_out (vty, " no auto-summary%s", VTY_NEWLINE); /* IPv4 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST); /* IPv4 VPN configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN); /* IPv6 unicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST); /* IPv6 multicast configuration. */ write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST); write++; } return write; } void bgp_master_init (void) { memset (&bgp_master, 0, sizeof (struct bgp_master)); bm = &bgp_master; bm->bgp = list_new (); bm->listen_sockets = list_new (); bm->port = BGP_PORT_DEFAULT; bm->master = thread_master_create (); bm->start_time = bgp_clock (); } void bgp_init (void) { /* BGP VTY commands installation. */ bgp_vty_init (); /* Init zebra. */ bgp_zebra_init (); /* BGP inits. */ bgp_attr_init (); bgp_debug_init (); bgp_dump_init (); bgp_route_init (); bgp_route_map_init (); bgp_address_init (); bgp_scan_init (); bgp_mplsvpn_init (); /* Access list initialize. */ access_list_init (); access_list_add_hook (peer_distribute_update); access_list_delete_hook (peer_distribute_update); /* Filter list initialize. */ bgp_filter_init (); as_list_add_hook (peer_aslist_update); as_list_delete_hook (peer_aslist_update); /* Prefix list initialize.*/ prefix_list_init (); prefix_list_add_hook (peer_prefix_list_update); prefix_list_delete_hook (peer_prefix_list_update); /* Community list initialize. */ bgp_clist = community_list_init (); #ifdef HAVE_SNMP bgp_snmp_init (); #endif /* HAVE_SNMP */ } void bgp_terminate (void) { struct bgp *bgp; struct peer *peer; struct listnode *node, *nnode; struct listnode *mnode, *mnnode; for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp)) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) if (peer->status == Established) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); bgp_cleanup_routes (); if (bm->process_main_queue) { work_queue_free (bm->process_main_queue); bm->process_main_queue = NULL; } if (bm->process_rsclient_queue) { work_queue_free (bm->process_rsclient_queue); bm->process_rsclient_queue = NULL; } } quagga-0.99.24.1/bgpd/bgp_mpath.h0000644000175000017500000000567612476520570013300 00000000000000/* $QuaggaId: Format:%an, %ai, %h$ $ * * BGP Multipath * Copyright (C) 2010 Google Inc. * * This file is part of Quagga * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Quagga; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #ifndef _QUAGGA_BGP_MPATH_H #define _QUAGGA_BGP_MPATH_H /* BGP default maximum-paths */ #define BGP_DEFAULT_MAXPATHS 1 /* Supplemental information linked to bgp_info for keeping track of * multipath selections, lazily allocated to save memory */ struct bgp_info_mpath { /* Points to the first multipath (on bestpath) or the next multipath */ struct bgp_info_mpath *mp_next; /* Points to the previous multipath or NULL on bestpath */ struct bgp_info_mpath *mp_prev; /* Points to bgp_info associated with this multipath info */ struct bgp_info *mp_info; /* When attached to best path, the number of selected multipaths */ u_int32_t mp_count; /* Aggregated attribute for advertising multipath route */ struct attr *mp_attr; }; /* Functions to support maximum-paths configuration */ extern int bgp_maximum_paths_set (struct bgp *, afi_t, safi_t, int, u_int16_t); extern int bgp_maximum_paths_unset (struct bgp *, afi_t, safi_t, int); /* Functions used by bgp_best_selection to record current * multipath selections */ extern void bgp_mp_list_init (struct list *); extern void bgp_mp_list_clear (struct list *); extern void bgp_mp_list_add (struct list *, struct bgp_info *); extern void bgp_mp_dmed_deselect (struct bgp_info *); extern void bgp_info_mpath_update (struct bgp_node *, struct bgp_info *, struct bgp_info *, struct list *, struct bgp_maxpaths_cfg *); extern void bgp_info_mpath_aggregate_update (struct bgp_info *, struct bgp_info *); /* Unlink and free multipath information associated with a bgp_info */ extern void bgp_info_mpath_dequeue (struct bgp_info *); extern void bgp_info_mpath_free (struct bgp_info_mpath **); /* Walk list of multipaths associated with a best path */ extern struct bgp_info *bgp_info_mpath_first (struct bgp_info *); extern struct bgp_info *bgp_info_mpath_next (struct bgp_info *); /* Accessors for multipath information */ extern u_int32_t bgp_info_mpath_count (struct bgp_info *); extern struct attr *bgp_info_mpath_attr (struct bgp_info *); #endif /* _QUAGGA_BGP_MPATH_H */ quagga-0.99.24.1/bgpd/bgp_vty.h0000644000175000017500000000175312476520570013001 00000000000000/* BGP VTY interface. Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_VTY_H #define _QUAGGA_BGP_VTY_H #define CMD_AS_RANGE "<1-4294967295>" extern void bgp_vty_init (void); extern const char *afi_safi_print (afi_t, safi_t); #endif /* _QUAGGA_BGP_VTY_H */ quagga-0.99.24.1/bgpd/bgp_snmp.h0000644000175000017500000000175712476520570013140 00000000000000/* BGP4 SNMP support Copyright (C) 1999, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_SNMP_H #define _QUAGGA_BGP_SNMP_H extern void bgp_snmp_init (void); extern void bgpTrapEstablished (struct peer *); extern void bgpTrapBackwardTransition (struct peer *); #endif /* _QUAGGA_BGP_SNMP_H */ quagga-0.99.24.1/bgpd/bgp_advertise.h0000644000175000017500000001034012476520570014135 00000000000000/* BGP advertisement and adjacency Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ADVERTISE_H #define _QUAGGA_BGP_ADVERTISE_H /* BGP advertise attribute. */ struct bgp_advertise_attr { /* Head of advertisement pointer. */ struct bgp_advertise *adv; /* Reference counter. */ unsigned long refcnt; /* Attribute pointer to be announced. */ struct attr *attr; }; struct bgp_advertise { /* FIFO for advertisement. */ struct fifo fifo; /* Link list for same attribute advertise. */ struct bgp_advertise *next; struct bgp_advertise *prev; /* Prefix information. */ struct bgp_node *rn; /* Reference pointer. */ struct bgp_adj_out *adj; /* Advertisement attribute. */ struct bgp_advertise_attr *baa; /* BGP info. */ struct bgp_info *binfo; }; /* BGP adjacency out. */ struct bgp_adj_out { /* Lined list pointer. */ struct bgp_adj_out *next; struct bgp_adj_out *prev; /* Advertised peer. */ struct peer *peer; /* Advertised attribute. */ struct attr *attr; /* Advertisement information. */ struct bgp_advertise *adv; }; /* BGP adjacency in. */ struct bgp_adj_in { /* Linked list pointer. */ struct bgp_adj_in *next; struct bgp_adj_in *prev; /* Received peer. */ struct peer *peer; /* Received attribute. */ struct attr *attr; }; /* BGP advertisement list. */ struct bgp_synchronize { struct fifo update; struct fifo withdraw; struct fifo withdraw_low; }; #define BGP_ADV_FIFO_HEAD(F) ((struct bgp_advertise *)FIFO_HEAD(F)) /* BGP adjacency linked list. */ #define BGP_INFO_ADD(N,A,TYPE) \ do { \ (A)->prev = NULL; \ (A)->next = (N)->TYPE; \ if ((N)->TYPE) \ (N)->TYPE->prev = (A); \ (N)->TYPE = (A); \ } while (0) #define BGP_INFO_DEL(N,A,TYPE) \ do { \ if ((A)->next) \ (A)->next->prev = (A)->prev; \ if ((A)->prev) \ (A)->prev->next = (A)->next; \ else \ (N)->TYPE = (A)->next; \ } while (0) #define BGP_ADJ_IN_ADD(N,A) BGP_INFO_ADD(N,A,adj_in) #define BGP_ADJ_IN_DEL(N,A) BGP_INFO_DEL(N,A,adj_in) #define BGP_ADJ_OUT_ADD(N,A) BGP_INFO_ADD(N,A,adj_out) #define BGP_ADJ_OUT_DEL(N,A) BGP_INFO_DEL(N,A,adj_out) /* Prototypes. */ extern void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *, struct attr *, afi_t, safi_t, struct bgp_info *); extern void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *, afi_t, safi_t); extern void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *, struct peer *, afi_t, safi_t); extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t, struct bgp_node *); extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *); extern void bgp_adj_in_unset (struct bgp_node *, struct peer *); extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *); extern struct bgp_advertise * bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t); extern void bgp_sync_init (struct peer *); extern void bgp_sync_delete (struct peer *); #endif /* _QUAGGA_BGP_ADVERTISE_H */ quagga-0.99.24.1/bgpd/bgp_table.h0000644000175000017500000001576012476520570013251 00000000000000/* BGP routing table Copyright (C) 1998, 2001 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_TABLE_H #define _QUAGGA_BGP_TABLE_H #include "table.h" typedef enum { BGP_TABLE_MAIN, BGP_TABLE_RSCLIENT, } bgp_table_t; struct bgp_table { bgp_table_t type; /* afi/safi of this table */ afi_t afi; safi_t safi; int lock; /* The owner of this 'bgp_table' structure. */ struct peer *owner; struct route_table *route_table; }; struct bgp_node { /* * CAUTION * * These fields must be the very first fields in this structure. * * @see bgp_node_to_rnode * @see bgp_node_from_rnode */ ROUTE_NODE_FIELDS; struct bgp_adj_out *adj_out; struct bgp_adj_in *adj_in; struct bgp_node *prn; u_char flags; #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) }; /* * bgp_table_iter_t * * Structure that holds state for iterating over a bgp table. */ typedef struct bgp_table_iter_t_ { struct bgp_table *table; route_table_iter_t rt_iter; } bgp_table_iter_t; extern struct bgp_table *bgp_table_init (afi_t, safi_t); extern void bgp_table_lock (struct bgp_table *); extern void bgp_table_unlock (struct bgp_table *); extern void bgp_table_finish (struct bgp_table **); /* * bgp_node_from_rnode * * Returns the bgp_node structure corresponding to a route_node. */ static inline struct bgp_node * bgp_node_from_rnode (struct route_node *rnode) { return (struct bgp_node *) rnode; } /* * bgp_node_to_rnode * * Returns the route_node structure corresponding to a bgp_node. */ static inline struct route_node * bgp_node_to_rnode (struct bgp_node *node) { return (struct route_node *) node; } /* * bgp_node_table * * Returns the bgp_table that the given node is in. */ static inline struct bgp_table * bgp_node_table (struct bgp_node *node) { return bgp_node_to_rnode (node)->table->info; } /* * bgp_node_info * * Returns the 'info' pointer corresponding to a bgp node. */ static inline void * bgp_node_info (const struct bgp_node *node) { return node->info; } /* * bgp_node_set_info */ static inline void bgp_node_set_info (struct bgp_node *node, void *info) { node->info = info; } /* * bgp_node_prefix */ static inline struct prefix * bgp_node_prefix (struct bgp_node *node) { return &node->p; } /* * bgp_node_prefixlen */ static inline u_char bgp_node_prefixlen (struct bgp_node *node) { return bgp_node_prefix (node)->prefixlen; } /* * bgp_node_parent_nolock * * Gets the parent node of the given node without locking it. */ static inline struct bgp_node * bgp_node_parent_nolock (struct bgp_node *node) { return bgp_node_from_rnode (node->parent); } /* * bgp_unlock_node */ static inline void bgp_unlock_node (struct bgp_node *node) { route_unlock_node (bgp_node_to_rnode (node)); } /* * bgp_table_top_nolock * * Gets the top node in the table without locking it. * * @see bgp_table_top */ static inline struct bgp_node * bgp_table_top_nolock (const struct bgp_table *const table) { return bgp_node_from_rnode (table->route_table->top); } /* * bgp_table_top */ static inline struct bgp_node * bgp_table_top (const struct bgp_table *const table) { return bgp_node_from_rnode (route_top (table->route_table)); } /* * bgp_route_next */ static inline struct bgp_node * bgp_route_next (struct bgp_node *node) { return bgp_node_from_rnode (route_next (bgp_node_to_rnode (node))); } /* * bgp_route_next_until */ static inline struct bgp_node * bgp_route_next_until (struct bgp_node *node, struct bgp_node *limit) { struct route_node *rnode; rnode = route_next_until (bgp_node_to_rnode (node), bgp_node_to_rnode (limit)); return bgp_node_from_rnode (rnode); } /* * bgp_node_get */ static inline struct bgp_node * bgp_node_get (struct bgp_table *const table, struct prefix *p) { return bgp_node_from_rnode (route_node_get (table->route_table, p)); } /* * bgp_node_lookup */ static inline struct bgp_node * bgp_node_lookup (const struct bgp_table *const table, struct prefix *p) { return bgp_node_from_rnode (route_node_lookup (table->route_table, p)); } /* * bgp_lock_node */ static inline struct bgp_node * bgp_lock_node (struct bgp_node *node) { return bgp_node_from_rnode (route_lock_node (bgp_node_to_rnode (node))); } /* * bgp_node_match */ static inline struct bgp_node * bgp_node_match (const struct bgp_table *table, struct prefix *p) { return bgp_node_from_rnode (route_node_match (table->route_table, p)); } /* * bgp_node_match_ipv4 */ static inline struct bgp_node * bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) { return bgp_node_from_rnode (route_node_match_ipv4 (table->route_table, addr)); } #ifdef HAVE_IPV6 /* * bgp_node_match_ipv6 */ static inline struct bgp_node * bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) { return bgp_node_from_rnode (route_node_match_ipv6 (table->route_table, addr)); } #endif /* HAVE_IPV6 */ static inline unsigned long bgp_table_count (const struct bgp_table *const table) { return route_table_count (table->route_table); } /* * bgp_table_get_next */ static inline struct bgp_node * bgp_table_get_next (const struct bgp_table *table, struct prefix *p) { return bgp_node_from_rnode (route_table_get_next (table->route_table, p)); } /* * bgp_table_iter_init */ static inline void bgp_table_iter_init (bgp_table_iter_t * iter, struct bgp_table *table) { bgp_table_lock (table); iter->table = table; route_table_iter_init (&iter->rt_iter, table->route_table); } /* * bgp_table_iter_next */ static inline struct bgp_node * bgp_table_iter_next (bgp_table_iter_t * iter) { return bgp_node_from_rnode (route_table_iter_next (&iter->rt_iter)); } /* * bgp_table_iter_cleanup */ static inline void bgp_table_iter_cleanup (bgp_table_iter_t * iter) { route_table_iter_cleanup (&iter->rt_iter); bgp_table_unlock (iter->table); iter->table = NULL; } /* * bgp_table_iter_pause */ static inline void bgp_table_iter_pause (bgp_table_iter_t * iter) { route_table_iter_pause (&iter->rt_iter); } /* * bgp_table_iter_is_done */ static inline int bgp_table_iter_is_done (bgp_table_iter_t * iter) { return route_table_iter_is_done (&iter->rt_iter); } /* * bgp_table_iter_started */ static inline int bgp_table_iter_started (bgp_table_iter_t * iter) { return route_table_iter_started (&iter->rt_iter); } #endif /* _QUAGGA_BGP_TABLE_H */ quagga-0.99.24.1/bgpd/bgp_damp.h0000644000175000017500000001061612476520570013076 00000000000000/* BGP flap dampening Copyright (C) 2001 IP Infusion Inc. This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_DAMP_H #define _QUAGGA_BGP_DAMP_H /* Structure maintained on a per-route basis. */ struct bgp_damp_info { /* Doubly linked list. This information must be linked to reuse_list or no_reuse_list. */ struct bgp_damp_info *next; struct bgp_damp_info *prev; /* Figure-of-merit. */ unsigned int penalty; /* Number of flapping. */ unsigned int flap; /* First flap time */ time_t start_time; /* Last time penalty was updated. */ time_t t_updated; /* Time of route start to be suppressed. */ time_t suppress_time; /* Back reference to bgp_info. */ struct bgp_info *binfo; /* Back reference to bgp_node. */ struct bgp_node *rn; /* Current index in the reuse_list. */ int index; /* Last time message type. */ u_char lastrecord; #define BGP_RECORD_UPDATE 1U #define BGP_RECORD_WITHDRAW 2U afi_t afi; safi_t safi; }; /* Specified parameter set configuration. */ struct bgp_damp_config { /* Value over which routes suppressed. */ unsigned int suppress_value; /* Value below which suppressed routes reused. */ unsigned int reuse_limit; /* Max time a route can be suppressed. */ time_t max_suppress_time; /* Time during which accumulated penalty reduces by half. */ time_t half_life; /* Non-configurable parameters but fixed at implementation time. * To change this values, init_bgp_damp() should be modified. */ time_t tmax; /* Max time previous instability retained */ unsigned int reuse_list_size; /* Number of reuse lists */ unsigned int reuse_index_size; /* Size of reuse index array */ /* Non-configurable parameters. Most of these are calculated from * the configurable parameters above. */ unsigned int ceiling; /* Max value a penalty can attain */ unsigned int decay_rate_per_tick; /* Calculated from half-life */ unsigned int decay_array_size; /* Calculated using config parameters */ double scale_factor; unsigned int reuse_scale_factor; /* Decay array per-set based. */ double *decay_array; /* Reuse index array per-set based. */ int *reuse_index; /* Reuse list array per-set based. */ struct bgp_damp_info **reuse_list; int reuse_offset; /* All dampening information which is not on reuse list. */ struct bgp_damp_info *no_reuse_list; /* Reuse timer thread per-set base. */ struct thread* t_reuse; }; #define BGP_DAMP_NONE 0 #define BGP_DAMP_USED 1 #define BGP_DAMP_SUPPRESSED 2 /* Time granularity for reuse lists */ #define DELTA_REUSE 10 /* Time granularity for decay arrays */ #define DELTA_T 5 #define DEFAULT_PENALTY 1000 #define DEFAULT_HALF_LIFE 15 #define DEFAULT_REUSE 750 #define DEFAULT_SUPPRESS 2000 #define REUSE_LIST_SIZE 256 #define REUSE_ARRAY_SIZE 1024 extern int bgp_damp_enable (struct bgp *, afi_t, safi_t, time_t, unsigned int, unsigned int, time_t); extern int bgp_damp_disable (struct bgp *, afi_t, safi_t); extern int bgp_damp_withdraw (struct bgp_info *, struct bgp_node *, afi_t, safi_t, int); extern int bgp_damp_update (struct bgp_info *, struct bgp_node *, afi_t, safi_t); extern int bgp_damp_scan (struct bgp_info *, afi_t, safi_t); extern void bgp_damp_info_free (struct bgp_damp_info *, int); extern void bgp_damp_info_clean (void); extern int bgp_damp_decay (time_t, int); extern void bgp_config_write_damp (struct vty *); extern void bgp_damp_info_vty (struct vty *, struct bgp_info *); extern const char * bgp_damp_reuse_time_vty (struct vty *, struct bgp_info *, char *, size_t); #endif /* _QUAGGA_BGP_DAMP_H */ quagga-0.99.24.1/bgpd/bgp_nexthop.h0000644000175000017500000000350712476520570013643 00000000000000/* BGP nexthop scan Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_NEXTHOP_H #define _QUAGGA_BGP_NEXTHOP_H #include "if.h" #define BGP_SCAN_INTERVAL_DEFAULT 60 #define BGP_IMPORT_INTERVAL_DEFAULT 15 /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { /* This nexthop exists in IGP. */ u_char valid; /* Nexthop is changed. */ u_char changed; /* Nexthop is changed. */ u_char metricchanged; /* IGP route's metric. */ u_int32_t metric; /* Nexthop number and nexthop linked list.*/ u_char nexthop_num; struct nexthop *nexthop; }; extern void bgp_scan_init (void); extern void bgp_scan_finish (void); extern int bgp_nexthop_lookup (afi_t, struct peer *peer, struct bgp_info *, int *, int *); extern void bgp_connected_add (struct connected *c); extern void bgp_connected_delete (struct connected *c); extern int bgp_multiaccess_check_v4 (struct in_addr, char *); extern int bgp_config_write_scan_time (struct vty *); extern int bgp_nexthop_onlink (afi_t, struct attr *); extern int bgp_nexthop_self (struct attr *); extern void bgp_address_init (void); #endif /* _QUAGGA_BGP_NEXTHOP_H */ quagga-0.99.24.1/bgpd/bgp_mplsvpn.h0000644000175000017500000000263612476520570013657 00000000000000/* MPLS-VPN Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_MPLSVPN_H #define _QUAGGA_BGP_MPLSVPN_H #define RD_TYPE_AS 0 #define RD_TYPE_IP 1 #define RD_ADDRSTRLEN 28 struct rd_as { u_int16_t type; as_t as; u_int32_t val; }; struct rd_ip { u_int16_t type; struct in_addr ip; u_int16_t val; }; extern void bgp_mplsvpn_init (void); extern int bgp_nlri_parse_vpnv4 (struct peer *, struct attr *, struct bgp_nlri *); extern u_int32_t decode_label (u_char *); extern int str2prefix_rd (const char *, struct prefix_rd *); extern int str2tag (const char *, u_char *); extern char *prefix_rd2str (struct prefix_rd *, char *, size_t); #endif /* _QUAGGA_BGP_MPLSVPN_H */ quagga-0.99.24.1/bgpd/bgp_ecommunity.h0000644000175000017500000000575112476520570014352 00000000000000/* BGP Extended Communities Attribute. Copyright (C) 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ECOMMUNITY_H #define _QUAGGA_BGP_ECOMMUNITY_H /* High-order octet of the Extended Communities type field. */ #define ECOMMUNITY_ENCODE_AS 0x00 #define ECOMMUNITY_ENCODE_IP 0x01 #define ECOMMUNITY_ENCODE_AS4 0x02 /* Low-order octet of the Extended Communityes type field. */ #define ECOMMUNITY_ROUTE_TARGET 0x02 #define ECOMMUNITY_SITE_ORIGIN 0x03 /* Extended communities attribute string format. */ #define ECOMMUNITY_FORMAT_ROUTE_MAP 0 #define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1 #define ECOMMUNITY_FORMAT_DISPLAY 2 /* Extended Communities value is eight octet long. */ #define ECOMMUNITY_SIZE 8 /* Extended Communities type flag. */ #define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 /* Extended Communities attribute. */ struct ecommunity { /* Reference counter. */ unsigned long refcnt; /* Size of Extended Communities attribute. */ int size; /* Extended Communities value. */ u_int8_t *val; /* Human readable format string. */ char *str; }; /* Extended community value is eight octet. */ struct ecommunity_val { char val[ECOMMUNITY_SIZE]; }; #define ecom_length(X) ((X)->size * ECOMMUNITY_SIZE) extern void ecommunity_init (void); extern void ecommunity_finish (void); extern void ecommunity_free (struct ecommunity **); extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short); extern struct ecommunity *ecommunity_dup (struct ecommunity *); extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *); extern struct ecommunity *ecommunity_uniq_sort (struct ecommunity *); extern struct ecommunity *ecommunity_intern (struct ecommunity *); extern int ecommunity_cmp (const void *, const void *); extern void ecommunity_unintern (struct ecommunity **); extern unsigned int ecommunity_hash_make (void *); extern struct ecommunity *ecommunity_str2com (const char *, int, int); extern char *ecommunity_ecom2str (struct ecommunity *, int); extern int ecommunity_match (const struct ecommunity *, const struct ecommunity *); extern char *ecommunity_str (struct ecommunity *); #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ quagga-0.99.24.1/bgpd/bgp_zebra.h0000644000175000017500000000416212476520570013257 00000000000000/* zebra connection and redistribute fucntions. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ZEBRA_H #define _QUAGGA_BGP_ZEBRA_H #define BGP_NEXTHOP_BUF_SIZE (8 * sizeof (struct in_addr *)) extern struct stream *bgp_nexthop_buf; extern void bgp_zebra_init (void); extern int bgp_if_update_all (void); extern int bgp_config_write_maxpaths (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t, int *); extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t); extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t); extern int bgp_redistribute_set (struct bgp *, afi_t, int); extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); extern int bgp_redistribute_metric_set (struct bgp *, afi_t, int, u_int32_t); extern int bgp_redistribute_unset (struct bgp *, afi_t, int); extern int bgp_redistribute_routemap_unset (struct bgp *, afi_t, int); extern int bgp_redistribute_metric_unset (struct bgp *, afi_t, int); extern struct interface *if_lookup_by_ipv4 (struct in_addr *); extern struct interface *if_lookup_by_ipv4_exact (struct in_addr *); #ifdef HAVE_IPV6 extern struct interface *if_lookup_by_ipv6 (struct in6_addr *); extern struct interface *if_lookup_by_ipv6_exact (struct in6_addr *); #endif /* HAVE_IPV6 */ #endif /* _QUAGGA_BGP_ZEBRA_H */ quagga-0.99.24.1/bgpd/bgp_dump.h0000644000175000017500000000356212476520570013124 00000000000000/* BGP dump routine. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_DUMP_H #define _QUAGGA_BGP_DUMP_H /* MRT compatible packet dump values. */ /* type value */ #define MSG_PROTOCOL_BGP4MP 16 /* subtype value */ #define BGP4MP_STATE_CHANGE 0 #define BGP4MP_MESSAGE 1 #define BGP4MP_ENTRY 2 #define BGP4MP_SNAPSHOT 3 #define BGP4MP_MESSAGE_AS4 4 #define BGP4MP_STATE_CHANGE_AS4 5 #define BGP_DUMP_HEADER_SIZE 12 #define BGP_DUMP_MSG_HEADER 40 #define TABLE_DUMP_V2_PEER_INDEX_TABLE 1 #define TABLE_DUMP_V2_RIB_IPV4_UNICAST 2 #define TABLE_DUMP_V2_RIB_IPV4_MULTICAST 3 #define TABLE_DUMP_V2_RIB_IPV6_UNICAST 4 #define TABLE_DUMP_V2_RIB_IPV6_MULTICAST 5 #define TABLE_DUMP_V2_RIB_GENERIC 6 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP 0 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_IP6 1 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS2 0 #define TABLE_DUMP_V2_PEER_INDEX_TABLE_AS4 2 extern void bgp_dump_init (void); extern void bgp_dump_finish (void); extern void bgp_dump_state (struct peer *, int, int); extern void bgp_dump_packet (struct peer *, int, struct stream *); #endif /* _QUAGGA_BGP_DUMP_H */ quagga-0.99.24.1/bgpd/bgp_clist.h0000644000175000017500000001112012476520570013262 00000000000000/* BGP Community list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_CLIST_H #define _QUAGGA_BGP_CLIST_H /* Master Community-list. */ #define COMMUNITY_LIST_MASTER 0 #define EXTCOMMUNITY_LIST_MASTER 1 /* Community-list deny and permit. */ #define COMMUNITY_DENY 0 #define COMMUNITY_PERMIT 1 /* Number and string based community-list name. */ #define COMMUNITY_LIST_STRING 0 #define COMMUNITY_LIST_NUMBER 1 /* Community-list entry types. */ #define COMMUNITY_LIST_STANDARD 0 /* Standard community-list. */ #define COMMUNITY_LIST_EXPANDED 1 /* Expanded community-list. */ #define EXTCOMMUNITY_LIST_STANDARD 2 /* Standard extcommunity-list. */ #define EXTCOMMUNITY_LIST_EXPANDED 3 /* Expanded extcommunity-list. */ /* Community-list. */ struct community_list { /* Name of the community-list. */ char *name; /* String or number. */ int sort; /* Link to upper list. */ struct community_list_list *parent; /* Linked list for other community-list. */ struct community_list *next; struct community_list *prev; /* Community-list entry in this community-list. */ struct community_entry *head; struct community_entry *tail; }; /* Each entry in community-list. */ struct community_entry { struct community_entry *next; struct community_entry *prev; /* Permit or deny. */ u_char direct; /* Standard or expanded. */ u_char style; /* Any match. */ u_char any; /* Community structure. */ union { struct community *com; struct ecommunity *ecom; } u; /* Configuration string. */ char *config; /* Expanded community-list regular expression. */ regex_t *reg; }; /* Linked list of community-list. */ struct community_list_list { struct community_list *head; struct community_list *tail; }; /* Master structure of community-list and extcommunity-list. */ struct community_list_master { struct community_list_list num; struct community_list_list str; }; /* Community-list handler. community_list_init() returns this structure as handler. */ struct community_list_handler { /* Community-list. */ struct community_list_master community_list; /* Exteded community-list. */ struct community_list_master extcommunity_list; }; /* Error code of community-list. */ #define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1 #define COMMUNITY_LIST_ERR_MALFORMED_VAL -2 #define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3 #define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4 /* Handler. */ extern struct community_list_handler *bgp_clist; /* Prototypes. */ extern struct community_list_handler *community_list_init (void); extern void community_list_terminate (struct community_list_handler *); extern int community_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int community_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int extcommunity_list_set (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern int extcommunity_list_unset (struct community_list_handler *ch, const char *name, const char *str, int direct, int style); extern struct community_list_master * community_list_master_lookup (struct community_list_handler *, int); extern struct community_list * community_list_lookup (struct community_list_handler *, const char *, int); extern int community_list_match (struct community *, struct community_list *); extern int ecommunity_list_match (struct ecommunity *, struct community_list *); extern int community_list_exact_match (struct community *, struct community_list *); extern struct community * community_list_match_delete (struct community *, struct community_list *); #endif /* _QUAGGA_BGP_CLIST_H */ quagga-0.99.24.1/bgpd/bgp_filter.h0000644000175000017500000000233112476520570013435 00000000000000/* AS path filter list. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; extern void bgp_filter_init (void); extern void bgp_filter_reset (void); extern enum as_filter_type as_list_apply (struct as_list *, void *); extern struct as_list *as_list_lookup (const char *); extern void as_list_add_hook (void (*func) (void)); extern void as_list_delete_hook (void (*func) (void)); #endif /* _QUAGGA_BGP_FILTER_H */ quagga-0.99.24.1/bgpd/bgpd.h0000644000175000017500000010600112476520570012233 00000000000000/* BGP message definition header. Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGPD_H #define _QUAGGA_BGPD_H /* For union sockunion. */ #include "sockunion.h" /* Typedef BGP specific types. */ typedef u_int32_t as_t; typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */ typedef u_int16_t bgp_size_t; /* BGP master for system wide configurations and variables. */ struct bgp_master { /* BGP instance list. */ struct list *bgp; /* BGP thread master. */ struct thread_master *master; /* work queues */ struct work_queue *process_main_queue; struct work_queue *process_rsclient_queue; /* Listening sockets */ struct list *listen_sockets; /* BGP port number. */ u_int16_t port; /* Listener address */ char *address; /* BGP start time. */ time_t start_time; /* Various BGP global configuration. */ u_char options; #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_MULTIPLE_INSTANCE (1 << 1) #define BGP_OPT_CONFIG_CISCO (1 << 2) #define BGP_OPT_NO_LISTEN (1 << 3) }; /* BGP instance structure. */ struct bgp { /* AS number of this BGP instance. */ as_t as; /* Name of this BGP instance. */ char *name; /* Reference count to allow peer_delete to finish after bgp_delete */ int lock; /* Self peer. */ struct peer *peer_self; /* BGP peer. */ struct list *peer; /* BGP peer group. */ struct list *group; /* BGP route-server-clients. */ struct list *rsclient; /* BGP configuration. */ u_int16_t config; #define BGP_CONFIG_ROUTER_ID (1 << 0) #define BGP_CONFIG_CLUSTER_ID (1 << 1) #define BGP_CONFIG_CONFEDERATION (1 << 2) /* BGP router identifier. */ struct in_addr router_id; struct in_addr router_id_static; /* BGP route reflector cluster ID. */ struct in_addr cluster_id; /* BGP confederation information. */ as_t confed_id; as_t *confed_peers; int confed_peers_cnt; struct thread *t_startup; /* BGP flags. */ u_int16_t flags; #define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0) #define BGP_FLAG_DETERMINISTIC_MED (1 << 1) #define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2) #define BGP_FLAG_MED_CONFED (1 << 3) #define BGP_FLAG_NO_DEFAULT_IPV4 (1 << 4) #define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 5) #define BGP_FLAG_ENFORCE_FIRST_AS (1 << 6) #define BGP_FLAG_COMPARE_ROUTER_ID (1 << 7) #define BGP_FLAG_ASPATH_IGNORE (1 << 8) #define BGP_FLAG_IMPORT_CHECK (1 << 9) #define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 10) #define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11) #define BGP_FLAG_GRACEFUL_RESTART (1 << 12) #define BGP_FLAG_ASPATH_CONFED (1 << 13) #define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14) /* BGP Per AF flags */ u_int16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) /* Static route configuration. */ struct bgp_table *route[AFI_MAX][SAFI_MAX]; /* Aggregate address configuration. */ struct bgp_table *aggregate[AFI_MAX][SAFI_MAX]; /* BGP routing information base. */ struct bgp_table *rib[AFI_MAX][SAFI_MAX]; /* BGP redistribute configuration. */ u_char redist[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP redistribute metric configuration. */ u_char redist_metric_flag[AFI_MAX][ZEBRA_ROUTE_MAX]; u_int32_t redist_metric[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP redistribute route-map. */ struct { char *name; struct route_map *map; } rmap[AFI_MAX][ZEBRA_ROUTE_MAX]; /* BGP distance configuration. */ u_char distance_ebgp; u_char distance_ibgp; u_char distance_local; /* BGP default local-preference. */ u_int32_t default_local_pref; /* BGP default timer. */ u_int32_t default_holdtime; u_int32_t default_keepalive; /* BGP graceful restart */ u_int32_t restart_time; u_int32_t stalepath_time; /* Maximum-paths configuration */ struct bgp_maxpaths_cfg { u_int16_t maxpaths_ebgp; u_int16_t maxpaths_ibgp; } maxpaths[AFI_MAX][SAFI_MAX]; }; /* BGP peer-group support. */ struct peer_group { /* Name of the peer-group. */ char *name; /* Pointer to BGP. */ struct bgp *bgp; /* Peer-group client list. */ struct list *peer; /* Peer-group config */ struct peer *conf; }; /* BGP Notify message format. */ struct bgp_notify { u_char code; u_char subcode; char *data; bgp_size_t length; }; /* Next hop self address. */ struct bgp_nexthop { struct interface *ifp; struct in_addr v4; #ifdef HAVE_IPV6 struct in6_addr v6_global; struct in6_addr v6_local; #endif /* HAVE_IPV6 */ }; /* BGP router distinguisher value. */ #define BGP_RD_SIZE 8 struct bgp_rd { u_char val[BGP_RD_SIZE]; }; #define RMAP_IN 0 #define RMAP_OUT 1 #define RMAP_IMPORT 2 #define RMAP_EXPORT 3 #define RMAP_MAX 4 /* BGP filter structure. */ struct bgp_filter { /* Distribute-list. */ struct { char *name; struct access_list *alist; } dlist[FILTER_MAX]; /* Prefix-list. */ struct { char *name; struct prefix_list *plist; } plist[FILTER_MAX]; /* Filter-list. */ struct { char *name; struct as_list *aslist; } aslist[FILTER_MAX]; /* Route-map. */ struct { char *name; struct route_map *map; } map[RMAP_MAX]; /* Unsuppress-map. */ struct { char *name; struct route_map *map; } usmap; }; /* IBGP/EBGP identifier. We also have a CONFED peer, which is to say, a peer who's AS is part of our Confederation. */ typedef enum { BGP_PEER_IBGP = 1, BGP_PEER_EBGP, BGP_PEER_INTERNAL, BGP_PEER_CONFED, } bgp_peer_sort_t; /* BGP neighbor structure. */ struct peer { /* BGP structure. */ struct bgp *bgp; /* reference count, primarily to allow bgp_process'ing of route_node's * to be done after a struct peer is deleted. * * named 'lock' for hysterical reasons within Quagga. */ int lock; /* BGP peer group. */ struct peer_group *group; u_char af_group[AFI_MAX][SAFI_MAX]; /* Peer's remote AS number. */ as_t as; /* Peer's local AS number. */ as_t local_as; bgp_peer_sort_t sort; /* Peer's Change local AS number. */ as_t change_local_as; /* Remote router ID. */ struct in_addr remote_id; /* Local router ID. */ struct in_addr local_id; /* Peer specific RIB when configured as route-server-client. */ struct bgp_table *rib[AFI_MAX][SAFI_MAX]; /* Packet receive and send buffer. */ struct stream *ibuf; struct stream_fifo *obuf; struct stream *work; /* We use a separate stream to encode MP_REACH_NLRI for efficient * NLRI packing. peer->work stores all the other attributes. The * actual packet is then constructed by concatenating the two. */ struct stream *scratch; /* Status of the peer. */ int status; int ostatus; /* Peer index, used for dumping TABLE_DUMP_V2 format */ uint16_t table_dump_index; /* Peer information */ int fd; /* File descriptor */ int ttl; /* TTL of TCP connection to the peer. */ int gtsm_hops; /* minimum hopcount to peer */ char *desc; /* Description of the peer. */ unsigned short port; /* Destination port for peer */ char *host; /* Printable address of the peer. */ union sockunion su; /* Sockunion address of the peer. */ time_t uptime; /* Last Up/Down time */ time_t readtime; /* Last read time */ time_t resettime; /* Last reset time */ unsigned int ifindex; /* ifindex of the BGP connection. */ char *ifname; /* bind interface name. */ char *update_if; union sockunion *update_source; struct zlog *log; union sockunion *su_local; /* Sockunion of local address. */ union sockunion *su_remote; /* Sockunion of remote address. */ int shared_network; /* Is this peer shared same network. */ struct bgp_nexthop nexthop; /* Nexthop */ /* Peer address family configuration. */ u_char afc[AFI_MAX][SAFI_MAX]; u_char afc_nego[AFI_MAX][SAFI_MAX]; u_char afc_adv[AFI_MAX][SAFI_MAX]; u_char afc_recv[AFI_MAX][SAFI_MAX]; /* Capability flags (reset in bgp_stop) */ u_int16_t cap; #define PEER_CAP_REFRESH_ADV (1 << 0) /* refresh advertised */ #define PEER_CAP_REFRESH_OLD_RCV (1 << 1) /* refresh old received */ #define PEER_CAP_REFRESH_NEW_RCV (1 << 2) /* refresh rfc received */ #define PEER_CAP_DYNAMIC_ADV (1 << 3) /* dynamic advertised */ #define PEER_CAP_DYNAMIC_RCV (1 << 4) /* dynamic received */ #define PEER_CAP_RESTART_ADV (1 << 5) /* restart advertised */ #define PEER_CAP_RESTART_RCV (1 << 6) /* restart received */ #define PEER_CAP_AS4_ADV (1 << 7) /* as4 advertised */ #define PEER_CAP_AS4_RCV (1 << 8) /* as4 received */ #define PEER_CAP_RESTART_BIT_ADV (1 << 9) /* sent restart state */ #define PEER_CAP_RESTART_BIT_RCV (1 << 10) /* peer restart state */ /* Capability flags (reset in bgp_stop) */ u_int16_t af_cap[AFI_MAX][SAFI_MAX]; #define PEER_CAP_ORF_PREFIX_SM_ADV (1 << 0) /* send-mode advertised */ #define PEER_CAP_ORF_PREFIX_RM_ADV (1 << 1) /* receive-mode advertised */ #define PEER_CAP_ORF_PREFIX_SM_RCV (1 << 2) /* send-mode received */ #define PEER_CAP_ORF_PREFIX_RM_RCV (1 << 3) /* receive-mode received */ #define PEER_CAP_ORF_PREFIX_SM_OLD_RCV (1 << 4) /* send-mode received */ #define PEER_CAP_ORF_PREFIX_RM_OLD_RCV (1 << 5) /* receive-mode received */ #define PEER_CAP_RESTART_AF_RCV (1 << 6) /* graceful restart afi/safi received */ #define PEER_CAP_RESTART_AF_PRESERVE_RCV (1 << 7) /* graceful restart afi/safi F-bit received */ /* Global configuration flags. */ u_int32_t flags; #define PEER_FLAG_PASSIVE (1 << 0) /* passive mode */ #define PEER_FLAG_SHUTDOWN (1 << 1) /* shutdown */ #define PEER_FLAG_DONT_CAPABILITY (1 << 2) /* dont-capability */ #define PEER_FLAG_OVERRIDE_CAPABILITY (1 << 3) /* override-capability */ #define PEER_FLAG_STRICT_CAP_MATCH (1 << 4) /* strict-match */ #define PEER_FLAG_DYNAMIC_CAPABILITY (1 << 5) /* dynamic capability */ #define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */ #define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */ #define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */ /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; /* Per AF configuration flags. */ u_int32_t af_flags[AFI_MAX][SAFI_MAX]; #define PEER_FLAG_SEND_COMMUNITY (1 << 0) /* send-community */ #define PEER_FLAG_SEND_EXT_COMMUNITY (1 << 1) /* send-community ext. */ #define PEER_FLAG_NEXTHOP_SELF (1 << 2) /* next-hop-self */ #define PEER_FLAG_REFLECTOR_CLIENT (1 << 3) /* reflector-client */ #define PEER_FLAG_RSERVER_CLIENT (1 << 4) /* route-server-client */ #define PEER_FLAG_SOFT_RECONFIG (1 << 5) /* soft-reconfiguration */ #define PEER_FLAG_AS_PATH_UNCHANGED (1 << 6) /* transparent-as */ #define PEER_FLAG_NEXTHOP_UNCHANGED (1 << 7) /* transparent-next-hop */ #define PEER_FLAG_MED_UNCHANGED (1 << 8) /* transparent-next-hop */ #define PEER_FLAG_DEFAULT_ORIGINATE (1 << 9) /* default-originate */ #define PEER_FLAG_REMOVE_PRIVATE_AS (1 << 10) /* remove-private-as */ #define PEER_FLAG_ALLOWAS_IN (1 << 11) /* set allowas-in */ #define PEER_FLAG_ORF_PREFIX_SM (1 << 12) /* orf capability send-mode */ #define PEER_FLAG_ORF_PREFIX_RM (1 << 13) /* orf capability receive-mode */ #define PEER_FLAG_MAX_PREFIX (1 << 14) /* maximum prefix */ #define PEER_FLAG_MAX_PREFIX_WARNING (1 << 15) /* maximum prefix warning-only */ #define PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED (1 << 16) /* leave link-local nexthop unchanged */ #define PEER_FLAG_NEXTHOP_SELF_ALL (1 << 17) /* next-hop-self all */ /* MD5 password */ char *password; /* default-originate route-map. */ struct { char *name; struct route_map *map; } default_rmap[AFI_MAX][SAFI_MAX]; /* Peer status flags. */ u_int16_t sflags; #define PEER_STATUS_ACCEPT_PEER (1 << 0) /* accept peer */ #define PEER_STATUS_PREFIX_OVERFLOW (1 << 1) /* prefix-overflow */ #define PEER_STATUS_CAPABILITY_OPEN (1 << 2) /* capability open send */ #define PEER_STATUS_HAVE_ACCEPT (1 << 3) /* accept peer's parent */ #define PEER_STATUS_GROUP (1 << 4) /* peer-group conf */ #define PEER_STATUS_NSF_MODE (1 << 5) /* NSF aware peer */ #define PEER_STATUS_NSF_WAIT (1 << 6) /* wait comeback peer */ /* Peer status af flags (reset in bgp_stop) */ u_int16_t af_sflags[AFI_MAX][SAFI_MAX]; #define PEER_STATUS_ORF_PREFIX_SEND (1 << 0) /* prefix-list send peer */ #define PEER_STATUS_ORF_WAIT_REFRESH (1 << 1) /* wait refresh received peer */ #define PEER_STATUS_DEFAULT_ORIGINATE (1 << 2) /* default-originate peer */ #define PEER_STATUS_PREFIX_THRESHOLD (1 << 3) /* exceed prefix-threshold */ #define PEER_STATUS_PREFIX_LIMIT (1 << 4) /* exceed prefix-limit */ #define PEER_STATUS_EOR_SEND (1 << 5) /* end-of-rib send to peer */ #define PEER_STATUS_EOR_RECEIVED (1 << 6) /* end-of-rib received from peer */ /* Default attribute value for the peer. */ u_int32_t config; #define PEER_CONFIG_WEIGHT (1 << 0) /* Default weight. */ #define PEER_CONFIG_TIMER (1 << 1) /* keepalive & holdtime */ #define PEER_CONFIG_CONNECT (1 << 2) /* connect */ #define PEER_CONFIG_ROUTEADV (1 << 3) /* route advertise */ u_int32_t weight; u_int32_t holdtime; u_int32_t keepalive; u_int32_t connect; u_int32_t routeadv; /* Timer values. */ u_int32_t v_start; u_int32_t v_connect; u_int32_t v_holdtime; u_int32_t v_keepalive; u_int32_t v_asorig; u_int32_t v_routeadv; u_int32_t v_pmax_restart; u_int32_t v_gr_restart; /* Threads. */ struct thread *t_read; struct thread *t_write; struct thread *t_start; struct thread *t_connect; struct thread *t_holdtime; struct thread *t_keepalive; struct thread *t_asorig; struct thread *t_routeadv; struct thread *t_pmax_restart; struct thread *t_gr_restart; struct thread *t_gr_stale; /* workqueues */ struct work_queue *clear_node_queue; /* Statistics field */ u_int32_t open_in; /* Open message input count */ u_int32_t open_out; /* Open message output count */ u_int32_t update_in; /* Update message input count */ u_int32_t update_out; /* Update message ouput count */ time_t update_time; /* Update message received time. */ u_int32_t keepalive_in; /* Keepalive input count */ u_int32_t keepalive_out; /* Keepalive output count */ u_int32_t notify_in; /* Notify input count */ u_int32_t notify_out; /* Notify output count */ u_int32_t refresh_in; /* Route Refresh input count */ u_int32_t refresh_out; /* Route Refresh output count */ u_int32_t dynamic_cap_in; /* Dynamic Capability input count. */ u_int32_t dynamic_cap_out; /* Dynamic Capability output count. */ /* BGP state count */ u_int32_t established; /* Established */ u_int32_t dropped; /* Dropped */ /* Syncronization list and time. */ struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX]; time_t synctime; /* Send prefix count. */ unsigned long scount[AFI_MAX][SAFI_MAX]; /* Announcement attribute hash. */ struct hash *hash[AFI_MAX][SAFI_MAX]; /* Notify data. */ struct bgp_notify notify; /* Whole packet size to be read. */ unsigned long packet_size; /* Filter structure. */ struct bgp_filter filter[AFI_MAX][SAFI_MAX]; /* ORF Prefix-list */ struct prefix_list *orf_plist[AFI_MAX][SAFI_MAX]; /* Prefix count. */ unsigned long pcount[AFI_MAX][SAFI_MAX]; /* Max prefix count. */ unsigned long pmax[AFI_MAX][SAFI_MAX]; u_char pmax_threshold[AFI_MAX][SAFI_MAX]; u_int16_t pmax_restart[AFI_MAX][SAFI_MAX]; #define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75 /* allowas-in. */ char allowas_in[AFI_MAX][SAFI_MAX]; /* peer reset cause */ char last_reset; #define PEER_DOWN_RID_CHANGE 1 /* bgp router-id command */ #define PEER_DOWN_REMOTE_AS_CHANGE 2 /* neighbor remote-as command */ #define PEER_DOWN_LOCAL_AS_CHANGE 3 /* neighbor local-as command */ #define PEER_DOWN_CLID_CHANGE 4 /* bgp cluster-id command */ #define PEER_DOWN_CONFED_ID_CHANGE 5 /* bgp confederation identifier command */ #define PEER_DOWN_CONFED_PEER_CHANGE 6 /* bgp confederation peer command */ #define PEER_DOWN_RR_CLIENT_CHANGE 7 /* neighbor route-reflector-client command */ #define PEER_DOWN_RS_CLIENT_CHANGE 8 /* neighbor route-server-client command */ #define PEER_DOWN_UPDATE_SOURCE_CHANGE 9 /* neighbor update-source command */ #define PEER_DOWN_AF_ACTIVATE 10 /* neighbor activate command */ #define PEER_DOWN_USER_SHUTDOWN 11 /* neighbor shutdown command */ #define PEER_DOWN_USER_RESET 12 /* clear ip bgp command */ #define PEER_DOWN_NOTIFY_RECEIVED 13 /* notification received */ #define PEER_DOWN_NOTIFY_SEND 14 /* notification send */ #define PEER_DOWN_CLOSE_SESSION 15 /* tcp session close */ #define PEER_DOWN_NEIGHBOR_DELETE 16 /* neghbor delete */ #define PEER_DOWN_RMAP_BIND 17 /* neghbor peer-group command */ #define PEER_DOWN_RMAP_UNBIND 18 /* no neighbor peer-group command */ #define PEER_DOWN_CAPABILITY_CHANGE 19 /* neighbor capability command */ #define PEER_DOWN_PASSIVE_CHANGE 20 /* neighbor passive command */ #define PEER_DOWN_MULTIHOP_CHANGE 21 /* neighbor multihop command */ #define PEER_DOWN_NSF_CLOSE_SESSION 22 /* NSF tcp session close */ /* The kind of route-map Flags.*/ u_char rmap_type; #define PEER_RMAP_TYPE_IN (1 << 0) /* neighbor route-map in */ #define PEER_RMAP_TYPE_OUT (1 << 1) /* neighbor route-map out */ #define PEER_RMAP_TYPE_NETWORK (1 << 2) /* network route-map */ #define PEER_RMAP_TYPE_REDISTRIBUTE (1 << 3) /* redistribute route-map */ #define PEER_RMAP_TYPE_DEFAULT (1 << 4) /* default-originate route-map */ #define PEER_RMAP_TYPE_NOSET (1 << 5) /* not allow to set commands */ #define PEER_RMAP_TYPE_IMPORT (1 << 6) /* neighbor route-map import */ #define PEER_RMAP_TYPE_EXPORT (1 << 7) /* neighbor route-map export */ }; #define PEER_PASSWORD_MINLEN (1) #define PEER_PASSWORD_MAXLEN (80) /* This structure's member directly points incoming packet data stream. */ struct bgp_nlri { /* AFI. */ afi_t afi; /* SAFI. */ safi_t safi; /* Pointer to NLRI byte stream. */ u_char *nlri; /* Length of whole NLRI. */ bgp_size_t length; }; /* BGP versions. */ #define BGP_VERSION_4 4 /* Default BGP port number. */ #define BGP_PORT_DEFAULT 179 /* BGP message header and packet size. */ #define BGP_MARKER_SIZE 16 #define BGP_HEADER_SIZE 19 #define BGP_MAX_PACKET_SIZE 4096 /* BGP minimum message size. */ #define BGP_MSG_OPEN_MIN_SIZE (BGP_HEADER_SIZE + 10) #define BGP_MSG_UPDATE_MIN_SIZE (BGP_HEADER_SIZE + 4) #define BGP_MSG_NOTIFY_MIN_SIZE (BGP_HEADER_SIZE + 2) #define BGP_MSG_KEEPALIVE_MIN_SIZE (BGP_HEADER_SIZE + 0) #define BGP_MSG_ROUTE_REFRESH_MIN_SIZE (BGP_HEADER_SIZE + 4) #define BGP_MSG_CAPABILITY_MIN_SIZE (BGP_HEADER_SIZE + 3) /* BGP message types. */ #define BGP_MSG_OPEN 1 #define BGP_MSG_UPDATE 2 #define BGP_MSG_NOTIFY 3 #define BGP_MSG_KEEPALIVE 4 #define BGP_MSG_ROUTE_REFRESH_NEW 5 #define BGP_MSG_CAPABILITY 6 #define BGP_MSG_ROUTE_REFRESH_OLD 128 /* BGP open optional parameter. */ #define BGP_OPEN_OPT_AUTH 1 #define BGP_OPEN_OPT_CAP 2 /* BGP4 attribute type codes. */ #define BGP_ATTR_ORIGIN 1 #define BGP_ATTR_AS_PATH 2 #define BGP_ATTR_NEXT_HOP 3 #define BGP_ATTR_MULTI_EXIT_DISC 4 #define BGP_ATTR_LOCAL_PREF 5 #define BGP_ATTR_ATOMIC_AGGREGATE 6 #define BGP_ATTR_AGGREGATOR 7 #define BGP_ATTR_COMMUNITIES 8 #define BGP_ATTR_ORIGINATOR_ID 9 #define BGP_ATTR_CLUSTER_LIST 10 #define BGP_ATTR_DPA 11 #define BGP_ATTR_ADVERTISER 12 #define BGP_ATTR_RCID_PATH 13 #define BGP_ATTR_MP_REACH_NLRI 14 #define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_EXT_COMMUNITIES 16 #define BGP_ATTR_AS4_PATH 17 #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 #define BGP_ORIGIN_EGP 1 #define BGP_ORIGIN_INCOMPLETE 2 /* BGP notify message codes. */ #define BGP_NOTIFY_HEADER_ERR 1 #define BGP_NOTIFY_OPEN_ERR 2 #define BGP_NOTIFY_UPDATE_ERR 3 #define BGP_NOTIFY_HOLD_ERR 4 #define BGP_NOTIFY_FSM_ERR 5 #define BGP_NOTIFY_CEASE 6 #define BGP_NOTIFY_CAPABILITY_ERR 7 #define BGP_NOTIFY_MAX 8 #define BGP_NOTIFY_SUBCODE_UNSPECIFIC 0 /* BGP_NOTIFY_HEADER_ERR sub codes. */ #define BGP_NOTIFY_HEADER_NOT_SYNC 1 #define BGP_NOTIFY_HEADER_BAD_MESLEN 2 #define BGP_NOTIFY_HEADER_BAD_MESTYPE 3 #define BGP_NOTIFY_HEADER_MAX 4 /* BGP_NOTIFY_OPEN_ERR sub codes. */ #define BGP_NOTIFY_OPEN_UNSUP_VERSION 1 #define BGP_NOTIFY_OPEN_BAD_PEER_AS 2 #define BGP_NOTIFY_OPEN_BAD_BGP_IDENT 3 #define BGP_NOTIFY_OPEN_UNSUP_PARAM 4 #define BGP_NOTIFY_OPEN_AUTH_FAILURE 5 #define BGP_NOTIFY_OPEN_UNACEP_HOLDTIME 6 #define BGP_NOTIFY_OPEN_UNSUP_CAPBL 7 #define BGP_NOTIFY_OPEN_MAX 8 /* BGP_NOTIFY_UPDATE_ERR sub codes. */ #define BGP_NOTIFY_UPDATE_MAL_ATTR 1 #define BGP_NOTIFY_UPDATE_UNREC_ATTR 2 #define BGP_NOTIFY_UPDATE_MISS_ATTR 3 #define BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR 4 #define BGP_NOTIFY_UPDATE_ATTR_LENG_ERR 5 #define BGP_NOTIFY_UPDATE_INVAL_ORIGIN 6 #define BGP_NOTIFY_UPDATE_AS_ROUTE_LOOP 7 #define BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP 8 #define BGP_NOTIFY_UPDATE_OPT_ATTR_ERR 9 #define BGP_NOTIFY_UPDATE_INVAL_NETWORK 10 #define BGP_NOTIFY_UPDATE_MAL_AS_PATH 11 #define BGP_NOTIFY_UPDATE_MAX 12 /* BGP_NOTIFY_CEASE sub codes (RFC 4486). */ #define BGP_NOTIFY_CEASE_MAX_PREFIX 1 #define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN 2 #define BGP_NOTIFY_CEASE_PEER_UNCONFIG 3 #define BGP_NOTIFY_CEASE_ADMIN_RESET 4 #define BGP_NOTIFY_CEASE_CONNECT_REJECT 5 #define BGP_NOTIFY_CEASE_CONFIG_CHANGE 6 #define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION 7 #define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE 8 #define BGP_NOTIFY_CEASE_MAX 9 /* BGP_NOTIFY_CAPABILITY_ERR sub codes (draft-ietf-idr-dynamic-cap-02). */ #define BGP_NOTIFY_CAPABILITY_INVALID_ACTION 1 #define BGP_NOTIFY_CAPABILITY_INVALID_LENGTH 2 #define BGP_NOTIFY_CAPABILITY_MALFORMED_CODE 3 #define BGP_NOTIFY_CAPABILITY_MAX 4 /* BGP finite state machine status. */ #define Idle 1 #define Connect 2 #define Active 3 #define OpenSent 4 #define OpenConfirm 5 #define Established 6 #define Clearing 7 #define Deleted 8 #define BGP_STATUS_MAX 9 /* BGP finite state machine events. */ #define BGP_Start 1 #define BGP_Stop 2 #define TCP_connection_open 3 #define TCP_connection_closed 4 #define TCP_connection_open_failed 5 #define TCP_fatal_error 6 #define ConnectRetry_timer_expired 7 #define Hold_Timer_expired 8 #define KeepAlive_timer_expired 9 #define Receive_OPEN_message 10 #define Receive_KEEPALIVE_message 11 #define Receive_UPDATE_message 12 #define Receive_NOTIFICATION_message 13 #define Clearing_Completed 14 #define BGP_EVENTS_MAX 15 /* BGP timers default value. */ #define BGP_INIT_START_TIMER 5 #define BGP_ERROR_START_TIMER 30 #define BGP_DEFAULT_HOLDTIME 180 #define BGP_DEFAULT_KEEPALIVE 60 #define BGP_DEFAULT_ASORIGINATE 15 #define BGP_DEFAULT_EBGP_ROUTEADV 30 #define BGP_DEFAULT_IBGP_ROUTEADV 5 #define BGP_CLEAR_CONNECT_RETRY 20 #define BGP_DEFAULT_CONNECT_RETRY 120 /* BGP default local preference. */ #define BGP_DEFAULT_LOCAL_PREF 100 /* BGP graceful restart */ #define BGP_DEFAULT_RESTART_TIME 120 #define BGP_DEFAULT_STALEPATH_TIME 360 /* RFC4364 */ #define SAFI_MPLS_LABELED_VPN 128 /* Max TTL value. */ #define TTL_MAX 255 /* BGP uptime string length. */ #define BGP_UPTIME_LEN 25 /* Default configuration settings for bgpd. */ #define BGP_VTY_PORT 2605 #define BGP_DEFAULT_CONFIG "bgpd.conf" /* Check AS path loop when we send NLRI. */ /* #define BGP_SEND_ASPATH_CHECK */ /* Flag for peer_clear_soft(). */ enum bgp_clear_type { BGP_CLEAR_SOFT_NONE, BGP_CLEAR_SOFT_OUT, BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_BOTH, BGP_CLEAR_SOFT_IN_ORF_PREFIX, BGP_CLEAR_SOFT_RSCLIENT }; /* Macros. */ #define BGP_INPUT(P) ((P)->ibuf) #define BGP_INPUT_PNT(P) (STREAM_PNT(BGP_INPUT(P))) #define BGP_IS_VALID_STATE_FOR_NOTIF(S)\ (((S) == OpenSent) || ((S) == OpenConfirm) || ((S) == Established)) /* Count prefix size from mask length */ #define PSIZE(a) (((a) + 7) / (8)) /* BGP error codes. */ #define BGP_SUCCESS 0 #define BGP_ERR_INVALID_VALUE -1 #define BGP_ERR_INVALID_FLAG -2 #define BGP_ERR_INVALID_AS -3 #define BGP_ERR_INVALID_BGP -4 #define BGP_ERR_PEER_GROUP_MEMBER -5 #define BGP_ERR_MULTIPLE_INSTANCE_USED -6 #define BGP_ERR_PEER_GROUP_MEMBER_EXISTS -7 #define BGP_ERR_PEER_BELONGS_TO_GROUP -8 #define BGP_ERR_PEER_GROUP_AF_UNCONFIGURED -9 #define BGP_ERR_PEER_GROUP_NO_REMOTE_AS -10 #define BGP_ERR_PEER_GROUP_CANT_CHANGE -11 #define BGP_ERR_PEER_GROUP_MISMATCH -12 #define BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT -13 #define BGP_ERR_MULTIPLE_INSTANCE_NOT_SET -14 #define BGP_ERR_AS_MISMATCH -15 #define BGP_ERR_PEER_INACTIVE -16 #define BGP_ERR_INVALID_FOR_PEER_GROUP_MEMBER -17 #define BGP_ERR_PEER_GROUP_HAS_THE_FLAG -18 #define BGP_ERR_PEER_FLAG_CONFLICT -19 #define BGP_ERR_PEER_GROUP_SHUTDOWN -20 #define BGP_ERR_PEER_FILTER_CONFLICT -21 #define BGP_ERR_NOT_INTERNAL_PEER -22 #define BGP_ERR_REMOVE_PRIVATE_AS -23 #define BGP_ERR_AF_UNCONFIGURED -24 #define BGP_ERR_SOFT_RECONFIG_UNCONFIGURED -25 #define BGP_ERR_INSTANCE_MISMATCH -26 #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP -27 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS -28 #define BGP_ERR_TCPSIG_FAILED -29 #define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK -30 #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 #define BGP_ERR_MAX -32 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33 extern struct bgp_master *bm; extern struct thread_master *master; /* Prototypes. */ extern void bgp_terminate (void); extern void bgp_reset (void); extern time_t bgp_clock (void); extern void bgp_zclient_reset (void); extern int bgp_nexthop_set (union sockunion *, union sockunion *, struct bgp_nexthop *, struct peer *); extern struct bgp *bgp_get_default (void); extern struct bgp *bgp_lookup (as_t, const char *); extern struct bgp *bgp_lookup_by_name (const char *); extern struct peer *peer_lookup (struct bgp *, union sockunion *); extern struct peer_group *peer_group_lookup (struct bgp *, const char *); extern struct peer_group *peer_group_get (struct bgp *, const char *); extern struct peer *peer_lookup_with_open (union sockunion *, as_t, struct in_addr *, int *); extern struct peer *peer_lock (struct peer *); extern struct peer *peer_unlock (struct peer *); extern bgp_peer_sort_t peer_sort (struct peer *peer); extern int peer_active (struct peer *); extern int peer_active_nego (struct peer *); extern struct peer *peer_create_accept (struct bgp *); extern char *peer_uptime (time_t, char *, size_t); extern int bgp_config_write (struct vty *); extern void bgp_config_write_family_header (struct vty *, afi_t, safi_t, int *); extern void bgp_master_init (void); extern void bgp_init (void); extern void bgp_route_map_init (void); extern int bgp_option_set (int); extern int bgp_option_unset (int); extern int bgp_option_check (int); extern int bgp_get (struct bgp **, as_t *, const char *); extern int bgp_delete (struct bgp *); extern int bgp_flag_set (struct bgp *, int); extern int bgp_flag_unset (struct bgp *, int); extern int bgp_flag_check (struct bgp *, int); extern void bgp_lock (struct bgp *); extern void bgp_unlock (struct bgp *); extern int bgp_router_id_set (struct bgp *, struct in_addr *); extern int bgp_cluster_id_set (struct bgp *, struct in_addr *); extern int bgp_cluster_id_unset (struct bgp *); extern int bgp_confederation_id_set (struct bgp *, as_t); extern int bgp_confederation_id_unset (struct bgp *); extern int bgp_confederation_peers_check (struct bgp *, as_t); extern int bgp_confederation_peers_add (struct bgp *, as_t); extern int bgp_confederation_peers_remove (struct bgp *, as_t); extern int bgp_timers_set (struct bgp *, u_int32_t, u_int32_t); extern int bgp_timers_unset (struct bgp *); extern int bgp_default_local_preference_set (struct bgp *, u_int32_t); extern int bgp_default_local_preference_unset (struct bgp *); extern int peer_rsclient_active (struct peer *); extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); extern int peer_group_remote_as (struct bgp *, const char *, as_t *); extern int peer_delete (struct peer *peer); extern int peer_group_delete (struct peer_group *); extern int peer_group_remote_as_delete (struct peer_group *); extern int peer_activate (struct peer *, afi_t, safi_t); extern int peer_deactivate (struct peer *, afi_t, safi_t); extern int peer_group_bind (struct bgp *, union sockunion *, struct peer_group *, afi_t, safi_t, as_t *); extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *, afi_t, safi_t); extern int peer_flag_set (struct peer *, u_int32_t); extern int peer_flag_unset (struct peer *, u_int32_t); extern int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_ebgp_multihop_set (struct peer *, int); extern int peer_ebgp_multihop_unset (struct peer *); extern int peer_description_set (struct peer *, char *); extern int peer_description_unset (struct peer *); extern int peer_update_source_if_set (struct peer *, const char *); extern int peer_update_source_addr_set (struct peer *, union sockunion *); extern int peer_update_source_unset (struct peer *); extern int peer_default_originate_set (struct peer *, afi_t, safi_t, const char *); extern int peer_default_originate_unset (struct peer *, afi_t, safi_t); extern int peer_port_set (struct peer *, u_int16_t); extern int peer_port_unset (struct peer *); extern int peer_weight_set (struct peer *, u_int16_t); extern int peer_weight_unset (struct peer *); extern int peer_timers_set (struct peer *, u_int32_t, u_int32_t); extern int peer_timers_unset (struct peer *); extern int peer_timers_connect_set (struct peer *, u_int32_t); extern int peer_timers_connect_unset (struct peer *); extern int peer_advertise_interval_set (struct peer *, u_int32_t); extern int peer_advertise_interval_unset (struct peer *); extern int peer_interface_set (struct peer *, const char *); extern int peer_interface_unset (struct peer *); extern int peer_distribute_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_distribute_unset (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_set (struct peer *, afi_t, safi_t, int); extern int peer_allowas_in_unset (struct peer *, afi_t, safi_t); extern int peer_local_as_set (struct peer *, as_t, int, int); extern int peer_local_as_unset (struct peer *); extern int peer_prefix_list_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_prefix_list_unset (struct peer *, afi_t, safi_t, int); extern int peer_aslist_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_aslist_unset (struct peer *,afi_t, safi_t, int); extern int peer_route_map_set (struct peer *, afi_t, safi_t, int, const char *); extern int peer_route_map_unset (struct peer *, afi_t, safi_t, int); extern int peer_unsuppress_map_set (struct peer *, afi_t, safi_t, const char *); extern int peer_password_set (struct peer *, const char *); extern int peer_password_unset (struct peer *); extern int peer_unsuppress_map_unset (struct peer *, afi_t, safi_t); extern int peer_maximum_prefix_set (struct peer *, afi_t, safi_t, u_int32_t, u_char, int, u_int16_t); extern int peer_maximum_prefix_unset (struct peer *, afi_t, safi_t); extern int peer_clear (struct peer *); extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); extern int peer_ttl_security_hops_unset (struct peer *); #endif /* _QUAGGA_BGPD_H */ quagga-0.99.24.1/bgpd/bgp_route.h0000644000175000017500000002055212476520570013313 00000000000000/* BGP routing information base Copyright (C) 1996, 97, 98, 2000 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ROUTE_H #define _QUAGGA_BGP_ROUTE_H #include "bgp_table.h" /* Ancillary information to struct bgp_info, * used for uncommonly used data (aggregation, MPLS, etc.) * and lazily allocated to save memory. */ struct bgp_info_extra { /* Pointer to dampening structure. */ struct bgp_damp_info *damp_info; /* This route is suppressed with aggregation. */ int suppress; /* Nexthop reachability check. */ u_int32_t igpmetric; /* MPLS label. */ u_char tag[3]; }; struct bgp_info { /* For linked list. */ struct bgp_info *next; struct bgp_info *prev; /* Peer structure. */ struct peer *peer; /* Attribute structure. */ struct attr *attr; /* Extra information */ struct bgp_info_extra *extra; /* Multipath information */ struct bgp_info_mpath *mpath; /* Uptime. */ time_t uptime; /* reference count */ int lock; /* BGP information status. */ u_int16_t flags; #define BGP_INFO_IGP_CHANGED (1 << 0) #define BGP_INFO_DAMPED (1 << 1) #define BGP_INFO_HISTORY (1 << 2) #define BGP_INFO_SELECTED (1 << 3) #define BGP_INFO_VALID (1 << 4) #define BGP_INFO_ATTR_CHANGED (1 << 5) #define BGP_INFO_DMED_CHECK (1 << 6) #define BGP_INFO_DMED_SELECTED (1 << 7) #define BGP_INFO_STALE (1 << 8) #define BGP_INFO_REMOVED (1 << 9) #define BGP_INFO_COUNTED (1 << 10) #define BGP_INFO_MULTIPATH (1 << 11) #define BGP_INFO_MULTIPATH_CHG (1 << 12) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ u_char type; /* When above type is BGP. This sub type specify BGP sub type information. */ u_char sub_type; #define BGP_ROUTE_NORMAL 0 #define BGP_ROUTE_STATIC 1 #define BGP_ROUTE_AGGREGATE 2 #define BGP_ROUTE_REDISTRIBUTE 3 }; /* BGP static route configuration. */ struct bgp_static { /* Backdoor configuration. */ int backdoor; /* Import check status. */ u_char valid; /* IGP metric. */ u_int32_t igpmetric; /* IGP nexthop. */ struct in_addr igpnexthop; /* Atomic set reference count (ie cause of pathlimit) */ u_int32_t atomic; /* BGP redistribute route-map. */ struct { char *name; struct route_map *map; } rmap; /* MPLS label. */ u_char tag[3]; }; /* Flags which indicate a route is unuseable in some form */ #define BGP_INFO_UNUSEABLE \ (BGP_INFO_HISTORY|BGP_INFO_DAMPED|BGP_INFO_REMOVED) /* Macro to check BGP information is alive or not. Sadly, * not equivalent to just checking previous, because of the * sense of the additional VALID flag. */ #define BGP_INFO_HOLDDOWN(BI) \ (! CHECK_FLAG ((BI)->flags, BGP_INFO_VALID) \ || CHECK_FLAG ((BI)->flags, BGP_INFO_UNUSEABLE)) #define DISTRIBUTE_IN_NAME(F) ((F)->dlist[FILTER_IN].name) #define DISTRIBUTE_IN(F) ((F)->dlist[FILTER_IN].alist) #define DISTRIBUTE_OUT_NAME(F) ((F)->dlist[FILTER_OUT].name) #define DISTRIBUTE_OUT(F) ((F)->dlist[FILTER_OUT].alist) #define PREFIX_LIST_IN_NAME(F) ((F)->plist[FILTER_IN].name) #define PREFIX_LIST_IN(F) ((F)->plist[FILTER_IN].plist) #define PREFIX_LIST_OUT_NAME(F) ((F)->plist[FILTER_OUT].name) #define PREFIX_LIST_OUT(F) ((F)->plist[FILTER_OUT].plist) #define FILTER_LIST_IN_NAME(F) ((F)->aslist[FILTER_IN].name) #define FILTER_LIST_IN(F) ((F)->aslist[FILTER_IN].aslist) #define FILTER_LIST_OUT_NAME(F) ((F)->aslist[FILTER_OUT].name) #define FILTER_LIST_OUT(F) ((F)->aslist[FILTER_OUT].aslist) #define ROUTE_MAP_IN_NAME(F) ((F)->map[RMAP_IN].name) #define ROUTE_MAP_IN(F) ((F)->map[RMAP_IN].map) #define ROUTE_MAP_OUT_NAME(F) ((F)->map[RMAP_OUT].name) #define ROUTE_MAP_OUT(F) ((F)->map[RMAP_OUT].map) #define ROUTE_MAP_IMPORT_NAME(F) ((F)->map[RMAP_IMPORT].name) #define ROUTE_MAP_IMPORT(F) ((F)->map[RMAP_IMPORT].map) #define ROUTE_MAP_EXPORT_NAME(F) ((F)->map[RMAP_EXPORT].name) #define ROUTE_MAP_EXPORT(F) ((F)->map[RMAP_EXPORT].map) #define UNSUPPRESS_MAP_NAME(F) ((F)->usmap.name) #define UNSUPPRESS_MAP(F) ((F)->usmap.map) enum bgp_clear_route_type { BGP_CLEAR_ROUTE_NORMAL, BGP_CLEAR_ROUTE_MY_RSCLIENT }; /* Prototypes. */ extern void bgp_route_init (void); extern void bgp_route_finish (void); extern void bgp_cleanup_routes (void); extern void bgp_announce_route (struct peer *, afi_t, safi_t); extern void bgp_announce_route_all (struct peer *); extern void bgp_default_originate (struct peer *, afi_t, safi_t, int); extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t); extern void bgp_soft_reconfig_rsclient (struct peer *, afi_t, safi_t); extern void bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi); extern void bgp_clear_route (struct peer *, afi_t, safi_t, enum bgp_clear_route_type); extern void bgp_clear_route_all (struct peer *); extern void bgp_clear_adj_in (struct peer *, afi_t, safi_t); extern void bgp_clear_stale_route (struct peer *, afi_t, safi_t); extern struct bgp_info *bgp_info_lock (struct bgp_info *); extern struct bgp_info *bgp_info_unlock (struct bgp_info *); extern void bgp_info_add (struct bgp_node *rn, struct bgp_info *ri); extern void bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri); extern struct bgp_info_extra *bgp_info_extra_get (struct bgp_info *); extern void bgp_info_set_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern void bgp_info_unset_flag (struct bgp_node *, struct bgp_info *, u_int32_t); extern int bgp_nlri_sanity_check (struct peer *, int, u_char *, bgp_size_t); extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *); extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, const struct in6_addr *, u_int32_t, u_char); extern void bgp_redistribute_delete (struct prefix *, u_char); extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); extern void bgp_static_delete (struct bgp *); extern void bgp_static_update (struct bgp *, struct prefix *, struct bgp_static *, afi_t, safi_t); extern void bgp_static_withdraw (struct bgp *, struct prefix *, afi_t, safi_t); extern int bgp_static_set_vpnv4 (struct vty *vty, const char *, const char *, const char *); extern int bgp_static_unset_vpnv4 (struct vty *, const char *, const char *, const char *); /* this is primarily for MPLS-VPN */ extern int bgp_update (struct peer *, struct prefix *, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, u_char *, int); extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *, afi_t, safi_t, int, int, struct prefix_rd *, u_char *); /* for bgp_nexthop and bgp_damp */ extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); extern int bgp_config_write_network (struct vty *, struct bgp *, afi_t, safi_t, int *); extern int bgp_config_write_distance (struct vty *, struct bgp *); extern void bgp_aggregate_increment (struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); extern void bgp_aggregate_decrement (struct bgp *, struct prefix *, struct bgp_info *, afi_t, safi_t); extern u_char bgp_distance_apply (struct prefix *, struct bgp_info *, struct bgp *); extern afi_t bgp_node_afi (struct vty *); extern safi_t bgp_node_safi (struct vty *); extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t); extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t); #endif /* _QUAGGA_BGP_ROUTE_H */ quagga-0.99.24.1/bgpd/bgp_regex.h0000644000175000017500000000233712476520570013270 00000000000000/* AS regular expression routine Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_REGEX_H #define _QUAGGA_BGP_REGEX_H #include #ifdef HAVE_LIBPCREPOSIX # include #else # ifdef HAVE_GNU_REGEX # include # else # include "regex-gnu.h" # endif /* HAVE_GNU_REGEX */ #endif /* HAVE_LIBPCREPOSIX */ extern void bgp_regex_free (regex_t *regex); extern regex_t *bgp_regcomp (const char *str); extern int bgp_regexec (regex_t *regex, struct aspath *aspath); #endif /* _QUAGGA_BGP_REGEX_H */ quagga-0.99.24.1/bgpd/bgp_packet.h0000644000175000017500000000414212476520570013421 00000000000000/* BGP packet management header. Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_PACKET_H #define _QUAGGA_BGP_PACKET_H #define BGP_NLRI_LENGTH 1U #define BGP_TOTAL_ATTR_LEN 2U #define BGP_UNFEASIBLE_LEN 2U #define BGP_WRITE_PACKET_MAX 10U /* When to refresh */ #define REFRESH_IMMEDIATE 1 #define REFRESH_DEFER 2 /* ORF Common part flag */ #define ORF_COMMON_PART_ADD 0x00 #define ORF_COMMON_PART_REMOVE 0x80 #define ORF_COMMON_PART_REMOVE_ALL 0xC0 #define ORF_COMMON_PART_PERMIT 0x00 #define ORF_COMMON_PART_DENY 0x20 /* Packet send and receive function prototypes. */ extern int bgp_read (struct thread *); extern int bgp_write (struct thread *); extern void bgp_keepalive_send (struct peer *); extern void bgp_open_send (struct peer *); extern void bgp_notify_send (struct peer *, u_int8_t, u_int8_t); extern void bgp_notify_send_with_data (struct peer *, u_int8_t, u_int8_t, u_int8_t *, size_t); extern void bgp_route_refresh_send (struct peer *, afi_t, safi_t, u_char, u_char, int); extern void bgp_capability_send (struct peer *, afi_t, safi_t, int, int); extern void bgp_default_update_send (struct peer *, struct attr *, afi_t, safi_t, struct peer *); extern void bgp_default_withdraw_send (struct peer *, afi_t, safi_t); extern int bgp_capability_receive (struct peer *, bgp_size_t); #endif /* _QUAGGA_BGP_PACKET_H */ quagga-0.99.24.1/bgpd/bgp_open.h0000644000175000017500000000625112476520570013116 00000000000000/* BGP open message handling Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_OPEN_H #define _QUAGGA_BGP_OPEN_H /* Standard header for capability TLV */ struct capability_header { u_char code; u_char length; }; /* Generic MP capability data */ struct capability_mp_data { afi_t afi; u_char reserved; safi_t safi; }; #pragma pack(1) struct capability_orf_entry { struct capability_mp_data mpc; u_char num; struct { u_char type; u_char mode; } orfs[]; } __attribute__ ((packed)); #pragma pack() struct capability_as4 { uint32_t as4; }; struct graceful_restart_af { afi_t afi; safi_t safi; u_char flag; }; struct capability_gr { u_int16_t restart_flag_time; struct graceful_restart_af gr[]; }; /* Capability Code */ #define CAPABILITY_CODE_MP 1 /* Multiprotocol Extensions */ #define CAPABILITY_CODE_REFRESH 2 /* Route Refresh Capability */ #define CAPABILITY_CODE_ORF 3 /* Cooperative Route Filtering Capability */ #define CAPABILITY_CODE_RESTART 64 /* Graceful Restart Capability */ #define CAPABILITY_CODE_AS4 65 /* 4-octet AS number Capability */ #define CAPABILITY_CODE_DYNAMIC 66 /* Dynamic Capability */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ #define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 #define CAPABILITY_CODE_REFRESH_LEN 0 #define CAPABILITY_CODE_DYNAMIC_LEN 0 #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ #define CAPABILITY_CODE_AS4_LEN 4 /* Cooperative Route Filtering Capability. */ /* ORF Type */ #define ORF_TYPE_PREFIX 64 #define ORF_TYPE_PREFIX_OLD 128 /* ORF Mode */ #define ORF_MODE_RECEIVE 1 #define ORF_MODE_SEND 2 #define ORF_MODE_BOTH 3 /* Capability Message Action. */ #define CAPABILITY_ACTION_SET 0 #define CAPABILITY_ACTION_UNSET 1 /* Graceful Restart */ #define RESTART_R_BIT 0x8000 #define RESTART_F_BIT 0x80 extern int bgp_open_option_parse (struct peer *, u_char, int *); extern void bgp_open_capability (struct stream *, struct peer *); extern void bgp_capability_vty_out (struct vty *, struct peer *); extern as_t peek_for_as4_capability (struct peer *, u_char); extern int bgp_afi_safi_valid_indices (afi_t, safi_t *); #endif /* _QUAGGA_BGP_OPEN_H */ quagga-0.99.24.1/bgpd/bgp_network.h0000644000175000017500000000215212476520570013642 00000000000000/* BGP network related header Copyright (C) 1999 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_NETWORK_H #define _QUAGGA_BGP_NETWORK_H #define BGP_SOCKET_SNDBUF_SIZE 65536 extern int bgp_socket (unsigned short, const char *); extern void bgp_close (void); extern int bgp_connect (struct peer *); extern void bgp_getsockname (struct peer *); extern int bgp_md5_set (struct peer *); #endif /* _QUAGGA_BGP_NETWORK_H */ quagga-0.99.24.1/bgpd/bgp_fsm.h0000644000175000017500000000435512476520570012745 00000000000000/* BGP-4 Finite State Machine From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] Copyright (C) 1998 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_FSM_H #define _QUAGGA_BGP_FSM_H /* Macro for BGP read, write and timer thread. */ #define BGP_READ_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_READ_ON(master,T,F,peer,V); \ } while (0) #define BGP_READ_OFF(T) \ do { \ if (T) \ THREAD_READ_OFF(T); \ } while (0) #define BGP_WRITE_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_WRITE_ON(master,(T),(F),peer,(V)); \ } while (0) #define BGP_WRITE_OFF(T) \ do { \ if (T) \ THREAD_WRITE_OFF(T); \ } while (0) #define BGP_TIMER_ON(T,F,V) \ do { \ if (!(T) && (peer->status != Deleted)) \ THREAD_TIMER_ON(master,(T),(F),peer,(V)); \ } while (0) #define BGP_TIMER_OFF(T) \ do { \ if (T) \ THREAD_TIMER_OFF(T); \ } while (0) #define BGP_EVENT_ADD(P,E) \ do { \ if ((P)->status != Deleted) \ thread_add_event (master, bgp_event, (P), (E)); \ } while (0) #define BGP_EVENT_FLUSH(P) \ do { \ assert (peer); \ thread_cancel_event (master, (P)); \ } while (0) /* Prototypes. */ extern int bgp_event (struct thread *); extern int bgp_stop (struct peer *peer); extern void bgp_timer_set (struct peer *); extern void bgp_fsm_change_status (struct peer *peer, int status); extern const char *peer_down_str[]; #endif /* _QUAGGA_BGP_FSM_H */ quagga-0.99.24.1/bgpd/bgp_debug.h0000644000175000017500000000752312476520570013246 00000000000000/* BGP message debug header. Copyright (C) 1996, 97, 98 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H #include "bgp_attr.h" /* sort of packet direction */ #define DUMP_ON 1 #define DUMP_SEND 2 #define DUMP_RECV 4 /* for dump_update */ #define DUMP_WITHDRAW 8 #define DUMP_NLRI 16 /* dump detail */ #define DUMP_DETAIL 32 extern int dump_open; extern int dump_update; extern int dump_keepalive; extern int dump_notify; extern int Debug_Event; extern int Debug_Keepalive; extern int Debug_Update; extern int Debug_Radix; #define NLRI 1 #define WITHDRAW 2 #define NO_OPT 3 #define SEND 4 #define RECV 5 #define DETAIL 6 /* Prototypes. */ extern void bgp_debug_init (void); extern void bgp_packet_dump (struct stream *); extern int debug (unsigned int option); extern unsigned long conf_bgp_debug_as4; extern unsigned long conf_bgp_debug_fsm; extern unsigned long conf_bgp_debug_events; extern unsigned long conf_bgp_debug_packet; extern unsigned long conf_bgp_debug_filter; extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_normal; extern unsigned long conf_bgp_debug_zebra; extern unsigned long term_bgp_debug_as4; extern unsigned long term_bgp_debug_fsm; extern unsigned long term_bgp_debug_events; extern unsigned long term_bgp_debug_packet; extern unsigned long term_bgp_debug_filter; extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_normal; extern unsigned long term_bgp_debug_zebra; #define BGP_DEBUG_AS4 0x01 #define BGP_DEBUG_AS4_SEGMENT 0x02 #define BGP_DEBUG_FSM 0x01 #define BGP_DEBUG_EVENTS 0x01 #define BGP_DEBUG_PACKET 0x01 #define BGP_DEBUG_FILTER 0x01 #define BGP_DEBUG_KEEPALIVE 0x01 #define BGP_DEBUG_UPDATE_IN 0x01 #define BGP_DEBUG_UPDATE_OUT 0x02 #define BGP_DEBUG_NORMAL 0x01 #define BGP_DEBUG_ZEBRA 0x01 #define BGP_DEBUG_PACKET_SEND 0x01 #define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 #define BGP_DEBUG_PACKET_RECV 0x01 #define BGP_DEBUG_PACKET_RECV_DETAIL 0x02 #define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) #define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) #define TERM_DEBUG_ON(a, b) (term_bgp_debug_ ## a |= (BGP_DEBUG_ ## b)) #define TERM_DEBUG_OFF(a, b) (term_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b)) #define DEBUG_ON(a, b) \ do { \ CONF_DEBUG_ON(a, b); \ TERM_DEBUG_ON(a, b); \ } while (0) #define DEBUG_OFF(a, b) \ do { \ CONF_DEBUG_OFF(a, b); \ TERM_DEBUG_OFF(a, b); \ } while (0) #define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) #define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) extern const char *bgp_type_str[]; extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t); extern void bgp_notify_print (struct peer *, struct bgp_notify *, const char *); extern const struct message bgp_status_msg[]; extern const int bgp_status_msg_max; #endif /* _QUAGGA_BGP_DEBUG_H */ quagga-0.99.24.1/bgpd/bgp_community.h0000644000175000017500000000555712476520570014211 00000000000000/* Community attribute related functions. Copyright (C) 1998 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_COMMUNITY_H #define _QUAGGA_BGP_COMMUNITY_H /* Communities attribute. */ struct community { /* Reference count of communities value. */ unsigned long refcnt; /* Communities value size. */ int size; /* Communities value. */ u_int32_t *val; /* String of community attribute. This sring is used by vty output and expanded community-list for regular expression match. */ char *str; }; /* Well-known communities value. */ #define COMMUNITY_INTERNET 0x0 #define COMMUNITY_NO_EXPORT 0xFFFFFF01 #define COMMUNITY_NO_ADVERTISE 0xFFFFFF02 #define COMMUNITY_NO_EXPORT_SUBCONFED 0xFFFFFF03 #define COMMUNITY_LOCAL_AS 0xFFFFFF03 /* Macros of community attribute. */ #define com_length(X) ((X)->size * 4) #define com_lastval(X) ((X)->val + (X)->size - 1) #define com_nthval(X,n) ((X)->val + (n)) /* Prototypes of communities attribute functions. */ extern void community_init (void); extern void community_finish (void); extern void community_free (struct community *); extern struct community *community_uniq_sort (struct community *); extern struct community *community_parse (u_int32_t *, u_short); extern struct community *community_intern (struct community *); extern void community_unintern (struct community **); extern char *community_str (struct community *); extern unsigned int community_hash_make (struct community *); extern struct community *community_str2com (const char *); extern int community_match (const struct community *, const struct community *); extern int community_cmp (const struct community *, const struct community *); extern struct community *community_merge (struct community *, struct community *); extern struct community *community_delete (struct community *, struct community *); extern struct community *community_dup (struct community *); extern int community_include (struct community *, u_int32_t); extern void community_del_val (struct community *, u_int32_t *); extern unsigned long community_count (void); extern struct hash *community_hash (void); #endif /* _QUAGGA_BGP_COMMUNITY_H */ quagga-0.99.24.1/bgpd/bgp_attr.h0000644000175000017500000001542212476520570013127 00000000000000/* BGP attributes. Copyright (C) 1996, 97, 98 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ATTR_H #define _QUAGGA_BGP_ATTR_H /* Simple bit mapping. */ #define BITMAP_NBBY 8 #define SET_BITMAP(MAP, NUM) \ SET_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) #define CHECK_BITMAP(MAP, NUM) \ CHECK_FLAG (MAP[(NUM) / BITMAP_NBBY], 1 << ((NUM) % BITMAP_NBBY)) #define BGP_MED_MAX UINT32_MAX /* BGP Attribute type range. */ #define BGP_ATTR_TYPE_RANGE 256 #define BGP_ATTR_BITMAP_SIZE (BGP_ATTR_TYPE_RANGE / BITMAP_NBBY) /* BGP Attribute flags. */ #define BGP_ATTR_FLAG_OPTIONAL 0x80 /* Attribute is optional. */ #define BGP_ATTR_FLAG_TRANS 0x40 /* Attribute is transitive. */ #define BGP_ATTR_FLAG_PARTIAL 0x20 /* Attribute is partial. */ #define BGP_ATTR_FLAG_EXTLEN 0x10 /* Extended length flag. */ /* BGP attribute header must bigger than 2. */ #define BGP_ATTR_MIN_LEN 3 /* Attribute flag, type length. */ #define BGP_ATTR_DEFAULT_WEIGHT 32768 /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. */ struct attr_extra { /* Multi-Protocol Nexthop, AFI IPv6 */ #ifdef HAVE_IPV6 struct in6_addr mp_nexthop_global; struct in6_addr mp_nexthop_local; #endif /* HAVE_IPV6 */ /* Extended Communities attribute. */ struct ecommunity *ecommunity; /* Route-Reflector Cluster attribute */ struct cluster_list *cluster; /* Unknown transitive attribute. */ struct transit *transit; struct in_addr mp_nexthop_global_in; struct in_addr mp_nexthop_local_in; /* Aggregator Router ID attribute */ struct in_addr aggregator_addr; /* Route Reflector Originator attribute */ struct in_addr originator_id; /* Local weight, not actually an attribute */ u_int32_t weight; /* Aggregator ASN */ as_t aggregator_as; /* MP Nexthop length */ u_char mp_nexthop_len; }; /* BGP core attribute structure. */ struct attr { /* AS Path structure */ struct aspath *aspath; /* Community structure */ struct community *community; /* Lazily allocated pointer to extra attributes */ struct attr_extra *extra; /* Reference count of this attribute. */ unsigned long refcnt; /* Flag of attribute is set or not. */ u_int32_t flag; /* Apart from in6_addr, the remaining static attributes */ struct in_addr nexthop; u_int32_t med; u_int32_t local_pref; /* Path origin attribute */ u_char origin; }; /* Router Reflector related structure. */ struct cluster_list { unsigned long refcnt; int length; struct in_addr *list; }; /* Unknown transit attribute. */ struct transit { unsigned long refcnt; int length; u_char *val; }; #define ATTR_FLAG_BIT(X) (1 << ((X) - 1)) typedef enum { BGP_ATTR_PARSE_PROCEED = 0, BGP_ATTR_PARSE_ERROR = -1, BGP_ATTR_PARSE_WITHDRAW = -2, /* only used internally, send notify + convert to BGP_ATTR_PARSE_ERROR */ BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3, } bgp_attr_parse_ret_t; /* Prototypes. */ extern void bgp_attr_init (void); extern void bgp_attr_finish (void); extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, struct bgp_nlri *, struct bgp_nlri *); extern struct attr_extra *bgp_attr_extra_get (struct attr *); extern void bgp_attr_extra_free (struct attr *); extern void bgp_attr_dup (struct attr *, struct attr *); extern struct attr *bgp_attr_intern (struct attr *attr); extern void bgp_attr_unintern_sub (struct attr *); extern void bgp_attr_unintern (struct attr **); extern void bgp_attr_flush (struct attr *); extern struct attr *bgp_attr_default_set (struct attr *attr, u_char); extern struct attr *bgp_attr_default_intern (u_char); extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char, struct aspath *, struct community *, int as_set); extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct prefix *, afi_t, safi_t, struct peer *, struct prefix_rd *, u_char *); extern void bgp_dump_routes_attr (struct stream *, struct attr *, struct prefix *); extern int attrhash_cmp (const void *, const void *); extern unsigned int attrhash_key_make (void *); extern void attr_show_all (struct vty *); extern unsigned long int attr_count (void); extern unsigned long int attr_unknown_count (void); /* Cluster list prototypes. */ extern int cluster_loop_check (struct cluster_list *, struct in_addr); extern void cluster_unintern (struct cluster_list *); /* Transit attribute prototypes. */ void transit_unintern (struct transit *); /* Below exported for unit-test purposes only */ struct bgp_attr_parser_args { struct peer *peer; bgp_size_t length; /* attribute data length; */ bgp_size_t total; /* total length, inc header */ struct attr *attr; u_int8_t type; u_int8_t flags; u_char *startp; }; extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); /** * Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes. * Typical call sequence is to call _start(), followed by multiple _prefix(), * one for each NLRI that needs to be encoded into the UPDATE message, and * finally the _end() function. */ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi, struct attr *attr); extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, struct prefix *p, struct prefix_rd *prd, u_char *tag); extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep); extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p, afi_t afi, safi_t safi, struct prefix_rd *prd, u_char *tag); extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt); #endif /* _QUAGGA_BGP_ATTR_H */ quagga-0.99.24.1/bgpd/bgp_aspath.h0000644000175000017500000001030212476520570013425 00000000000000/* AS path related definitions. Copyright (C) 1997, 98, 99 Kunihiro Ishiguro This file is part of GNU Zebra. GNU Zebra is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Zebra is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Zebra; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _QUAGGA_BGP_ASPATH_H #define _QUAGGA_BGP_ASPATH_H /* AS path segment type. */ #define AS_SET 1 #define AS_SEQUENCE 2 #define AS_CONFED_SEQUENCE 3 #define AS_CONFED_SET 4 /* Private AS range defined in RFC2270. */ #define BGP_PRIVATE_AS_MIN 64512U #define BGP_PRIVATE_AS_MAX 65535U /* we leave BGP_AS_MAX as the 16bit AS MAX number. */ #define BGP_AS_MAX 65535U #define BGP_AS4_MAX 4294967295U /* Transition 16Bit AS as defined by IANA */ #define BGP_AS_TRANS 23456U /* AS_PATH segment data in abstracted form, no limit is placed on length */ struct assegment { struct assegment *next; as_t *as; u_short length; u_char type; }; /* AS path may be include some AsSegments. */ struct aspath { /* Reference count to this aspath. */ unsigned long refcnt; /* segment data */ struct assegment *segments; /* String expression of AS path. This string is used by vty output and AS path regular expression match. */ char *str; unsigned short str_len; }; #define ASPATH_STR_DEFAULT_LEN 32 /* Prototypes. */ extern void aspath_init (void); extern void aspath_finish (void); extern struct aspath *aspath_parse (struct stream *, size_t, int); extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); extern struct aspath *aspath_add_seq_n (struct aspath *, as_t, unsigned); extern struct aspath *aspath_add_seq (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); extern int aspath_cmp (const void *, const void *); extern int aspath_cmp_left (const struct aspath *, const struct aspath *); extern int aspath_cmp_left_confed (const struct aspath *, const struct aspath *); extern struct aspath *aspath_delete_confed_seq (struct aspath *); extern struct aspath *aspath_empty (void); extern struct aspath *aspath_empty_get (void); extern struct aspath *aspath_str2aspath (const char *); extern void aspath_free (struct aspath *); extern struct aspath *aspath_intern (struct aspath *); extern void aspath_unintern (struct aspath **); extern const char *aspath_print (struct aspath *); extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *); extern void aspath_print_all_vty (struct vty *); extern unsigned int aspath_key_make (void *); extern int aspath_loop_check (struct aspath *, as_t); extern int aspath_private_as_check (struct aspath *); extern int aspath_firstas_check (struct aspath *, as_t); extern int aspath_confed_check (struct aspath *); extern int aspath_left_confed_check (struct aspath *); extern unsigned long aspath_count (void); extern unsigned int aspath_count_hops (struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); extern as_t aspath_highest (struct aspath *); extern as_t aspath_leftmost (struct aspath *); extern size_t aspath_put (struct stream *, struct aspath *, int); extern struct aspath *aspath_reconcile_as4 (struct aspath *, struct aspath *); extern unsigned int aspath_has_as4 (struct aspath *); /* For SNMP BGP4PATHATTRASPATHSEGMENT, might be useful for debug */ extern u_char *aspath_snmp_pathseg (struct aspath *, size_t *); #endif /* _QUAGGA_BGP_ASPATH_H */ quagga-0.99.24.1/bgpd/bgpd.conf.sample20000644000175000017500000000536112476520570014302 00000000000000! ! Zebra configuration saved from vty ! 2002/07/01 03:16:33 ! hostname bgpd password zebra log file bgpd.log log stdout ! router bgp 7675 no bgp default ipv4-unicast neighbor 3ffe:506:1000::2 remote-as 7675 neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377 neighbor fe80::200:c0ff:fe30:9be3 interface sit3 neighbor fe80::210:5aff:fe6b:3cee remote-as 7675 neighbor fe80::210:5aff:fe6b:3cee interface eth0 neighbor fe80::290:27ff:fe51:84c7 remote-as 4691 neighbor fe80::290:27ff:fe51:84c7 description DTI neighbor fe80::290:27ff:fe51:84c7 interface sit7 neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530 neighbor fe80::2a0:c9ff:fec8:82ec description IRI neighbor fe80::2a0:c9ff:fec8:82ec interface sit8 neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500 neighbor fe80::2e0:18ff:fe98:2725 description WIDE neighbor fe80::2e0:18ff:fe98:2725 interface sit5 neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000 neighbor fe80::2e0:18ff:fea8:bf5 interface sit6 ! address-family ipv6 network 3ffe:506::/33 network 3ffe:1800:e800::/40 aggregate-address 3ffe:506::/32 redistribute connected neighbor 3ffe:506:1000::2 activate neighbor fe80::200:c0ff:fe30:9be3 activate neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out neighbor fe80::210:5aff:fe6b:3cee activate neighbor fe80::290:27ff:fe51:84c7 activate neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out neighbor fe80::2a0:c9ff:fec8:82ec activate neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out neighbor fe80::2e0:18ff:fe98:2725 activate neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out neighbor fe80::2e0:18ff:fea8:bf5 activate neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out exit-address-family ! ipv6 access-list all permit any ipv6 access-list nla1 deny 3ffe:506::/33 ipv6 access-list nla1 permit 3ffe:506::/32 ipv6 access-list nla1 deny any ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127 ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41 ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40 ipv6 access-list ntt-nla1 deny any ! ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24 ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28 ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16 ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16 ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35 ! route-map set-nexthop permit 10 match ipv6 address all set ipv6 next-hop global 3ffe:506::1 set ipv6 next-hop local fe80::cbb5:591a set ip next-hop 203.181.89.26 set community 7675:0 ! route-map set-link-local permit 10 match ipv6 address all set ipv6 next-hop local fe80::cbb5:591a set ipv6 next-hop global 3ffe:1800:0:ffff::d ! line vty ! quagga-0.99.24.1/bgpd/bgpd.conf.sample0000644000175000017500000000106612476520570014216 00000000000000! -*- bgp -*- ! ! BGPd sample configuratin file ! ! $Id: bgpd.conf.sample,v 1.1 2002/12/13 20:15:29 paul Exp $ ! hostname bgpd password zebra !enable password please-set-at-here ! !bgp mulitple-instance ! router bgp 7675 ! bgp router-id 10.0.0.1 ! network 10.0.0.0/8 ! neighbor 10.0.0.2 remote-as 7675 ! neighbor 10.0.0.2 route-map set-nexthop out ! neighbor 10.0.0.2 ebgp-multihop ! neighbor 10.0.0.2 next-hop-self ! ! access-list all permit any ! !route-map set-nexthop permit 10 ! match ip address all ! set ip next-hop 10.0.0.1 ! !log file bgpd.log ! log stdout quagga-0.99.24.1/bgpd/Makefile.am0000644000175000017500000000224312476520570013205 00000000000000## Process this file with automake to produce Makefile.in. AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" INSTALL_SDATA=@INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbgp.a sbin_PROGRAMS = bgpd libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 EXTRA_DIST = BGP4-MIB.txt quagga-0.99.24.1/bgpd/Makefile.in0000644000175000017500000006431212476521250013217 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ sbin_PROGRAMS = bgpd$(EXEEXT) subdir = bgpd DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp $(dist_examples_DATA) $(noinst_HEADERS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_sys_weak_alias.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libbgp_a_AR = $(AR) $(ARFLAGS) libbgp_a_LIBADD = am_libbgp_a_OBJECTS = bgpd.$(OBJEXT) bgp_fsm.$(OBJEXT) \ bgp_aspath.$(OBJEXT) bgp_community.$(OBJEXT) \ bgp_attr.$(OBJEXT) bgp_debug.$(OBJEXT) bgp_route.$(OBJEXT) \ bgp_zebra.$(OBJEXT) bgp_open.$(OBJEXT) bgp_routemap.$(OBJEXT) \ bgp_packet.$(OBJEXT) bgp_network.$(OBJEXT) \ bgp_filter.$(OBJEXT) bgp_regex.$(OBJEXT) bgp_clist.$(OBJEXT) \ bgp_dump.$(OBJEXT) bgp_snmp.$(OBJEXT) bgp_ecommunity.$(OBJEXT) \ bgp_mplsvpn.$(OBJEXT) bgp_nexthop.$(OBJEXT) bgp_damp.$(OBJEXT) \ bgp_table.$(OBJEXT) bgp_advertise.$(OBJEXT) bgp_vty.$(OBJEXT) \ bgp_mpath.$(OBJEXT) libbgp_a_OBJECTS = $(am_libbgp_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)" PROGRAMS = $(sbin_PROGRAMS) am_bgpd_OBJECTS = bgp_main.$(OBJEXT) bgpd_OBJECTS = $(am_bgpd_OBJECTS) bgpd_DEPENDENCIES = libbgp.a ../lib/libzebra.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) DIST_SOURCES = $(libbgp_a_SOURCES) $(bgpd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_examples_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BABELD = @BABELD@ BGPD = @BGPD@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONFDATE = @CONFDATE@ CONFIG_ARGS = @CONFIG_ARGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CURSES = @CURSES@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" DEJAGNU = @DEJAGNU@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOC = @DOC@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GAWK = @GAWK@ GREP = @GREP@ HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@ IF_METHOD = @IF_METHOD@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IOCTL_METHOD = @IOCTL_METHOD@ IPFORWARD = @IPFORWARD@ ISISD = @ISISD@ ISIS_TOPOLOGY_DIR = @ISIS_TOPOLOGY_DIR@ ISIS_TOPOLOGY_INCLUDES = @ISIS_TOPOLOGY_INCLUDES@ ISIS_TOPOLOGY_LIB = @ISIS_TOPOLOGY_LIB@ KERNEL_METHOD = @KERNEL_METHOD@ LATEXMK = @LATEXMK@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBCAP = @LIBCAP@ LIBM = @LIBM@ LIBOBJS = @LIBOBJS@ LIBPAM = @LIBPAM@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIB_REGEX = @LIB_REGEX@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MULTIPATH_NUM = @MULTIPATH_NUM@ NETSNMP_CONFIG = @NETSNMP_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OSPF6D = @OSPF6D@ OSPFAPI = @OSPFAPI@ OSPFCLIENT = @OSPFCLIENT@ OSPFD = @OSPFD@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PICFLAGS = @PICFLAGS@ PILDFLAGS = @PILDFLAGS@ PIMD = @PIMD@ RANLIB = @RANLIB@ RIPD = @RIPD@ RIPNGD = @RIPNGD@ RTREAD_METHOD = @RTREAD_METHOD@ RT_METHOD = @RT_METHOD@ RUNTESTDEFAULTFLAGS = @RUNTESTDEFAULTFLAGS@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOLARIS = @SOLARIS@ STRIP = @STRIP@ VERSION = @VERSION@ VTYSH = @VTYSH@ WATCHQUAGGA = @WATCHQUAGGA@ WEAK_ALIAS = @WEAK_ALIAS@ WEAK_ALIAS_CROSSFILE = @WEAK_ALIAS_CROSSFILE@ ZEBRA = @ZEBRA@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ enable_group = @enable_group@ enable_user = @enable_user@ enable_vty_group = @enable_vty_group@ exampledir = @exampledir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgsrcdir = @pkgsrcdir@ pkgsrcrcdir = @pkgsrcrcdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ quagga_statedir = @quagga_statedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib INSTALL_SDATA = @INSTALL@ -m 600 AM_CFLAGS = $(PICFLAGS) AM_LDFLAGS = $(PILDFLAGS) noinst_LIBRARIES = libbgp.a libbgp_a_SOURCES = \ bgpd.c bgp_fsm.c bgp_aspath.c bgp_community.c bgp_attr.c \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ examplesdir = $(exampledir) dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 EXTRA_DIST = BGP4-MIB.txt all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu bgpd/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu bgpd/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libbgp.a: $(libbgp_a_OBJECTS) $(libbgp_a_DEPENDENCIES) $(EXTRA_libbgp_a_DEPENDENCIES) $(AM_V_at)-rm -f libbgp.a $(AM_V_AR)$(libbgp_a_AR) libbgp.a $(libbgp_a_OBJECTS) $(libbgp_a_LIBADD) $(AM_V_at)$(RANLIB) libbgp.a install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list bgpd$(EXEEXT): $(bgpd_OBJECTS) $(bgpd_DEPENDENCIES) $(EXTRA_bgpd_DEPENDENCIES) @rm -f bgpd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bgpd_OBJECTS) $(bgpd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_advertise.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_aspath.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_attr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_clist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_community.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_damp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_dump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_ecommunity.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_filter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_fsm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mpath.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_mplsvpn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_network.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_nexthop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_open.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_regex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_route.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_routemap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_snmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_table.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_vty.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgp_zebra.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgpd.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-dist_examplesDATA: $(dist_examples_DATA) @$(NORMAL_INSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(examplesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(examplesdir)" || exit $$?; \ done uninstall-dist_examplesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_examples_DATA)'; test -n "$(examplesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(examplesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_examplesDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_examplesDATA uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_examplesDATA \ install-dvi install-dvi-am install-exec install-exec-am \ install-html install-html-am install-info install-info-am \ install-man install-pdf install-pdf-am install-ps \ install-ps-am install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am \ uninstall-dist_examplesDATA uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: quagga-0.99.24.1/zebra/0000755000175000017500000000000012476521355011421 500000000000000quagga-0.99.24.1/zebra/GNOME-PRODUCT-ZEBRA-MIB0000644000175000017500000000370012476520570014513 00000000000000GNOME-PRODUCT-ZEBRA-MIB DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-IDENTITY FROM SNMPv2-SMI gnomeProducts FROM GNOME-SMI; zebra MODULE-IDENTITY LAST-UPDATED "200004250000Z" ORGANIZATION "GNOME project" CONTACT-INFO "GNU Network Object Model Environment project see http://www.gnome.org for contact persons of a particular area or subproject of GNOME. Administrative contact for MIB module: Jochen Friedrich Wingertstr. 70/1 68809 Neulussheim Germany email: snmp@gnome.org" DESCRIPTION "The product registrations for the various zebra subdeamons. These registrations are guaranteed to be unique and are used for SMUX registration by default (if not overridden manually)." ::= { gnomeProducts 2 } zserv OBJECT-IDENTITY STATUS current DESCRIPTION "zserv is part of the zebra project which again is a GNU endorsed internet routing program. zserv is the main zebra process which implements routing entries with the kernel and handles routing updates between other routing protocols." ::= { zebra 1 } bgpd OBJECT-IDENTITY STATUS current DESCRIPTION "bgpd is part of the zebra project which again is a GNU endorsed internet routing program." ::= { zebra 2 } ripd OBJECT-IDENTITY STATUS current DESCRIPTION "ripd is part of the zebra project which again is a GNU endorsed internet routing program." ::= { zebra 3 } ripngd OBJECT-IDENTITY STATUS current DESCRIPTION "ripngd is part of the zebra project which again is a GNU endorsed internet routing program." ::= { zebra 4 } ospfd OBJECT-IDENTITY STATUS current DESCRIPTION "ospfd is part of the zebra project which again is a GNU endorsed internet routing program." ::= { zebra 5 } ospf6d OBJECT-IDENTITY STATUS current DESCRIPTION "ospf6d is part of the zebra project which again is a GNU endorsed internet routing program." ::= { zebra 6 } END quagga-0.99.24.1/zebra/GNOME-SMI0000644000175000017500000000217312476520570012560 00000000000000GNOME-SMI DEFINITIONS ::= BEGIN IMPORTS MODULE-IDENTITY, OBJECT-IDENTITY, enterprises FROM SNMPv2-SMI; gnome MODULE-IDENTITY LAST-UPDATED "9809010000Z" ORGANIZATION "GNOME project" CONTACT-INFO "GNU Network Object Model Environment project see http://www.gnome.org for contact persons of a particular area or subproject of GNOME. Administrative contact for MIB module: Jochen Friedrich Wingertstr. 70/1 68809 Neulussheim Germany email: snmp@gnome.org" DESCRIPTION "The Structure of GNOME." ::= { enterprises 3317 } -- assigned by IANA gnomeProducts OBJECT-IDENTITY STATUS current DESCRIPTION "gnomeProducts is the root OBJECT IDENTIFIER from which sysObjectID values are assigned." ::= { gnome 1 } gnomeMgmt OBJECT-IDENTITY STATUS current DESCRIPTION "gnomeMgmt defines the subtree for production GNOME related MIB registrations." ::= { gnome 2 } gnomeTest OBJECT-IDENTITY STATUS current DESCRIPTION "gnomeTest defines the subtree for testing GNOME related MIB registrations." ::= { gnome 3 } -- more to come if necessary. END quagga-0.99.24.1/zebra/ioctl_solaris.c0000644000175000017500000002324112476520570014353 00000000000000/* * Common ioctl functions for Solaris. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "linklist.h" #include "if.h" #include "prefix.h" #include "ioctl.h" #include "log.h" #include "privs.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.h" extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void lifreq_set_name (struct lifreq *lifreq, const char *ifname) { strncpy (lifreq->lifr_name, ifname, IFNAMSIZ); } /* call ioctl system call */ int if_ioctl (u_long request, caddr_t buffer) { int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } return 0; } int if_ioctl_ipv6 (u_long request, caddr_t buffer) { #ifdef HAVE_IPV6 int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create IPv6 datagram socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } #endif /* HAVE_IPV6 */ return 0; } /* * get interface metric * -- if value is not avaliable set -1 */ void if_get_metric (struct interface *ifp) { struct lifreq lifreq; int ret; lifreq_set_name (&lifreq, ifp->name); if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCGLIFMETRIC, (caddr_t) & lifreq); #ifdef SOLARIS_IPV6 else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCGLIFMETRIC, (caddr_t) & lifreq); #endif /* SOLARIS_IPV6 */ else ret = -1; if (ret < 0) return; ifp->metric = lifreq.lifr_metric; if (ifp->metric == 0) ifp->metric = 1; } /* get interface MTU */ void if_get_mtu (struct interface *ifp) { struct lifreq lifreq; int ret; u_char changed = 0; if (ifp->flags & IFF_IPV4) { lifreq_set_name (&lifreq, ifp->name); ret = AF_IOCTL (AF_INET, SIOCGLIFMTU, (caddr_t) & lifreq); if (ret < 0) { zlog_info ("Can't lookup mtu on %s by ioctl(SIOCGLIFMTU)", ifp->name); ifp->mtu = -1; } else { ifp->mtu = lifreq.lifr_metric; changed = 1; } } #ifdef HAVE_IPV6 if (ifp->flags & IFF_IPV6) { memset(&lifreq, 0, sizeof(lifreq)); lifreq_set_name (&lifreq, ifp->name); ret = AF_IOCTL (AF_INET6, SIOCGLIFMTU, (caddr_t) & lifreq); if (ret < 0) { zlog_info ("Can't lookup mtu6 on %s by ioctl(SIOCGIFMTU)", ifp->name); ifp->mtu6 = -1; } else { ifp->mtu6 = lifreq.lifr_metric; changed = 1; } } #endif /* HAVE_IPV6 */ if (changed) zebra_interface_up_update(ifp); } /* Set up interface's address, netmask (and broadcast? ). Solaris uses ifname:number semantics to set IP address aliases. */ int if_set_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in broad; struct sockaddr_in mask; struct prefix_ipv4 ifaddr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; ifaddr = *p; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); addr.sin_addr = p->prefix; addr.sin_family = p->family; memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq); if (ret < 0) return ret; /* We need mask for make broadcast addr. */ masklen2ip (p->prefixlen, &mask.sin_addr); if (if_is_broadcast (ifp)) { apply_mask_ipv4 (&ifaddr); addr.sin_addr = ifaddr.prefix; broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); broad.sin_family = p->family; memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) & ifreq); if (ret < 0) return ret; } mask.sin_family = p->family; #ifdef SUNOS_5 memcpy (&mask, &ifreq.ifr_addr, sizeof (mask)); #else memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in)); #endif /* SUNOS_5 */ ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) & ifreq); return ((ret < 0) ? ret : 0); } /* Set up interface's address, netmask (and broadcast). Solaris uses ifname:number semantics to set IP address aliases. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = p->family; memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFADDR, (caddr_t) & ifreq); if (ret < 0) return ret; return 0; } /* Get just the flags for the given name. * Used by the normal 'if_get_flags' function, as well * as the bootup interface-list code, which has to peek at per-address * flags in order to figure out which ones should be ignored.. */ int if_get_flags_direct (const char *ifname, uint64_t *flags, unsigned int af) { struct lifreq lifreq; int ret; lifreq_set_name (&lifreq, ifname); ret = AF_IOCTL (af, SIOCGLIFFLAGS, (caddr_t) &lifreq); if (ret) zlog_debug ("%s: ifname %s, error %s (%d)", __func__, ifname, safe_strerror (errno), errno); *flags = lifreq.lifr_flags; return ret; } /* get interface flags */ void if_get_flags (struct interface *ifp) { int ret4, ret6; uint64_t newflags = 0; uint64_t tmpflags; if (ifp->flags & IFF_IPV4) { ret4 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET); if (!ret4) newflags |= tmpflags; else if (errno == ENXIO) { /* it's gone */ UNSET_FLAG (ifp->flags, IFF_UP); if_flags_update (ifp, ifp->flags); } } if (ifp->flags & IFF_IPV6) { ret6 = if_get_flags_direct (ifp->name, &tmpflags, AF_INET6); if (!ret6) newflags |= tmpflags; else if (errno == ENXIO) { /* it's gone */ UNSET_FLAG (ifp->flags, IFF_UP); if_flags_update (ifp, ifp->flags); } } /* only update flags if one of above succeeded */ if ( !(ret4 && ret6) ) if_flags_update (ifp, newflags); } /* Set interface flags */ int if_set_flags (struct interface *ifp, uint64_t flags) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); lifreq.lifr_flags = ifp->flags; lifreq.lifr_flags |= flags; if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq); else ret = -1; if (ret < 0) zlog_info ("can't set interface flags on %s: %s", ifp->name, safe_strerror (errno)); else ret = 0; return ret; } /* Unset interface's flag. */ int if_unset_flags (struct interface *ifp, uint64_t flags) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); lifreq.lifr_flags = ifp->flags; lifreq.lifr_flags &= ~flags; if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCSLIFFLAGS, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCSLIFFLAGS, (caddr_t) & lifreq); else ret = -1; if (ret < 0) zlog_info ("can't unset interface flags"); else ret = 0; return ret; } #ifdef HAVE_IPV6 /* Interface's address add/delete functions. */ int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { char addrbuf[INET_ADDRSTRLEN]; inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), addrbuf, sizeof (addrbuf)); zlog_warn ("Can't set %s on interface %s", addrbuf, ifp->name); return 0; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { char addrbuf[INET_ADDRSTRLEN]; inet_ntop (AF_INET6, &(((struct prefix_ipv6 *) (ifc->address))->prefix), addrbuf, sizeof (addrbuf)); zlog_warn ("Can't delete %s on interface %s", addrbuf, ifp->name); return 0; } #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/ioctl.c0000644000175000017500000003532412476520570012624 00000000000000/* * Common ioctl functions. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "linklist.h" #include "if.h" #include "prefix.h" #include "ioctl.h" #include "log.h" #include "privs.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/interface.h" #ifdef HAVE_BSD_LINK_DETECT #include #endif /* HAVE_BSD_LINK_DETECT*/ extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ void ifreq_set_name (struct ifreq *ifreq, struct interface *ifp) { strncpy (ifreq->ifr_name, ifp->name, IFNAMSIZ); } /* call ioctl system call */ int if_ioctl (u_long request, caddr_t buffer) { int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create UDP socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } return 0; } #ifdef HAVE_IPV6 static int if_ioctl_ipv6 (u_long request, caddr_t buffer) { int sock; int ret; int err; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_err("Cannot create IPv6 datagram socket: %s", safe_strerror(save_errno)); exit (1); } if ((ret = ioctl (sock, request, buffer)) < 0) err = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); close (sock); if (ret < 0) { errno = err; return ret; } return 0; } #endif /* HAVE_IPV6 */ /* * get interface metric * -- if value is not avaliable set -1 */ void if_get_metric (struct interface *ifp) { #ifdef SIOCGIFMETRIC struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); if (if_ioctl (SIOCGIFMETRIC, (caddr_t) &ifreq) < 0) return; ifp->metric = ifreq.ifr_metric; if (ifp->metric == 0) ifp->metric = 1; #else /* SIOCGIFMETRIC */ ifp->metric = -1; #endif /* SIOCGIFMETRIC */ } /* get interface MTU */ void if_get_mtu (struct interface *ifp) { struct ifreq ifreq; ifreq_set_name (&ifreq, ifp); #if defined(SIOCGIFMTU) if (if_ioctl (SIOCGIFMTU, (caddr_t) & ifreq) < 0) { zlog_info ("Can't lookup mtu by ioctl(SIOCGIFMTU)"); ifp->mtu6 = ifp->mtu = -1; return; } #ifdef SUNOS_5 ifp->mtu6 = ifp->mtu = ifreq.ifr_metric; #else ifp->mtu6 = ifp->mtu = ifreq.ifr_mtu; #endif /* SUNOS_5 */ /* propogate */ zebra_interface_up_update(ifp); #else zlog (NULL, LOG_INFO, "Can't lookup mtu on this system"); ifp->mtu6 = ifp->mtu = -1; #endif } #ifdef HAVE_NETLINK /* Interface address setting via netlink interface. */ int if_set_prefix (struct interface *ifp, struct connected *ifc) { return kernel_address_add_ipv4 (ifp, ifc); } /* Interface address is removed using netlink interface. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { return kernel_address_delete_ipv4 (ifp, ifc); } #else /* ! HAVE_NETLINK */ #ifdef HAVE_STRUCT_IFALIASREQ /* Set up interface's IP address, netmask (and broadcas? ). *BSD may has ifaliasreq structure. */ int if_set_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; struct sockaddr_in addr; struct sockaddr_in mask; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; rib_lookup_and_pushup (p); memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_addr = p->prefix; addr.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCAIFADDR, (caddr_t) &addreq); if (ret < 0) return ret; return 0; } /* Set up interface's IP address, netmask (and broadcas? ). *BSD may has ifaliasreq structure. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; struct sockaddr_in addr; struct sockaddr_in mask; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *)ifc->address; memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_addr = p->prefix; addr.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin_len = sizeof (struct sockaddr_in); #endif memcpy (&addreq.ifra_mask, &mask, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCDIFADDR, (caddr_t) &addreq); if (ret < 0) return ret; return 0; } #else /* Set up interface's address, netmask (and broadcas? ). Linux or Solaris uses ifname:number semantics to set IP address aliases. */ int if_set_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in broad; struct sockaddr_in mask; struct prefix_ipv4 ifaddr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; ifaddr = *p; ifreq_set_name (&ifreq, ifp); addr.sin_addr = p->prefix; addr.sin_family = p->family; memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); if (ret < 0) return ret; /* We need mask for make broadcast addr. */ masklen2ip (p->prefixlen, &mask.sin_addr); if (if_is_broadcast (ifp)) { apply_mask_ipv4 (&ifaddr); addr.sin_addr = ifaddr.prefix; broad.sin_addr.s_addr = (addr.sin_addr.s_addr | ~mask.sin_addr.s_addr); broad.sin_family = p->family; memcpy (&ifreq.ifr_broadaddr, &broad, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFBRDADDR, (caddr_t) &ifreq); if (ret < 0) return ret; } mask.sin_family = p->family; #ifdef SUNOS_5 memcpy (&mask, &ifreq.ifr_addr, sizeof (mask)); #else memcpy (&ifreq.ifr_netmask, &mask, sizeof (struct sockaddr_in)); #endif /* SUNOS5 */ ret = if_ioctl (SIOCSIFNETMASK, (caddr_t) &ifreq); if (ret < 0) return ret; return 0; } /* Set up interface's address, netmask (and broadcas? ). Linux or Solaris uses ifname:number semantics to set IP address aliases. */ int if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; ifreq_set_name (&ifreq, ifp); memset (&addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = p->family; memcpy (&ifreq.ifr_addr, &addr, sizeof (struct sockaddr_in)); ret = if_ioctl (SIOCSIFADDR, (caddr_t) &ifreq); if (ret < 0) return ret; return 0; } #endif /* HAVE_STRUCT_IFALIASREQ */ #endif /* HAVE_NETLINK */ /* get interface flags */ void if_get_flags (struct interface *ifp) { int ret; struct ifreq ifreq; #ifdef HAVE_BSD_LINK_DETECT struct ifmediareq ifmr; #endif /* HAVE_BSD_LINK_DETECT */ ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ /* Per-default, IFF_RUNNING is held high, unless link-detect says * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag, * following practice on Linux and Solaris kernels */ SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) { (void) memset(&ifmr, 0, sizeof(ifmr)); strncpy (ifmr.ifm_name, ifp->name, IFNAMSIZ); /* Seems not all interfaces implement this ioctl */ if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno)); else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ { if (ifmr.ifm_status & IFM_ACTIVE) SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); else UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); } } #endif /* HAVE_BSD_LINK_DETECT */ if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); } /* Set interface flags */ int if_set_flags (struct interface *ifp, uint64_t flags) { int ret; struct ifreq ifreq; memset (&ifreq, 0, sizeof(struct ifreq)); ifreq_set_name (&ifreq, ifp); ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags |= flags; ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_info ("can't set interface flags"); return ret; } return 0; } /* Unset interface's flag. */ int if_unset_flags (struct interface *ifp, uint64_t flags) { int ret; struct ifreq ifreq; memset (&ifreq, 0, sizeof(struct ifreq)); ifreq_set_name (&ifreq, ifp); ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags &= ~flags; ret = if_ioctl (SIOCSIFFLAGS, (caddr_t) &ifreq); if (ret < 0) { zlog_info ("can't unset interface flags"); return ret; } return 0; } #ifdef HAVE_IPV6 #ifdef LINUX_IPV6 #ifndef _LINUX_IN6_H /* linux/include/net/ipv6.h */ struct in6_ifreq { struct in6_addr ifr6_addr; u_int32_t ifr6_prefixlen; int ifr6_ifindex; }; #endif /* _LINUX_IN6_H */ /* Interface's address add/delete functions. */ int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { int ret; struct prefix_ipv6 *p; struct in6_ifreq ifreq; p = (struct prefix_ipv6 *) ifc->address; memset (&ifreq, 0, sizeof (struct in6_ifreq)); memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); ifreq.ifr6_ifindex = ifp->ifindex; ifreq.ifr6_prefixlen = p->prefixlen; ret = if_ioctl_ipv6 (SIOCSIFADDR, (caddr_t) &ifreq); return ret; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { int ret; struct prefix_ipv6 *p; struct in6_ifreq ifreq; p = (struct prefix_ipv6 *) ifc->address; memset (&ifreq, 0, sizeof (struct in6_ifreq)); memcpy (&ifreq.ifr6_addr, &p->prefix, sizeof (struct in6_addr)); ifreq.ifr6_ifindex = ifp->ifindex; ifreq.ifr6_prefixlen = p->prefixlen; ret = if_ioctl_ipv6 (SIOCDIFADDR, (caddr_t) &ifreq); return ret; } #else /* LINUX_IPV6 */ #ifdef HAVE_STRUCT_IN6_ALIASREQ #ifndef ND6_INFINITE_LIFETIME #define ND6_INFINITE_LIFETIME 0xffffffffL #endif /* ND6_INFINITE_LIFETIME */ int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { int ret; struct in6_aliasreq addreq; struct sockaddr_in6 addr; struct sockaddr_in6 mask; struct prefix_ipv6 *p; p = (struct prefix_ipv6 * ) ifc->address; memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); memset (&addr, 0, sizeof (struct sockaddr_in6)); addr.sin6_addr = p->prefix; addr.sin6_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); memset (&mask, 0, sizeof (struct sockaddr_in6)); masklen2ip6 (p->prefixlen, &mask.sin6_addr); mask.sin6_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); addreq.ifra_lifetime.ia6t_vltime = 0xffffffff; addreq.ifra_lifetime.ia6t_pltime = 0xffffffff; #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; #endif ret = if_ioctl_ipv6 (SIOCAIFADDR_IN6, (caddr_t) &addreq); if (ret < 0) return ret; return 0; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { int ret; struct in6_aliasreq addreq; struct sockaddr_in6 addr; struct sockaddr_in6 mask; struct prefix_ipv6 *p; p = (struct prefix_ipv6 *) ifc->address; memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); memset (&addr, 0, sizeof (struct sockaddr_in6)); addr.sin6_addr = p->prefix; addr.sin6_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in6)); memset (&mask, 0, sizeof (struct sockaddr_in6)); masklen2ip6 (p->prefixlen, &mask.sin6_addr); mask.sin6_family = p->family; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN mask.sin6_len = sizeof (struct sockaddr_in6); #endif memcpy (&addreq.ifra_prefixmask, &mask, sizeof (struct sockaddr_in6)); #ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; #endif ret = if_ioctl_ipv6 (SIOCDIFADDR_IN6, (caddr_t) &addreq); if (ret < 0) return ret; return 0; } #else int if_prefix_add_ipv6 (struct interface *ifp, struct connected *ifc) { return 0; } int if_prefix_delete_ipv6 (struct interface *ifp, struct connected *ifc) { return 0; } #endif /* HAVE_STRUCT_IN6_ALIASREQ */ #endif /* LINUX_IPV6 */ #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/kernel_netlink.c0000644000175000017500000000152412476520570014511 00000000000000/* Kernel communication using netlink interface. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ quagga-0.99.24.1/zebra/kernel_socket.c0000644000175000017500000011607212476520570014342 00000000000000/* Kernel communication using routing socket. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "sockunion.h" #include "connected.h" #include "memory.h" #include "ioctl.h" #include "log.h" #include "str.h" #include "table.h" #include "rib.h" #include "privs.h" #include "zebra/interface.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/kernel_socket.h" extern struct zebra_privs_t zserv_privs; extern struct zebra_t zebrad; /* * Historically, the BSD routing socket has aligned data following a * struct sockaddr to sizeof(long), which was 4 bytes on some * platforms, and 8 bytes on others. NetBSD 6 changed the routing * socket to align to sizeof(uint64_t), which is 8 bytes. OS X * appears to align to sizeof(int), which is 4 bytes. * * Alignment of zero-sized sockaddrs is nonsensical, but historically * BSD defines RT_ROUNDUP(0) to be the alignment interval (rather than * 0). We follow this practice without questioning it, but it is a * bug if quagga calls ROUNDUP with 0. */ /* * Because of these varying conventions, the only sane approach is for * the header to define some flavor of ROUNDUP macro. */ #if defined(RT_ROUNDUP) #define ROUNDUP(a) RT_ROUNDUP(a) #endif /* defined(RT_ROUNDUP) */ /* * If ROUNDUP has not yet been defined in terms of platform-provided * defines, attempt to cope with heuristics. */ #if !defined(ROUNDUP) /* * It's a bug for a platform not to define rounding/alignment for * sockaddrs on the routing socket. This warning really is * intentional, to provoke filing bug reports with operating systems * that don't define RT_ROUNDUP or equivalent. */ #warning "net/route.h does not define RT_ROUNDUP; making unwarranted assumptions!" /* OS X (Xcode as of 2014-12) is known not to define RT_ROUNDUP */ #ifdef __APPLE__ #define ROUNDUP_TYPE long #else #define ROUNDUP_TYPE int #endif #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(ROUNDUP_TYPE) - 1))) : sizeof(ROUNDUP_TYPE)) #endif /* defined(ROUNDUP) */ /* * Given a pointer (sockaddr or void *), return the number of bytes * taken up by the sockaddr and any padding needed for alignment. */ #if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) #define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len) #elif defined(HAVE_IPV6) /* * One would hope all fixed-size structure definitions are aligned, * but round them up nonetheless. */ #define SAROUNDUP(X) \ (((struct sockaddr *)(X))->sa_family == AF_INET ? \ ROUNDUP(sizeof(struct sockaddr_in)):\ (((struct sockaddr *)(X))->sa_family == AF_INET6 ? \ ROUNDUP(sizeof(struct sockaddr_in6)) : \ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))) #else /* HAVE_IPV6 */ #define SAROUNDUP(X) \ (((struct sockaddr *)(X))->sa_family == AF_INET ? \ ROUNDUP(sizeof(struct sockaddr_in)):\ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))) #endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ /* * We use a call to an inline function to copy (PNT) to (DEST) * 1. Calculating the length of the copy requires an #ifdef to determine * if sa_len is a field and can't be used directly inside a #define * 2. So the compiler doesn't complain when DEST is NULL, which is only true * when we are skipping the copy and incrementing to the next SA */ static void inline rta_copy (union sockunion *dest, caddr_t src) { int len; #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN len = (((struct sockaddr *)src)->sa_len > sizeof (*dest)) ? sizeof (*dest) : ((struct sockaddr *)src)->sa_len ; #else len = (SAROUNDUP (src) > sizeof (*dest)) ? sizeof (*dest) : SAROUNDUP (src) ; #endif memcpy (dest, src, len); } #define RTA_ADDR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ if ( ((DEST) != NULL) && \ af_check (((struct sockaddr *)(PNT))->sa_family)) \ rta_copy((DEST), (PNT)); \ (PNT) += len; \ } #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \ if ((RTMADDRS) & (RTA)) \ { \ int len = SAROUNDUP ((PNT)); \ if ((DEST) != NULL) \ rta_copy((DEST), (PNT)); \ (PNT) += len; \ } #define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \ if ((RTMADDRS) & (RTA)) \ { \ u_char *pdest = (u_char *) (DEST); \ int len = SAROUNDUP ((PNT)); \ struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \ if (IS_ZEBRA_DEBUG_KERNEL) \ zlog_debug ("%s: RTA_SDL_GET nlen %d, alen %d", \ __func__, sdl->sdl_nlen, sdl->sdl_alen); \ if ( ((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \ && (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len) ) \ { \ memcpy (pdest, sdl->sdl_data, sdl->sdl_nlen); \ pdest[sdl->sdl_nlen] = '\0'; \ (LEN) = sdl->sdl_nlen; \ } \ (PNT) += len; \ } \ else \ { \ (LEN) = 0; \ } /* Routing socket message types. */ const struct message rtm_type_str[] = { {RTM_ADD, "RTM_ADD"}, {RTM_DELETE, "RTM_DELETE"}, {RTM_CHANGE, "RTM_CHANGE"}, {RTM_GET, "RTM_GET"}, {RTM_LOSING, "RTM_LOSING"}, {RTM_REDIRECT, "RTM_REDIRECT"}, {RTM_MISS, "RTM_MISS"}, {RTM_LOCK, "RTM_LOCK"}, #ifdef OLDADD {RTM_OLDADD, "RTM_OLDADD"}, #endif /* RTM_OLDADD */ #ifdef RTM_OLDDEL {RTM_OLDDEL, "RTM_OLDDEL"}, #endif /* RTM_OLDDEL */ {RTM_RESOLVE, "RTM_RESOLVE"}, {RTM_NEWADDR, "RTM_NEWADDR"}, {RTM_DELADDR, "RTM_DELADDR"}, {RTM_IFINFO, "RTM_IFINFO"}, #ifdef RTM_OIFINFO {RTM_OIFINFO, "RTM_OIFINFO"}, #endif /* RTM_OIFINFO */ #ifdef RTM_NEWMADDR {RTM_NEWMADDR, "RTM_NEWMADDR"}, #endif /* RTM_NEWMADDR */ #ifdef RTM_DELMADDR {RTM_DELMADDR, "RTM_DELMADDR"}, #endif /* RTM_DELMADDR */ #ifdef RTM_IFANNOUNCE {RTM_IFANNOUNCE, "RTM_IFANNOUNCE"}, #endif /* RTM_IFANNOUNCE */ {0, NULL} }; static const struct message rtm_flag_str[] = { {RTF_UP, "UP"}, {RTF_GATEWAY, "GATEWAY"}, {RTF_HOST, "HOST"}, {RTF_REJECT, "REJECT"}, {RTF_DYNAMIC, "DYNAMIC"}, {RTF_MODIFIED, "MODIFIED"}, {RTF_DONE, "DONE"}, #ifdef RTF_MASK {RTF_MASK, "MASK"}, #endif /* RTF_MASK */ #ifdef RTF_CLONING {RTF_CLONING, "CLONING"}, #endif /* RTF_CLONING */ {RTF_XRESOLVE, "XRESOLVE"}, {RTF_LLINFO, "LLINFO"}, {RTF_STATIC, "STATIC"}, {RTF_BLACKHOLE, "BLACKHOLE"}, #ifdef RTF_PRIVATE {RTF_PRIVATE, "PRIVATE"}, #endif /* RTF_PRIVATE */ {RTF_PROTO1, "PROTO1"}, {RTF_PROTO2, "PROTO2"}, #ifdef RTF_PRCLONING {RTF_PRCLONING, "PRCLONING"}, #endif /* RTF_PRCLONING */ #ifdef RTF_WASCLONED {RTF_WASCLONED, "WASCLONED"}, #endif /* RTF_WASCLONED */ #ifdef RTF_PROTO3 {RTF_PROTO3, "PROTO3"}, #endif /* RTF_PROTO3 */ #ifdef RTF_PINNED {RTF_PINNED, "PINNED"}, #endif /* RTF_PINNED */ #ifdef RTF_LOCAL {RTF_LOCAL, "LOCAL"}, #endif /* RTF_LOCAL */ #ifdef RTF_BROADCAST {RTF_BROADCAST, "BROADCAST"}, #endif /* RTF_BROADCAST */ #ifdef RTF_MULTICAST {RTF_MULTICAST, "MULTICAST"}, #endif /* RTF_MULTICAST */ #ifdef RTF_MULTIRT {RTF_MULTIRT, "MULTIRT"}, #endif /* RTF_MULTIRT */ #ifdef RTF_SETSRC {RTF_SETSRC, "SETSRC"}, #endif /* RTF_SETSRC */ {0, NULL} }; /* Kernel routing update socket. */ int routing_sock = -1; /* Yes I'm checking ugly routing socket behavior. */ /* #define DEBUG */ /* Supported address family check. */ static int inline af_check (int family) { if (family == AF_INET) return 1; #ifdef HAVE_IPV6 if (family == AF_INET6) return 1; #endif /* HAVE_IPV6 */ return 0; } /* Dump routing table flag for debug purpose. */ static void rtm_flag_dump (int flag) { const struct message *mes; static char buf[BUFSIZ]; buf[0] = '\0'; for (mes = rtm_flag_str; mes->key != 0; mes++) { if (mes->key & flag) { strlcat (buf, mes->str, BUFSIZ); strlcat (buf, " ", BUFSIZ); } } zlog_debug ("Kernel: %s", buf); } #ifdef RTM_IFANNOUNCE /* Interface adding function */ static int ifan_read (struct if_announcemsghdr *ifan) { struct interface *ifp; ifp = if_lookup_by_index (ifan->ifan_index); if (ifp) assert ( (ifp->ifindex == ifan->ifan_index) || (ifp->ifindex == IFINDEX_INTERNAL) ); if ( (ifp == NULL) || ((ifp->ifindex == IFINDEX_INTERNAL) && (ifan->ifan_what == IFAN_ARRIVAL)) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating interface for ifindex %d, name %s", __func__, ifan->ifan_index, ifan->ifan_name); /* Create Interface */ ifp = if_get_by_name_len(ifan->ifan_name, strnlen(ifan->ifan_name, sizeof(ifan->ifan_name))); ifp->ifindex = ifan->ifan_index; if_get_metric (ifp); if_add_update (ifp); } else if (ifp != NULL && ifan->ifan_what == IFAN_DEPARTURE) if_delete_update (ifp); if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifan->ifan_name, ifan->ifan_index); return 0; } #endif /* RTM_IFANNOUNCE */ #ifdef HAVE_BSD_IFI_LINK_STATE /* BSD link detect translation */ static void bsd_linkdetect_translate (struct if_msghdr *ifm) { if ((ifm->ifm_data.ifi_link_state >= LINK_STATE_UP) || (ifm->ifm_data.ifi_link_state == LINK_STATE_UNKNOWN)) SET_FLAG(ifm->ifm_flags, IFF_RUNNING); else UNSET_FLAG(ifm->ifm_flags, IFF_RUNNING); } #endif /* HAVE_BSD_IFI_LINK_STATE */ /* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs * present after the header. */ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp = NULL; struct sockaddr_dl *sdl; char ifname[IFNAMSIZ]; short ifnlen = 0; caddr_t cp; /* terminate ifname at head (for strnlen) and tail (for safety) */ ifname[IFNAMSIZ - 1] = '\0'; /* paranoia: sanity check structure */ if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { zlog_err ("ifm_read: ifm->ifm_msglen %d too short\n", ifm->ifm_msglen); return -1; } /* * Check for a sockaddr_dl following the message. First, point to * where a socakddr might be if one follows the message. */ cp = (void *)(ifm + 1); #ifdef SUNOS_5 /* * XXX This behavior should be narrowed to only the kernel versions * for which the structures returned do not match the headers. * * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions * is 12 bytes larger than the 32 bit version. */ if (((struct sockaddr *) cp)->sa_family == AF_UNSPEC) cp = cp + 12; #endif RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp); RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp); sdl = (struct sockaddr_dl *)cp; RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp); RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)")); /* * Look up on ifindex first, because ifindices are the primary handle for * interfaces across the user/kernel boundary, for most systems. (Some * messages, such as up/down status changes on NetBSD, do not include a * sockaddr_dl). */ if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL ) { /* we have an ifp, verify that the name matches as some systems, * eg Solaris, have a 1:many association of ifindex:ifname * if they dont match, we dont have the correct ifp and should * set it back to NULL to let next check do lookup by name */ if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) ) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ifp name %s doesnt match sdl name %s", __func__, ifp->name, ifname); ifp = NULL; } } /* * If we dont have an ifp, try looking up by name. Particularly as some * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname * is therefore our unique handle to that interface. * * Interfaces specified in the configuration file for which the ifindex * has not been determined will have ifindex == IFINDEX_INTERNAL, and such * interfaces are found by this search, and then their ifindex values can * be filled in. */ if ( (ifp == NULL) && ifnlen) ifp = if_lookup_by_name (ifname); /* * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL), * create or fill in an interface. */ if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL)) { /* * To create or fill in an interface, a sockaddr_dl (via * RTA_IFP) is required. */ if (!ifnlen) { zlog_warn ("Interface index %d (new) missing ifname\n", ifm->ifm_index); return -1; } #ifndef RTM_IFANNOUNCE /* Down->Down interface should be ignored here. * See further comment below. */ if (!CHECK_FLAG (ifm->ifm_flags, IFF_UP)) return 0; #endif /* !RTM_IFANNOUNCE */ if (ifp == NULL) { /* Interface that zebra was not previously aware of, so create. */ ifp = if_create (ifname, ifnlen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: creating ifp for ifindex %d", __func__, ifm->ifm_index); } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d", __func__, ifp->name, ifp->ifindex); /* * Fill in newly created interface structure, or larval * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; #ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_IFI_LINK_STATE */ if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); /* * XXX sockaddr_dl contents can be larger than the structure * definition. There are 2 big families here: * - BSD has sdl_len + sdl_data[16] + overruns sdl_data * we MUST use sdl_len here or we'll truncate data. * - Solaris has no sdl_len, but sdl_data[244] * presumably, it's not going to run past that, so sizeof() * is fine here. * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid */ if (ifnlen) { #ifdef HAVE_STRUCT_SOCKADDR_DL_SDL_LEN memcpy (&ifp->sdl, sdl, sdl->sdl_len); #else memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); #endif /* HAVE_STRUCT_SOCKADDR_DL_SDL_LEN */ } if_add_update (ifp); } else /* * Interface structure exists. Adjust stored flags from * notification. If interface has up->down or down->up * transition, call state change routines (to adjust routes, * notify routing daemons, etc.). (Other flag changes are stored * but apparently do not trigger action.) */ { if (ifp->ifindex != ifm->ifm_index) { zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, " "ifm index %d", __func__, ifp->name, ifp->ifindex, ifm->ifm_index); return -1; } #ifdef HAVE_BSD_IFI_LINK_STATE /* translate BSD kernel msg for link-state */ bsd_linkdetect_translate(ifm); #endif /* HAVE_BSD_IFI_LINK_STATE */ /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); #ifndef RTM_IFANNOUNCE if (!if_is_up (ifp)) { /* No RTM_IFANNOUNCE on this platform, so we can never * distinguish between ~IFF_UP and delete. We must presume * it has been deleted. * Eg, Solaris will not notify us of unplumb. * * XXX: Fixme - this should be runtime detected * So that a binary compiled on a system with IFANNOUNCE * will still behave correctly if run on a platform without */ if_delete_update (ifp); } #endif /* RTM_IFANNOUNCE */ if (if_is_up (ifp)) { #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: interface %s index %d", __func__, ifp->name, ifp->ifindex); return 0; } /* Address read from struct ifa_msghdr. */ static void ifam_read_mesg (struct ifa_msghdr *ifm, union sockunion *addr, union sockunion *mask, union sockunion *brd, char *ifname, short *ifnlen) { caddr_t pnt, end; union sockunion dst; union sockunion gateway; pnt = (caddr_t)(ifm + 1); end = ((caddr_t)ifm) + ifm->ifam_msglen; /* Be sure structure is cleared */ memset (mask, 0, sizeof (union sockunion)); memset (addr, 0, sizeof (union sockunion)); memset (brd, 0, sizeof (union sockunion)); memset (&dst, 0, sizeof (union sockunion)); memset (&gateway, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt); RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen); RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt); RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt); if (IS_ZEBRA_DEBUG_KERNEL) { switch (sockunion_family(addr)) { case AF_INET: { char buf[4][INET_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET,&addr->sin.sin_addr, buf[0],sizeof(buf[0])), ip_masklen(mask->sin.sin_addr), inet_ntop(AF_INET,&brd->sin.sin_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET,&dst.sin.sin_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET,&gateway.sin.sin_addr, buf[3],sizeof(buf[3]))); } break; #ifdef HAVE_IPV6 case AF_INET6: { char buf[4][INET6_ADDRSTRLEN]; zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, " "ifam_flags 0x%x, addr %s/%d broad %s dst %s " "gateway %s", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs, ifm->ifam_flags, inet_ntop(AF_INET6,&addr->sin6.sin6_addr, buf[0],sizeof(buf[0])), ip6_masklen(mask->sin6.sin6_addr), inet_ntop(AF_INET6,&brd->sin6.sin6_addr, buf[1],sizeof(buf[1])), inet_ntop(AF_INET6,&dst.sin6.sin6_addr, buf[2],sizeof(buf[2])), inet_ntop(AF_INET6,&gateway.sin6.sin6_addr, buf[3],sizeof(buf[3]))); } break; #endif /* HAVE_IPV6 */ default: zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs); break; } } /* Assert read up end point matches to end point */ if (pnt != end) zlog_warn ("ifam_read() doesn't read all socket data"); } /* Interface's address information get. */ int ifam_read (struct ifa_msghdr *ifam) { struct interface *ifp = NULL; union sockunion addr, mask, brd; char ifname[INTERFACE_NAMSIZ]; short ifnlen = 0; char isalias = 0; int flags = 0; ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; /* Allocate and read address information. */ ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen); if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL) { zlog_warn ("%s: no interface for ifname %s, index %d", __func__, ifname, ifam->ifam_index); return -1; } if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ)) isalias = 1; /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD field contains a broadcast address or a peer address, so we are forced to rely upon the interface type. */ if (if_is_pointopoint(ifp)) SET_FLAG(flags, ZEBRA_IFA_PEER); #if 0 /* it might seem cute to grab the interface metric here, however * we're processing an address update message, and so some systems * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left * in deliberately, as comment. */ ifp->metric = ifam->ifam_metric; #endif /* Add connected address. */ switch (sockunion_family (&addr)) { case AF_INET: if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, (isalias ? ifname : NULL)); else connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr); break; #ifdef HAVE_IPV6 case AF_INET6: /* Unset interface index from link-local address when IPv6 stack is KAME. */ if (IN6_IS_ADDR_LINKLOCAL (&addr.sin6.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0); if (ifam->ifam_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr, (isalias ? ifname : NULL)); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr); break; #endif /* HAVE_IPV6 */ default: /* Unsupported family silently ignore... */ break; } /* Check interface flag for implicit up of the interface. */ if_refresh (ifp); #ifdef SUNOS_5 /* In addition to lacking IFANNOUNCE, on SUNOS IFF_UP is strange. * See comments for SUNOS_5 in interface.c::if_flags_mangle. * * Here we take care of case where the real IFF_UP was previously * unset (as kept in struct zebra_if.primary_state) and the mangled * IFF_UP (ie IFF_UP set || listcount(connected) has now transitioned * to unset due to the lost non-primary address having DELADDR'd. * * we must delete the interface, because in between here and next * event for this interface-name the administrator could unplumb * and replumb the interface. */ if (!if_is_up (ifp)) if_delete_update (ifp); #endif /* SUNOS_5 */ return 0; } /* Interface function for reading kernel routing table information. */ static int rtm_read_mesg (struct rt_msghdr *rtm, union sockunion *dest, union sockunion *mask, union sockunion *gate, char *ifname, short *ifnlen) { caddr_t pnt, end; /* Pnt points out socket data start point. */ pnt = (caddr_t)(rtm + 1); end = ((caddr_t)rtm) + rtm->rtm_msglen; /* rt_msghdr version check. */ if (rtm->rtm_version != RTM_VERSION) zlog (NULL, LOG_WARNING, "Routing message version different %d should be %d." "This may cause problem\n", rtm->rtm_version, RTM_VERSION); /* Be sure structure is cleared */ memset (dest, 0, sizeof (union sockunion)); memset (gate, 0, sizeof (union sockunion)); memset (mask, 0, sizeof (union sockunion)); /* We fetch each socket variable into sockunion. */ RTA_ADDR_GET (dest, RTA_DST, rtm->rtm_addrs, pnt); RTA_ADDR_GET (gate, RTA_GATEWAY, rtm->rtm_addrs, pnt); RTA_ATTR_GET (mask, RTA_NETMASK, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_GENMASK, rtm->rtm_addrs, pnt); RTA_NAME_GET (ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen); RTA_ADDR_GET (NULL, RTA_IFA, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt); RTA_ADDR_GET (NULL, RTA_BRD, rtm->rtm_addrs, pnt); /* If there is netmask information set it's family same as destination family*/ if (rtm->rtm_addrs & RTA_NETMASK) mask->sa.sa_family = dest->sa.sa_family; /* Assert read up to the end of pointer. */ if (pnt != end) zlog (NULL, LOG_WARNING, "rtm_read() doesn't read all socket data."); return rtm->rtm_flags; } void rtm_read (struct rt_msghdr *rtm) { int flags; u_char zebra_flags; union sockunion dest, mask, gate; char ifname[INTERFACE_NAMSIZ + 1]; short ifnlen = 0; zebra_flags = 0; /* Read destination and netmask and gateway from rtm message structure. */ flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen); if (!(flags & RTF_DONE)) return; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type, lookup (rtm_type_str, rtm->rtm_type)); #ifdef RTF_CLONED /*bsdi, netbsd 1.6*/ if (flags & RTF_CLONED) return; #endif #ifdef RTF_WASCLONED /*freebsd*/ if (flags & RTF_WASCLONED) return; #endif if ((rtm->rtm_type == RTM_ADD) && ! (flags & RTF_UP)) return; /* This is connected route. */ if (! (flags & RTF_GATEWAY)) return; if (flags & RTF_PROTO1) SET_FLAG (zebra_flags, ZEBRA_FLAG_SELFROUTE); /* This is persistent route. */ if (flags & RTF_STATIC) SET_FLAG (zebra_flags, ZEBRA_FLAG_STATIC); /* This is a reject or blackhole route */ if (flags & RTF_REJECT) SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT); if (flags & RTF_BLACKHOLE) SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE); if (dest.sa.sa_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; p.prefix = dest.sin.sin_addr; if (flags & RTF_HOST) p.prefixlen = IPV4_MAX_PREFIXLEN; else p.prefixlen = ip_masklen (mask.sin.sin_addr); /* Catch self originated messages and match them against our current RIB. * At the same time, ignore unconfirmed messages, they should be tracked * by rtm_write() and kernel_rtm_ipv4(). */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) { char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN]; int ret; if (! IS_ZEBRA_DEBUG_RIB) return; ret = rib_lookup_ipv4_route (&p, &gate); inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN); switch (rtm->rtm_type) { case RTM_ADD: case RTM_GET: case RTM_CHANGE: /* The kernel notifies us about a new route in FIB created by us. Do we have a correspondent entry in our RIB? */ switch (ret) { case ZEBRA_RIB_NOTFOUND: zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN); zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf); break; case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); return; break; } break; case RTM_DELETE: /* The kernel notifies us about a route deleted by us. Do we still have it in the RIB? Do we have anything instead? */ switch (ret) { case ZEBRA_RIB_FOUND_EXACT: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_FOUND_CONNECTED: case ZEBRA_RIB_FOUND_NOGATE: zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); break; case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */ zlog_debug ("%s: %s %s/%d: done Ok", __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen); rib_lookup_and_dump (&p); return; break; } break; default: zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received", __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type)); } return; } /* Change, delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin.sin_addr, 0, 0, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (dest.sa.sa_family == AF_INET6) { /* One day we might have a debug section here like one in the * IPv4 case above. Just ignore own messages at the moment. */ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid) return; struct prefix_ipv6 p; unsigned int ifindex = 0; p.family = AF_INET6; p.prefix = dest.sin6.sin6_addr; if (flags & RTF_HOST) p.prefixlen = IPV6_MAX_PREFIXLEN; else p.prefixlen = ip6_masklen (mask.sin6.sin6_addr); #ifdef KAME if (IN6_IS_ADDR_LINKLOCAL (&gate.sin6.sin6_addr)) { ifindex = IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr); SET_IN6_LINKLOCAL_IFINDEX (gate.sin6.sin6_addr, 0); } #endif /* KAME */ /* CHANGE: delete the old prefix, we have no further information * to specify the route really */ if (rtm->rtm_type == RTM_CHANGE) rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, NULL, 0, 0, SAFI_UNICAST); if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD || rtm->rtm_type == RTM_CHANGE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p, &gate.sin6.sin6_addr, ifindex, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ } /* Interface function for the kernel routing table updates. Support * for RTM_CHANGE will be needed. * Exported only for rt_socket.c */ int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric) { int ret; caddr_t pnt; struct interface *ifp; /* Sequencial number of routing message. */ static int msg_seq = 0; /* Struct of rt_msghdr and buffer for storing socket's data. */ struct { struct rt_msghdr rtm; char buf[512]; } msg; if (routing_sock < 0) return ZEBRA_ERR_EPERM; /* Clear and set rt_msghdr values */ memset (&msg, 0, sizeof (struct rt_msghdr)); msg.rtm.rtm_version = RTM_VERSION; msg.rtm.rtm_type = message; msg.rtm.rtm_seq = msg_seq++; msg.rtm.rtm_addrs = RTA_DST; msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags = RTF_UP; msg.rtm.rtm_index = index; if (metric != 0) { msg.rtm.rtm_rmx.rmx_hopcount = metric; msg.rtm.rtm_inits |= RTV_HOPCOUNT; } ifp = if_lookup_by_index (index); if (gate && message == RTM_ADD) msg.rtm.rtm_flags |= RTF_GATEWAY; /* When RTF_CLONING is unavailable on BSD, should we set some * other flag instead? */ #ifdef RTF_CLONING if (! gate && message == RTM_ADD && ifp && (ifp->flags & IFF_POINTOPOINT) == 0) msg.rtm.rtm_flags |= RTF_CLONING; #endif /* RTF_CLONING */ /* If no protocol specific gateway is specified, use link address for gateway. */ if (! gate) { if (!ifp) { char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255"; if (dest) inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN); if (mask) inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN); zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d", __func__, dest_buf, mask_buf, index); return -1; } gate = (union sockunion *) & ifp->sdl; } if (mask) msg.rtm.rtm_addrs |= RTA_NETMASK; else if (message == RTM_ADD) msg.rtm.rtm_flags |= RTF_HOST; /* Tagging route with flags */ msg.rtm.rtm_flags |= (RTF_PROTO1); /* Additional flags. */ if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) msg.rtm.rtm_flags |= RTF_BLACKHOLE; if (zebra_flags & ZEBRA_FLAG_REJECT) msg.rtm.rtm_flags |= RTF_REJECT; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = ROUNDUP ((X)->sa.sa_len); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #else #define SOCKADDRSET(X,R) \ if (msg.rtm.rtm_addrs & (R)) \ { \ int len = SAROUNDUP (X); \ memcpy (pnt, (caddr_t)(X), len); \ pnt += len; \ } #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ pnt = (caddr_t) msg.buf; /* Write each socket data into rtm message buffer */ SOCKADDRSET (dest, RTA_DST); SOCKADDRSET (gate, RTA_GATEWAY); SOCKADDRSET (mask, RTA_NETMASK); msg.rtm.rtm_msglen = pnt - (caddr_t) &msg; ret = write (routing_sock, &msg, msg.rtm.rtm_msglen); if (ret != msg.rtm.rtm_msglen) { if (errno == EEXIST) return ZEBRA_ERR_RTEXIST; if (errno == ENETUNREACH) return ZEBRA_ERR_RTUNREACH; if (errno == ESRCH) return ZEBRA_ERR_RTNOEXIST; zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno); return ZEBRA_ERR_KERNEL; } return ZEBRA_ERR_NOERROR; } #include "thread.h" #include "zebra/zserv.h" /* For debug purpose. */ static void rtmsg_debug (struct rt_msghdr *rtm) { zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup (rtm_type_str, rtm->rtm_type)); rtm_flag_dump (rtm->rtm_flags); zlog_debug ("Kernel: message seq %d", rtm->rtm_seq); zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs); } /* This is pretty gross, better suggestions welcome -- mhandler */ #ifndef RTAX_MAX #ifdef RTA_NUMBITS #define RTAX_MAX RTA_NUMBITS #else #define RTAX_MAX 8 #endif /* RTA_NUMBITS */ #endif /* RTAX_MAX */ /* Kernel routing table and interface updates via routing socket. */ static int kernel_read (struct thread *thread) { int sock; int nbytes; struct rt_msghdr *rtm; /* * This must be big enough for any message the kernel might send. * Rather than determining how many sockaddrs of what size might be * in each particular message, just use RTAX_MAX of sockaddr_storage * for each. Note that the sockaddrs must be after each message * definition, or rather after whichever happens to be the largest, * since the buffer needs to be big enough for a message and the * sockaddrs together. */ union { /* Routing information. */ struct { struct rt_msghdr rtm; struct sockaddr_storage addr[RTAX_MAX]; } r; /* Interface information. */ struct { struct if_msghdr ifm; struct sockaddr_storage addr[RTAX_MAX]; } im; /* Interface address information. */ struct { struct ifa_msghdr ifa; struct sockaddr_storage addr[RTAX_MAX]; } ia; #ifdef RTM_IFANNOUNCE /* Interface arrival/departure */ struct { struct if_announcemsghdr ifan; struct sockaddr_storage addr[RTAX_MAX]; } ian; #endif /* RTM_IFANNOUNCE */ } buf; /* Fetch routing socket. */ sock = THREAD_FD (thread); nbytes= read (sock, &buf, sizeof buf); if (nbytes <= 0) { if (nbytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN) zlog_warn ("routing socket error: %s", safe_strerror (errno)); return 0; } thread_add_read (zebrad.master, kernel_read, NULL, sock); if (IS_ZEBRA_DEBUG_KERNEL) rtmsg_debug (&buf.r.rtm); rtm = &buf.r.rtm; /* * Ensure that we didn't drop any data, so that processing routines * can assume they have the whole message. */ if (rtm->rtm_msglen != nbytes) { zlog_warn ("kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d\n", rtm->rtm_msglen, nbytes, rtm->rtm_type); return -1; } switch (rtm->rtm_type) { case RTM_ADD: case RTM_DELETE: case RTM_CHANGE: rtm_read (rtm); break; case RTM_IFINFO: ifm_read (&buf.im.ifm); break; case RTM_NEWADDR: case RTM_DELADDR: ifam_read (&buf.ia.ifa); break; #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: ifan_read (&buf.ian.ifan); break; #endif /* RTM_IFANNOUNCE */ default: if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Unprocessed RTM_type: %d", rtm->rtm_type); break; } return 0; } /* Make routing socket. */ static void routing_socket (void) { if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("routing_socket: Can't raise privileges"); routing_sock = socket (AF_ROUTE, SOCK_RAW, 0); if (routing_sock < 0) { if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); zlog_warn ("Can't init kernel routing socket"); return; } /* XXX: Socket should be NONBLOCK, however as we currently * discard failed writes, this will lead to inconsistencies. * For now, socket must be blocking. */ /*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0) zlog_warn ("Can't set O_NONBLOCK to routing socket");*/ if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); /* kernel_read needs rewrite. */ thread_add_read (zebrad.master, kernel_read, NULL, routing_sock); } /* Exported interface function. This function simply calls routing_socket (). */ void kernel_init (void) { routing_socket (); } quagga-0.99.24.1/zebra/rtread_getmsg.c0000644000175000017500000001415512476520570014340 00000000000000/* * Kernel routing table readup by getmsg(2) * Copyright (C) 1999 Michael Handler * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "prefix.h" #include "log.h" #include "if.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include #include /* Solaris defines these in both and , sigh */ #ifdef SUNOS_5 #include #ifndef T_CURRENT #define T_CURRENT MI_T_CURRENT #endif /* T_CURRENT */ #ifndef IRE_CACHE #define IRE_CACHE 0x0020 /* Cached Route entry */ #endif /* IRE_CACHE */ #ifndef IRE_HOST_REDIRECT #define IRE_HOST_REDIRECT 0x0200 /* Host route entry from redirects */ #endif /* IRE_HOST_REDIRECT */ #ifndef IRE_CACHETABLE #define IRE_CACHETABLE (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \ IRE_LOOPBACK) #endif /* IRE_CACHETABLE */ #undef IPOPT_EOL #undef IPOPT_NOP #undef IPOPT_LSRR #undef IPOPT_RR #undef IPOPT_SSRR #endif /* SUNOS_5 */ #include #include #include /* device to read IP routing table from */ #ifndef _PATH_GETMSG_ROUTE #define _PATH_GETMSG_ROUTE "/dev/ip" #endif /* _PATH_GETMSG_ROUTE */ #define RT_BUFSIZ 8192 static void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) { struct prefix_ipv4 prefix; struct in_addr tmpaddr, gateway; u_char zebra_flags = 0; if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) return; if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) zebra_flags |= ZEBRA_FLAG_SELFROUTE; prefix.family = AF_INET; tmpaddr.s_addr = routeEntry->ipRouteDest; prefix.prefix = tmpaddr; tmpaddr.s_addr = routeEntry->ipRouteMask; prefix.prefixlen = ip_masklen (tmpaddr); gateway.s_addr = routeEntry->ipRouteNextHop; rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, &gateway, NULL, 0, 0, 0, 0, SAFI_UNICAST); } void route_read (void) { char storage[RT_BUFSIZ]; struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage; struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage; struct T_error_ack *TLIerr = (struct T_error_ack *) storage; struct opthdr *MIB2hdr; mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry; struct strbuf msgdata; int flags, dev, retval, process; if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, safe_strerror (errno)); return; } TLIreq->PRIM_type = T_OPTMGMT_REQ; TLIreq->OPT_offset = sizeof (struct T_optmgmt_req); TLIreq->OPT_length = sizeof (struct opthdr); TLIreq->MGMT_flags = T_CURRENT; MIB2hdr = (struct opthdr *) &TLIreq[1]; MIB2hdr->level = MIB2_IP; MIB2hdr->name = 0; MIB2hdr->len = 0; msgdata.buf = storage; msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr); flags = 0; if (putmsg (dev, &msgdata, NULL, flags) == -1) { zlog_warn ("putmsg failed: %s", safe_strerror (errno)); goto exit; } MIB2hdr = (struct opthdr *) &TLIack[1]; msgdata.maxlen = sizeof (storage); while (1) { flags = 0; retval = getmsg (dev, &msgdata, NULL, &flags); if (retval == -1) { zlog_warn ("getmsg(ctl) failed: %s", safe_strerror (errno)); goto exit; } /* This is normal loop termination */ if (retval == 0 && msgdata.len >= sizeof (struct T_optmgmt_ack) && TLIack->PRIM_type == T_OPTMGMT_ACK && TLIack->MGMT_flags == T_SUCCESS && MIB2hdr->len == 0) break; if (msgdata.len >= sizeof (struct T_error_ack) && TLIerr->PRIM_type == T_ERROR_ACK) { zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", safe_strerror ((TLIerr->TLI_error == TSYSERR) ? TLIerr->UNIX_error : EPROTO)); break; } /* should dump more debugging info to the log statement, like what GateD does in this instance, but not critical yet. */ if (retval != MOREDATA || msgdata.len < sizeof (struct T_optmgmt_ack) || TLIack->PRIM_type != T_OPTMGMT_ACK || TLIack->MGMT_flags != T_SUCCESS) { errno = ENOMSG; zlog_warn ("getmsg(ctl) returned bizarreness"); break; } /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable entry, see . "This isn't the MIB data you're looking for." */ process = (MIB2hdr->level == MIB2_IP && MIB2hdr->name == MIB2_IP_21) ? 1 : 0; /* getmsg writes the data buffer out completely, not to the closest smaller multiple. Unless reassembling data structures across buffer boundaries is your idea of a good time, set maxlen to the closest smaller multiple of the size of the datastructure you're retrieving. */ msgdata.maxlen = sizeof (storage) - (sizeof (storage) % sizeof (mib2_ipRouteEntry_t)); msgdata.len = 0; flags = 0; do { retval = getmsg (dev, NULL, &msgdata, &flags); if (retval == -1) { zlog_warn ("getmsg(data) failed: %s", safe_strerror (errno)); goto exit; } if (!(retval == 0 || retval == MOREDATA)) { zlog_warn ("getmsg(data) returned %d", retval); goto exit; } if (process) { if (msgdata.len % sizeof (mib2_ipRouteEntry_t) != 0) { zlog_warn ("getmsg(data) returned " "msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len); goto exit; } routeEntry = (mib2_ipRouteEntry_t *) msgdata.buf; lastRouteEntry = (mib2_ipRouteEntry_t *) (msgdata.buf + msgdata.len); do { handle_route_entry (routeEntry); } while (++routeEntry < lastRouteEntry); } } while (retval == MOREDATA); } exit: close (dev); } quagga-0.99.24.1/zebra/rtread_sysctl.c0000644000175000017500000000376412476520570014377 00000000000000/* * Kernel routing table read by sysctl function. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "log.h" #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" /* Kernel routing table read up by sysctl function. */ void route_read (void) { caddr_t buf, end, ref; size_t bufsiz; struct rt_msghdr *rtm; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 }; /* Get buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog_warn ("sysctl fail: %s", safe_strerror (errno)); return; } /* Allocate buffer. */ ref = buf = XMALLOC (MTYPE_TMP, bufsiz); /* Read routing table information by calling sysctl(). */ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) { zlog_warn ("sysctl() fail by %s", safe_strerror (errno)); return; } for (end = buf + bufsiz; buf < end; buf += rtm->rtm_msglen) { rtm = (struct rt_msghdr *) buf; /* We must set RTF_DONE here, so rtm_read() doesn't ignore the message. */ SET_FLAG (rtm->rtm_flags, RTF_DONE); rtm_read (rtm); } /* Free buffer. */ XFREE (MTYPE_TMP, ref); return; } quagga-0.99.24.1/zebra/rtread_netlink.c0000644000175000017500000000173312476520570014514 00000000000000/* * Kernel routing table readup by netlink * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "zebra/zserv.h" extern void netlink_route_read (void); void route_read (void) { netlink_route_read (); } quagga-0.99.24.1/zebra/rt_socket.c0000644000175000017500000003223512476520570013505 00000000000000/* * Kernel routing table updates by routing socket. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "prefix.h" #include "sockunion.h" #include "log.h" #include "str.h" #include "privs.h" #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" extern struct zebra_privs_t zserv_privs; /* kernel socket export */ extern int rtm_write (int message, union sockunion *dest, union sockunion *mask, union sockunion *gate, unsigned int index, int zebra_flags, int metric); /* Adjust netmask socket length. Return value is a adjusted sin_len value. */ static int sin_masklen (struct in_addr mask) { char *p, *lim; int len; struct sockaddr_in sin; if (mask.s_addr == 0) return sizeof (long); sin.sin_addr = mask; len = sizeof (struct sockaddr_in); lim = (char *) &sin.sin_addr; p = lim + sizeof (sin.sin_addr); while (*--p == 0 && p >= lim) len--; return len; } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) { struct sockaddr_in *mask = NULL; struct sockaddr_in sin_dest, sin_mask, sin_gate; struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; unsigned int ifindex = 0; int gate = 0; int error; char prefix_buf[INET_ADDRSTRLEN]; if (IS_ZEBRA_DEBUG_RIB) inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); memset (&sin_dest, 0, sizeof (struct sockaddr_in)); sin_dest.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_dest.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_dest.sin_addr = p->u.prefix4; memset (&sin_mask, 0, sizeof (struct sockaddr_in)); memset (&sin_gate, 0, sizeof (struct sockaddr_in)); sin_gate.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; gate = 0; char gate_buf[INET_ADDRSTRLEN] = "NULL"; /* * XXX We need to refrain from kernel operations in some cases, * but this if statement seems overly cautious - what about * other than ADD and DELETE? */ if ((cmd == RTM_ADD && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELETE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) )) { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { sin_gate.sin_addr = nexthop->gate.ipv4; gate = 1; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) ifindex = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { struct in_addr loopback; loopback.s_addr = htonl (INADDR_LOOPBACK); sin_gate.sin_addr = loopback; gate = 1; } if (gate && p->prefixlen == 32) mask = NULL; else { masklen2ip (p->prefixlen, &sin_mask.sin_addr); sin_mask.sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_mask.sin_len = sin_masklen (sin_mask.sin_addr); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ mask = &sin_mask; } error = rtm_write (cmd, (union sockunion *)&sin_dest, (union sockunion *)mask, gate ? (union sockunion *)&sin_gate : NULL, ifindex, rib->flags, rib->metric); if (IS_ZEBRA_DEBUG_RIB) { if (!gate) { zlog_debug ("%s: %s/%d: attention! gate not found for rib %p", __func__, prefix_buf, p->prefixlen, rib); rib_dump (p, rib); } else inet_ntop (AF_INET, &sin_gate.sin_addr, gate_buf, INET_ADDRSTRLEN); } switch (error) { /* We only flag nexthops as being in FIB if rtm_write() did its work. */ case ZEBRA_ERR_NOERROR: nexthop_num++; if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: %s/%d: successfully did NH %s", __func__, prefix_buf, p->prefixlen, gate_buf); if (cmd == RTM_ADD) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); break; /* The only valid case for this error is kernel's failure to install * a multipath route, which is common for FreeBSD. This should be * ignored silently, but logged as an error otherwise. */ case ZEBRA_ERR_RTEXIST: if (cmd != RTM_ADD) zlog_err ("%s: rtm_write() returned %d for command %d", __func__, error, cmd); continue; break; /* Given that our NEXTHOP_FLAG_FIB matches real kernel FIB, it isn't * normal to get any other messages in ANY case. */ case ZEBRA_ERR_RTNOEXIST: case ZEBRA_ERR_RTUNREACH: default: /* This point is reachable regardless of debugging mode. */ if (!IS_ZEBRA_DEBUG_RIB) inet_ntop (AF_INET, &p->u.prefix, prefix_buf, INET_ADDRSTRLEN); zlog_err ("%s: %s/%d: rtm_write() unexpectedly returned %d for command %s", __func__, prefix_buf, p->prefixlen, error, lookup (rtm_type_str, cmd)); break; } } /* if (cmd and flags make sense) */ else if (IS_ZEBRA_DEBUG_RIB) zlog_debug ("%s: odd command %s for flags %d", __func__, lookup (rtm_type_str, cmd), nexthop->flags); } /* for (ALL_NEXTHOPS_RO(...))*/ /* If there was no useful nexthop, then complain. */ if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: No useful nexthops were found in RIB entry %p", __func__, rib); return 0; /*XXX*/ } int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } #ifdef HAVE_IPV6 /* Calculate sin6_len value for netmask socket value. */ static int sin6_masklen (struct in6_addr mask) { struct sockaddr_in6 sin6; char *p, *lim; int len; if (IN6_IS_ADDR_UNSPECIFIED (&mask)) return sizeof (long); sin6.sin6_addr = mask; len = sizeof (struct sockaddr_in6); lim = (char *) & sin6.sin6_addr; p = lim + sizeof (sin6.sin6_addr); while (*--p == 0 && p >= lim) len--; return len; } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, struct in6_addr *gate, int index, int flags) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); sin_dest.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_dest.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); sin_gate.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_gate.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ sin_dest.sin6_addr = dest->prefix; if (gate) memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr)); /* Under kame set interface index to link local address. */ #ifdef KAME #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ do { \ (a).s6_addr[2] = ((i) >> 8) & 0xff; \ (a).s6_addr[3] = (i) & 0xff; \ } while (0) if (gate && IN6_IS_ADDR_LINKLOCAL(gate)) SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index); #endif /* KAME */ if (gate && dest->prefixlen == 128) mask = NULL; else { masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr); sin_mask.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); #endif /* SIN6_LEN */ mask = &sin_mask; } return rtm_write (message, (union sockunion *) &sin_dest, (union sockunion *) mask, gate ? (union sockunion *)&sin_gate : NULL, index, flags, 0); } /* Interface between zebra message and rtm message. */ static int kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, int family) { struct sockaddr_in6 *mask; struct sockaddr_in6 sin_dest, sin_mask, sin_gate; struct nexthop *nexthop, *tnexthop; int recursing; int nexthop_num = 0; unsigned int ifindex = 0; int gate = 0; int error; memset (&sin_dest, 0, sizeof (struct sockaddr_in6)); sin_dest.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_dest.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ sin_dest.sin6_addr = p->u.prefix6; memset (&sin_mask, 0, sizeof (struct sockaddr_in6)); memset (&sin_gate, 0, sizeof (struct sockaddr_in6)); sin_gate.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sin_gate.sin6_len = sizeof (struct sockaddr_in6); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ /* Make gateway. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; gate = 0; if ((cmd == RTM_ADD && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELETE #if 0 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) #endif )) { if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { sin_gate.sin6_addr = nexthop->gate.ipv6; gate = 1; } if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) ifindex = nexthop->ifindex; if (cmd == RTM_ADD) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } /* Under kame set interface index to link local address. */ #ifdef KAME #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ do { \ (a).s6_addr[2] = ((i) >> 8) & 0xff; \ (a).s6_addr[3] = (i) & 0xff; \ } while (0) if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr)) SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex); #endif /* KAME */ if (gate && p->prefixlen == 128) mask = NULL; else { masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr); sin_mask.sin6_family = AF_INET6; #ifdef SIN6_LEN sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr); #endif /* SIN6_LEN */ mask = &sin_mask; } error = rtm_write (cmd, (union sockunion *) &sin_dest, (union sockunion *) mask, gate ? (union sockunion *)&sin_gate : NULL, ifindex, rib->flags, rib->metric); #if 0 if (error) { zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.", nexthop_num, error); } #endif nexthop_num++; } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("kernel_rtm_ipv6_multipath(): No useful nexthop."); return 0; } return 0; /*XXX*/ } int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { int route; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); route = kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return route; } #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/rt_netlink.c0000644000175000017500000015464012476520570013666 00000000000000/* Kernel routing table updates using netlink over GNU/Linux system. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include /* Hack for GNU libc version 2. */ #ifndef MSG_TRUNC #define MSG_TRUNC 0x20 #endif /* MSG_TRUNC */ #include "linklist.h" #include "if.h" #include "log.h" #include "prefix.h" #include "connected.h" #include "table.h" #include "memory.h" #include "rib.h" #include "thread.h" #include "privs.h" #include "zebra/zserv.h" #include "zebra/rt.h" #include "zebra/redistribute.h" #include "zebra/interface.h" #include "zebra/debug.h" #include "rt_netlink.h" /* Socket interface to kernel */ struct nlsock { int sock; int seq; struct sockaddr_nl snl; const char *name; } netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */ netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */ static const struct message nlmsg_str[] = { {RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_DELROUTE, "RTM_DELROUTE"}, {RTM_GETROUTE, "RTM_GETROUTE"}, {RTM_NEWLINK, "RTM_NEWLINK"}, {RTM_DELLINK, "RTM_DELLINK"}, {RTM_GETLINK, "RTM_GETLINK"}, {RTM_NEWADDR, "RTM_NEWADDR"}, {RTM_DELADDR, "RTM_DELADDR"}, {RTM_GETADDR, "RTM_GETADDR"}, {0, NULL} }; extern struct zebra_t zebrad; extern struct zebra_privs_t zserv_privs; extern u_int32_t nl_rcvbufsize; /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void set_ifindex(struct interface *ifp, unsigned int ifi_index) { struct interface *oifp; if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp)) { if (ifi_index == IFINDEX_INTERNAL) zlog_err("Netlink is setting interface %s ifindex to reserved " "internal value %u", ifp->name, ifi_index); else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface index %d was renamed from %s to %s", ifi_index, oifp->name, ifp->name); if (if_is_up(oifp)) zlog_err("interface rename detected on up interface: index %d " "was renamed from %s to %s, results are uncertain!", ifi_index, oifp->name, ifp->name); if_delete_update(oifp); } } ifp->ifindex = ifi_index; } #ifndef SO_RCVBUFFORCE #define SO_RCVBUFFORCE (33) #endif static int netlink_recvbuf (struct nlsock *nl, uint32_t newsize) { u_int32_t oldsize; socklen_t newlen = sizeof(newsize); socklen_t oldlen = sizeof(oldsize); int ret; ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } /* Try force option (linux >= 2.6.14) and fall back to normal set */ if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("routing_socket: Can't raise privileges"); ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize, sizeof(nl_rcvbufsize)); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("routing_socket: Can't lower privileges"); if (ret < 0) ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize, sizeof(nl_rcvbufsize)); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name, safe_strerror (errno)); return -1; } zlog (NULL, LOG_INFO, "Setting netlink socket receive buffer size: %u -> %u", oldsize, newsize); return 0; } /* Make socket for Linux netlink interface. */ static int netlink_socket (struct nlsock *nl, unsigned long groups) { int ret; struct sockaddr_nl snl; int sock; int namelen; int save_errno; if (zserv_privs.change (ZPRIVS_RAISE)) { zlog (NULL, LOG_ERR, "Can't raise privileges"); return -1; } sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (sock < 0) { zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name, safe_strerror (errno)); return -1; } memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; snl.nl_groups = groups; /* Bind the socket to the netlink structure for anything. */ ret = bind (sock, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog (NULL, LOG_ERR, "Can't bind %s socket to group 0x%x: %s", nl->name, snl.nl_groups, safe_strerror (save_errno)); close (sock); return -1; } /* multiple netlink sockets will have different nl_pid */ namelen = sizeof snl; ret = getsockname (sock, (struct sockaddr *) &snl, (socklen_t *) &namelen); if (ret < 0 || namelen != sizeof snl) { zlog (NULL, LOG_ERR, "Can't get %s socket name: %s", nl->name, safe_strerror (errno)); close (sock); return -1; } nl->snl = snl; nl->sock = sock; return ret; } /* Get type specified information from netlink. */ static int netlink_request (int family, int type, struct nlsock *nl) { int ret; struct sockaddr_nl snl; int save_errno; struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; /* Check netlink socket. */ if (nl->sock < 0) { zlog (NULL, LOG_ERR, "%s socket isn't active.", nl->name); return -1; } memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; memset (&req, 0, sizeof req); req.nlh.nlmsg_len = sizeof req; req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = nl->snl.nl_pid; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; /* linux appears to check capabilities on every message * have to raise caps for every message sent */ if (zserv_privs.change (ZPRIVS_RAISE)) { zlog (NULL, LOG_ERR, "Can't raise privileges"); return -1; } ret = sendto (nl->sock, (void *) &req, sizeof req, 0, (struct sockaddr *) &snl, sizeof snl); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog (NULL, LOG_ERR, "%s sendto failed: %s", nl->name, safe_strerror (save_errno)); return -1; } return 0; } /* Receive message from netlink interface and pass those information to the given function. */ static int netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), struct nlsock *nl) { int status; int ret = 0; int error; while (1) { char buf[NL_PKT_BUF_SIZE]; struct iovec iov = { .iov_base = buf, .iov_len = sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { .msg_name = (void *) &snl, .msg_namelen = sizeof snl, .msg_iov = &iov, .msg_iovlen = 1 }; struct nlmsghdr *h; status = recvmsg (nl->sock, &msg, 0); if (status < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) break; zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s", nl->name, safe_strerror(errno)); continue; } if (status == 0) { zlog (NULL, LOG_ERR, "%s EOF", nl->name); return -1; } if (msg.msg_namelen != sizeof snl) { zlog (NULL, LOG_ERR, "%s sender address length error: length %d", nl->name, msg.msg_namelen); return -1; } for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status); h = NLMSG_NEXT (h, status)) { /* Finish of reading. */ if (h->nlmsg_type == NLMSG_DONE) return ret; /* Error handling. */ if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h); int errnum = err->error; int msg_type = err->msg.nlmsg_type; /* If the error field is zero, then this is an ACK */ if (err->error == 0) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("%s: %s ACK: type=%s(%u), seq=%u, pid=%u", __FUNCTION__, nl->name, lookup (nlmsg_str, err->msg.nlmsg_type), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); } /* return if not a multipart message, otherwise continue */ if (!(h->nlmsg_flags & NLM_F_MULTI)) { return 0; } continue; } if (h->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) { zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); return -1; } /* Deal with errors that occur because of races in link handling */ if (nl == &netlink_cmd && ((msg_type == RTM_DELROUTE && (-errnum == ENODEV || -errnum == ESRCH)) || (msg_type == RTM_NEWROUTE && -errnum == EEXIST))) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return 0; } zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u", nl->name, safe_strerror (-errnum), lookup (nlmsg_str, msg_type), msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return -1; } /* OK we got netlink message. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s type %s(%u), seq=%u, pid=%u", nl->name, lookup (nlmsg_str, h->nlmsg_type), h->nlmsg_type, h->nlmsg_seq, h->nlmsg_pid); /* skip unsolicited messages originating from command socket * linux sets the originators port-id for {NEW|DEL}ADDR messages, * so this has to be checked here. */ if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid && (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_parse_info: %s packet comes from %s", netlink_cmd.name, nl->name); continue; } error = (*filter) (&snl, h); if (error < 0) { zlog (NULL, LOG_ERR, "%s filter function error", nl->name); ret = error; } } /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { zlog (NULL, LOG_ERR, "%s error: message truncated", nl->name); continue; } if (status) { zlog (NULL, LOG_ERR, "%s error: data remnant size %d", nl->name, status); return -1; } } return ret; } /* Utility function for parse rtattr. */ static void netlink_parse_rtattr (struct rtattr **tb, int max, struct rtattr *rta, int len) { while (RTA_OK (rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT (rta, len); } } /* Utility function to parse hardware link-layer address and update ifp */ static void netlink_interface_update_hw_addr (struct rtattr **tb, struct interface *ifp) { int i; if (tb[IFLA_ADDRESS]) { int hw_addr_len; hw_addr_len = RTA_PAYLOAD (tb[IFLA_ADDRESS]); if (hw_addr_len > INTERFACE_HWADDR_MAX) zlog_warn ("Hardware address is too large: %d", hw_addr_len); else { ifp->hw_addr_len = hw_addr_len; memcpy (ifp->hw_addr, RTA_DATA (tb[IFLA_ADDRESS]), hw_addr_len); for (i = 0; i < hw_addr_len; i++) if (ifp->hw_addr[i] != 0) break; if (i == hw_addr_len) ifp->hw_addr_len = 0; else ifp->hw_addr_len = hw_addr_len; } } } /* Called from interface_lookup_netlink(). This function is only used during bootstrap. */ static int netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (h->nlmsg_type != RTM_NEWLINK) return 0; len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } #endif /* IFLA_WIRELESS */ if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ ifp = if_get_by_name (name); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; /* Hardware type and address. */ ifp->hw_type = ifi->ifi_type; netlink_interface_update_hw_addr (tb, ifp); if_add_update (ifp); return 0; } /* Lookup interface IPv4/IPv6 address. */ static int netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; struct interface *ifp; void *addr; void *broad; u_char flags = 0; char *label = NULL; ifa = NLMSG_DATA (h); if (ifa->ifa_family != AF_INET #ifdef HAVE_IPV6 && ifa->ifa_family != AF_INET6 #endif /* HAVE_IPV6 */ ) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len); ifp = if_lookup_by_index (ifa->ifa_index); if (ifp == NULL) { zlog_err ("netlink_interface_addr can't find interface by index %d", ifa->ifa_index); return -1; } if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ { char buf[BUFSIZ]; zlog_debug ("netlink_interface_addr %s %s:", lookup (nlmsg_str, h->nlmsg_type), ifp->name); if (tb[IFA_LOCAL]) zlog_debug (" IFA_LOCAL %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_ADDRESS]) zlog_debug (" IFA_ADDRESS %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_ADDRESS]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_BROADCAST]) zlog_debug (" IFA_BROADCAST %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_BROADCAST]), buf, BUFSIZ), ifa->ifa_prefixlen); if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL]))) zlog_debug (" IFA_LABEL %s", (char *)RTA_DATA (tb[IFA_LABEL])); if (tb[IFA_CACHEINFO]) { struct ifa_cacheinfo *ci = RTA_DATA (tb[IFA_CACHEINFO]); zlog_debug (" IFA_CACHEINFO pref %d, valid %d", ci->ifa_prefered, ci->ifa_valid); } } /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); /* is there a peer address? */ if (tb[IFA_ADDRESS] && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), RTA_PAYLOAD(tb[IFA_ADDRESS]))) { broad = RTA_DATA(tb[IFA_ADDRESS]); SET_FLAG (flags, ZEBRA_IFA_PEER); } else /* seeking a broadcast address */ broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) : NULL); /* addr is primary key, SOL if we don't have one */ if (addr == NULL) { zlog_debug ("%s: NULL address", __func__); return -1; } /* Flags. */ if (ifa->ifa_flags & IFA_F_SECONDARY) SET_FLAG (flags, ZEBRA_IFA_SECONDARY); /* Label */ if (tb[IFA_LABEL]) label = (char *) RTA_DATA (tb[IFA_LABEL]); if (ifp && label && strcmp (ifp->name, label) == 0) label = NULL; /* Register interface address to the interface. */ if (ifa->ifa_family == AF_INET) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad, label); else connected_delete_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, (struct in_addr *) broad); } #ifdef HAVE_IPV6 if (ifa->ifa_family == AF_INET6) { if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad, label); else connected_delete_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, (struct in6_addr *) broad); } #endif /* HAVE_IPV6 */ return 0; } /* Looking up routing table by netlink interface. */ static int netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char flags = 0; char anyaddr[16] = { 0 }; int index; int table; int metric; void *dest; void *gate; void *src; rtm = NLMSG_DATA (h); if (h->nlmsg_type != RTM_NEWROUTE) return 0; if (rtm->rtm_type != RTN_UNICAST) return 0; table = rtm->rtm_table; #if 0 /* we weed them out later in rib_weed_tables () */ if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default) return 0; #endif len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; if (rtm->rtm_src_len != 0) return 0; /* Route which inserted by Zebra. */ if (rtm->rtm_protocol == RTPROT_ZEBRA) flags |= ZEBRA_FLAG_SELFROUTE; index = 0; metric = 0; dest = NULL; gate = NULL; src = NULL; if (tb[RTA_OIF]) index = *(int *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_DST]) dest = RTA_DATA (tb[RTA_DST]); else dest = anyaddr; if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (tb[RTA_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); else { /* This is a multipath route */ struct rib *rib; struct rtnexthop *rtnh = (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = flags; rib->metric = metric; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; rib->nexthop_num++; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) { memset (tb, 0, sizeof (tb)); netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), rtnh->rtnh_len - sizeof (*rtnh)); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); } if (gate) { if (index) nexthop_ipv4_ifindex_add (rib, gate, src, index); else nexthop_ipv4_add (rib, gate, src); } else nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); } } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, metric, 0, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ return 0; } static const struct message rtproto_str[] = { {RTPROT_REDIRECT, "redirect"}, {RTPROT_KERNEL, "kernel"}, {RTPROT_BOOT, "boot"}, {RTPROT_STATIC, "static"}, {RTPROT_GATED, "GateD"}, {RTPROT_RA, "router advertisement"}, {RTPROT_MRT, "MRT"}, {RTPROT_ZEBRA, "Zebra"}, #ifdef RTPROT_BIRD {RTPROT_BIRD, "BIRD"}, #endif /* RTPROT_BIRD */ {0, NULL} }; /* Routing information change from the kernel. */ static int netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; char anyaddr[16] = { 0 }; int index; int table; int metric; void *dest; void *gate; void *src; rtm = NLMSG_DATA (h); if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { /* If this is not route add/delete message print warning. */ zlog_warn ("Kernel message: %d\n", h->nlmsg_type); return 0; } /* Connected route. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s %s %s proto %s", h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", lookup (rtproto_str, rtm->rtm_protocol)); if (rtm->rtm_type != RTN_UNICAST) { return 0; } table = rtm->rtm_table; if (table != RT_TABLE_MAIN && table != zebrad.rtm_table_default) { return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); if (len < 0) return -1; memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); if (rtm->rtm_flags & RTM_F_CLONED) return 0; if (rtm->rtm_protocol == RTPROT_REDIRECT) return 0; if (rtm->rtm_protocol == RTPROT_KERNEL) return 0; if (rtm->rtm_protocol == RTPROT_ZEBRA && h->nlmsg_type == RTM_NEWROUTE) return 0; if (rtm->rtm_src_len != 0) { zlog_warn ("netlink_route_change(): no src len"); return 0; } index = 0; metric = 0; dest = NULL; gate = NULL; src = NULL; if (tb[RTA_OIF]) index = *(int *) RTA_DATA (tb[RTA_OIF]); if (tb[RTA_DST]) dest = RTA_DATA (tb[RTA_DST]); else dest = anyaddr; if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); if (tb[RTA_PREFSRC]) src = RTA_DATA (tb[RTA_PREFSRC]); if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY]) metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); if (rtm->rtm_family == AF_INET) { struct prefix_ipv4 p; p.family = AF_INET; memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_debug ("RTM_NEWROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); else zlog_debug ("RTM_DELROUTE %s/%d", inet_ntoa (p.prefix), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) { if (!tb[RTA_MULTIPATH]) rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0, SAFI_UNICAST); else { /* This is a multipath route */ struct rib *rib; struct rtnexthop *rtnh = (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); rib->type = ZEBRA_ROUTE_KERNEL; rib->distance = 0; rib->flags = 0; rib->metric = metric; rib->table = table; rib->nexthop_num = 0; rib->uptime = time (NULL); for (;;) { if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) break; rib->nexthop_num++; index = rtnh->rtnh_ifindex; gate = 0; if (rtnh->rtnh_len > sizeof (*rtnh)) { memset (tb, 0, sizeof (tb)); netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), rtnh->rtnh_len - sizeof (*rtnh)); if (tb[RTA_GATEWAY]) gate = RTA_DATA (tb[RTA_GATEWAY]); } if (gate) { if (index) nexthop_ipv4_ifindex_add (rib, gate, src, index); else nexthop_ipv4_add (rib, gate, src); } else nexthop_ifindex_add (rib, index); len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } if (rib->nexthop_num == 0) XFREE (MTYPE_RIB, rib); else rib_add_ipv4_multipath (&p, rib, SAFI_UNICAST); } } else rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) { struct prefix_ipv6 p; char buf[BUFSIZ]; p.family = AF_INET6; memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; if (IS_ZEBRA_DEBUG_KERNEL) { if (h->nlmsg_type == RTM_NEWROUTE) zlog_debug ("RTM_NEWROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); else zlog_debug ("RTM_DELROUTE %s/%d", inet_ntop (AF_INET6, &p.prefix, buf, BUFSIZ), p.prefixlen); } if (h->nlmsg_type == RTM_NEWROUTE) rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0, SAFI_UNICAST); else rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, SAFI_UNICAST); } #endif /* HAVE_IPV6 */ return 0; } static int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } #endif /* IFLA_WIRELESS */ if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); /* If new link is added. */ if_add_update (ifp); } else { /* Interface status change. */ set_ifindex(ifp, ifi->ifi_index); ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 0; netlink_interface_update_hw_addr (tb, ifp); if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!if_is_operative (ifp)) if_down (ifp); else /* Must notify client daemons of new interface status. */ zebra_interface_up_update (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_operative (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", name); return 0; } if_delete_update (ifp); } return 0; } static int netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h) { /* JF: Ignore messages that aren't from the kernel */ if ( snl->nl_pid != 0 ) { zlog ( NULL, LOG_ERR, "Ignoring message from pid %u", snl->nl_pid ); return 0; } switch (h->nlmsg_type) { case RTM_NEWROUTE: return netlink_route_change (snl, h); break; case RTM_DELROUTE: return netlink_route_change (snl, h); break; case RTM_NEWLINK: return netlink_link_change (snl, h); break; case RTM_DELLINK: return netlink_link_change (snl, h); break; case RTM_NEWADDR: return netlink_interface_addr (snl, h); break; case RTM_DELADDR: return netlink_interface_addr (snl, h); break; default: zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type); break; } return 0; } /* Interface lookup by netlink socket. */ int interface_lookup_netlink (void) { int ret; /* Get interface information. */ ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface, &netlink_cmd); if (ret < 0) return ret; /* Get IPv4 address of the interfaces. */ ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 address of the interfaces. */ ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ return 0; } /* Routing table read function using netlink interface. Only called bootstrap time. */ int netlink_route_read (void) { int ret; /* Get IPv4 routing table. */ ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret; #ifdef HAVE_IPV6 /* Get IPv6 routing table. */ ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd); if (ret < 0) return ret; ret = netlink_parse_info (netlink_routing_table, &netlink_cmd); if (ret < 0) return ret; #endif /* HAVE_IPV6 */ return 0; } /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int addattr_l (struct nlmsghdr *n, size_t maxlen, int type, void *data, int alen) { size_t len; struct rtattr *rta; len = RTA_LENGTH (alen); if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA (rta), data, alen); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0; } int rta_addattr_l (struct rtattr *rta, int maxlen, int type, void *data, int alen) { int len; struct rtattr *subrta; len = RTA_LENGTH (alen); if (RTA_ALIGN (rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr *) (((char *) rta) + RTA_ALIGN (rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy (RTA_DATA (subrta), data, alen); rta->rta_len = NLMSG_ALIGN (rta->rta_len) + len; return 0; } /* Utility function comes from iproute2. Authors: Alexey Kuznetsov, */ int addattr32 (struct nlmsghdr *n, size_t maxlen, int type, int data) { size_t len; struct rtattr *rta; len = RTA_LENGTH (4); if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr *) (((char *) n) + NLMSG_ALIGN (n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA (rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0; } static int netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h) { zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type); return 0; } /* sendmsg() to netlink socket then recvmsg(). */ static int netlink_talk (struct nlmsghdr *n, struct nlsock *nl) { int status; struct sockaddr_nl snl; struct iovec iov = { .iov_base = (void *) n, .iov_len = n->nlmsg_len }; struct msghdr msg = { .msg_name = (void *) &snl, .msg_namelen = sizeof snl, .msg_iov = &iov, .msg_iovlen = 1, }; int save_errno; memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++nl->seq; /* Request an acknowledgement by setting NLM_F_ACK */ n->nlmsg_flags |= NLM_F_ACK; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_talk: %s type %s(%u), seq=%u", nl->name, lookup (nlmsg_str, n->nlmsg_type), n->nlmsg_type, n->nlmsg_seq); /* Send message to netlink interface. */ if (zserv_privs.change (ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); status = sendmsg (nl->sock, &msg, 0); save_errno = errno; if (zserv_privs.change (ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (status < 0) { zlog (NULL, LOG_ERR, "netlink_talk sendmsg() error: %s", safe_strerror (save_errno)); return -1; } /* * Get reply from netlink socket. * The reply should either be an acknowlegement or an error. */ return netlink_parse_info (netlink_talk_filter, nl); } /* Routing table change via netlink interface. */ static int netlink_route (int cmd, int family, void *dest, int length, void *gate, int index, int zebra_flags, int table) { int ret; int bytelen; struct sockaddr_nl snl; int discard; struct { struct nlmsghdr n; struct rtmsg r; char buf[NL_PKT_BUF_SIZE]; } req; memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = table; req.r.rtm_dst_len = length; req.r.rtm_protocol = RTPROT_ZEBRA; req.r.rtm_scope = RT_SCOPE_UNIVERSE; if ((zebra_flags & ZEBRA_FLAG_BLACKHOLE) || (zebra_flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (zebra_flags & ZEBRA_FLAG_BLACKHOLE) req.r.rtm_type = RTN_BLACKHOLE; else if (zebra_flags & ZEBRA_FLAG_REJECT) req.r.rtm_type = RTN_UNREACHABLE; else assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ } else req.r.rtm_type = RTN_UNICAST; } if (dest) addattr_l (&req.n, sizeof req, RTA_DST, dest, bytelen); if (!discard) { if (gate) addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, bytelen); if (index > 0) addattr32 (&req.n, sizeof req, RTA_OIF, index); } /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ ret = netlink_talk (&req.n, &netlink_cmd); if (ret < 0) return -1; return 0; } /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. * * @param routedesc: Human readable description of route type * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information * @param nlmsg: nlmsghdr structure to fill in. * @param req_size: The size allocated for the message. */ static void _netlink_route_build_singlepath( const char *routedesc, int bytelen, struct nexthop *nexthop, struct nlmsghdr *nlmsg, struct rtmsg *rtmsg, size_t req_size) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); if (nexthop->src.ipv4.s_addr) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); } #ifdef HAVE_IPV6 if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); } #endif /* HAVE_IPV6 */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); if (nexthop->src.ipv4.s_addr) addattr_l (nlmsg, req_size, RTA_PREFSRC, &nexthop->src.ipv4, bytelen); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME) { addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } } /* This function takes a nexthop as argument and * appends to the given rtattr/rtnexthop pair the * representation of the nexthop. If the nexthop * defines a preferred source, the src parameter * will be modified to point to that src, otherwise * it will be kept unmodified. * * @param routedesc: Human readable description of route type * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information * @param rta: rtnetlink attribute structure * @param rtnh: pointer to an rtnetlink nexthop structure * @param src: pointer pointing to a location where * the prefsrc should be stored. */ static void _netlink_route_build_multipath( const char *routedesc, int bytelen, struct nexthop *nexthop, struct rtattr *rta, struct rtnexthop *rtnh, union g_addr **src ) { rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rta->rta_len += rtnh->rtnh_len; if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtnh->rtnh_flags |= RTNH_F_ONLINK; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); } #ifdef HAVE_IPV6 if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via %s if %u", routedesc, inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); } #endif /* HAVE_IPV6 */ /* ifindex */ if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { rtnh->rtnh_ifindex = nexthop->ifindex; if (nexthop->src.ipv4.s_addr) *src = &nexthop->src; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { rtnh->rtnh_ifindex = nexthop->ifindex; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("netlink_route_multipath() (%s): " "nexthop via if %u", routedesc, nexthop->ifindex); } else { rtnh->rtnh_ifindex = 0; } } /* Log debug information for netlink_route_multipath * if debug logging is enabled. * * @param cmd: Netlink command which is to be processed * @param p: Prefix for which the change is due * @param nexthop: Nexthop which is currently processed * @param routedesc: Semantic annotation for nexthop * (recursive, multipath, etc.) * @param family: Address family which the change concerns */ static void _netlink_route_debug( int cmd, struct prefix *p, struct nexthop *nexthop, const char *routedesc, int family) { if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug ("netlink_route_multipath() (%s): %s %s/%d type %s", routedesc, lookup (nlmsg_str, cmd), #ifdef HAVE_IPV6 (family == AF_INET) ? inet_ntoa (p->u.prefix4) : inet6_ntoa (p->u.prefix6), #else inet_ntoa (p->u.prefix4), #endif /* HAVE_IPV6 */ p->prefixlen, nexthop_type_to_str (nexthop->type)); } } /* Routing table change via netlink interface. */ static int netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int family) { int bytelen; struct sockaddr_nl snl; struct nexthop *nexthop = NULL, *tnexthop; int recursing; int nexthop_num; int discard; const char *routedesc; struct { struct nlmsghdr n; struct rtmsg r; char buf[NL_PKT_BUF_SIZE]; } req; memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.r.rtm_family = family; req.r.rtm_table = rib->table; req.r.rtm_dst_len = p->prefixlen; req.r.rtm_protocol = RTPROT_ZEBRA; req.r.rtm_scope = RT_SCOPE_UNIVERSE; if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (rib->flags & ZEBRA_FLAG_BLACKHOLE) req.r.rtm_type = RTN_BLACKHOLE; else if (rib->flags & ZEBRA_FLAG_REJECT) req.r.rtm_type = RTN_UNREACHABLE; else assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ } else req.r.rtm_type = RTN_UNICAST; } addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); /* Metric. */ addattr32 (&req.n, sizeof req, RTA_PRIORITY, rib->metric); if (discard) { if (cmd == RTM_NEWROUTE) for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { /* We shouldn't encounter recursive nexthops on discard routes, * but it is probably better to handle that case correctly anyway. */ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } goto skip; } /* Count overall nexthops so we can decide whether to use singlepath * or multipath case. */ nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) continue; nexthop_num++; } /* Singlepath case. */ if (nexthop_num == 1 || MULTIPATH_NUM == 1) { nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { routedesc = recursing ? "recursive, 1 hop" : "single hop"; _netlink_route_debug(cmd, p, nexthop, routedesc, family); _netlink_route_build_singlepath(routedesc, bytelen, nexthop, &req.n, &req.r, sizeof req); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); nexthop_num++; break; } } } else { char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; union g_addr *src = NULL; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH (0); rtnh = RTA_DATA (rta); nexthop_num = 0; for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (MULTIPATH_NUM != 0 && nexthop_num >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { routedesc = recursing ? "recursive, multihop" : "multihop"; nexthop_num++; _netlink_route_debug(cmd, p, nexthop, routedesc, family); _netlink_route_build_multipath(routedesc, bytelen, nexthop, rta, rtnh, &src); rtnh = RTNH_NEXT (rtnh); if (cmd == RTM_NEWROUTE) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); } } if (src) addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src->ipv4, bytelen); if (rta->rta_len > RTA_LENGTH (0)) addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), RTA_PAYLOAD (rta)); } /* If there is no useful nexthop then return. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug ("netlink_route_multipath(): No useful nexthop."); return 0; } skip: /* Destination netlink address. */ memset (&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; /* Talk to netlink socket. */ return netlink_talk (&req.n, &netlink_cmd); } int kernel_add_ipv4 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET); } int kernel_delete_ipv4 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET); } #ifdef HAVE_IPV6 int kernel_add_ipv6 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_NEWROUTE, p, rib, AF_INET6); } int kernel_delete_ipv6 (struct prefix *p, struct rib *rib) { return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); } #endif /* HAVE_IPV6 */ /* Interface address modification. */ static int netlink_address (int cmd, int family, struct interface *ifp, struct connected *ifc) { int bytelen; struct prefix *p; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[NL_PKT_BUF_SIZE]; } req; p = ifc->address; memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); bytelen = (family == AF_INET ? 4 : 16); req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = family; req.ifa.ifa_index = ifp->ifindex; req.ifa.ifa_prefixlen = p->prefixlen; addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); if (family == AF_INET && cmd == RTM_NEWADDR) { if (!CONNECTED_PEER(ifc) && ifc->destination) { p = ifc->destination; addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, bytelen); } } if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY); if (ifc->label) addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label, strlen (ifc->label) + 1); return netlink_talk (&req.n, &netlink_cmd); } int kernel_address_add_ipv4 (struct interface *ifp, struct connected *ifc) { return netlink_address (RTM_NEWADDR, AF_INET, ifp, ifc); } int kernel_address_delete_ipv4 (struct interface *ifp, struct connected *ifc) { return netlink_address (RTM_DELADDR, AF_INET, ifp, ifc); } extern struct thread_master *master; /* Kernel route reflection. */ static int kernel_read (struct thread *thread) { netlink_parse_info (netlink_information_fetch, &netlink); thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); return 0; } /* Filter out messages from self that occur on listener socket, caused by our actions on the command socket */ static void netlink_install_filter (int sock, __u32 pid) { struct sock_filter filter[] = { /* 0: ldh [4] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_H, offsetof(struct nlmsghdr, nlmsg_type)), /* 1: jeq 0x18 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_NEWROUTE), 1, 0), /* 2: jeq 0x19 jt 3 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htons(RTM_DELROUTE), 0, 3), /* 3: ldw [12] */ BPF_STMT(BPF_LD|BPF_ABS|BPF_W, offsetof(struct nlmsghdr, nlmsg_pid)), /* 4: jeq XX jt 5 jf 6 */ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, htonl(pid), 0, 1), /* 5: ret 0 (skip) */ BPF_STMT(BPF_RET|BPF_K, 0), /* 6: ret 0xffff (keep) */ BPF_STMT(BPF_RET|BPF_K, 0xffff), }; struct sock_fprog prog = { .len = array_size(filter), .filter = filter, }; if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) zlog_warn ("Can't install socket filter: %s\n", safe_strerror(errno)); } /* Exported interface function. This function simply calls netlink_socket (). */ void kernel_init (void) { unsigned long groups; groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR; #ifdef HAVE_IPV6 groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR; #endif /* HAVE_IPV6 */ netlink_socket (&netlink, groups); netlink_socket (&netlink_cmd, 0); /* Register kernel socket. */ if (netlink.sock > 0) { /* Only want non-blocking on the netlink event socket */ if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0) zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name, safe_strerror (errno)); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) netlink_recvbuf (&netlink, nl_rcvbufsize); netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid); thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock); } } /* * nl_msg_type_to_str */ const char * nl_msg_type_to_str (uint16_t msg_type) { return lookup (nlmsg_str, msg_type); } /* * nl_rtproto_to_str */ const char * nl_rtproto_to_str (u_char rtproto) { return lookup (rtproto_str, rtproto); } quagga-0.99.24.1/zebra/ipforward_sysctl.c0000644000175000017500000001046012476520570015102 00000000000000/* IP forward control by sysctl function. * Copyright (C) 1997, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "privs.h" #include "zebra/ipforward.h" #include "log.h" #define MIB_SIZ 4 extern struct zebra_privs_t zserv_privs; /* IPv4 forwarding control MIB. */ int mib[MIB_SIZ] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_FORWARDING }; int ipforward (void) { size_t len; int ipforwarding = 0; len = sizeof ipforwarding; if (sysctl (mib, MIB_SIZ, &ipforwarding, &len, 0, 0) < 0) { zlog_warn ("Can't get ipforwarding value"); return -1; } return ipforwarding; } int ipforward_on (void) { size_t len; int ipforwarding = 1; len = sizeof ipforwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } int ipforward_off (void) { size_t len; int ipforwarding = 0; len = sizeof ipforwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("Can't set ipforwarding on"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ipforwarding; } #ifdef HAVE_IPV6 /* IPv6 forwarding control MIB. */ int mib_ipv6[MIB_SIZ] = { CTL_NET, PF_INET6, #if defined(KAME) IPPROTO_IPV6, IPV6CTL_FORWARDING #else /* NOT KAME */ IPPROTO_IP, IP6CTL_FORWARDING #endif /* KAME */ }; int ipforward_ipv6 (void) { size_t len; int ip6forwarding = 0; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } int ipforward_ipv6_on (void) { size_t len; int ip6forwarding = 1; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } int ipforward_ipv6_off (void) { size_t len; int ip6forwarding = 0; len = sizeof ip6forwarding; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); if (sysctl (mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) { if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); zlog_warn ("can't get ip6forwarding value"); return -1; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return ip6forwarding; } #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/ipforward_solaris.c0000644000175000017500000001042712476520570015240 00000000000000/* * ipforward value get function for solaris. * Copyright (C) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "log.h" #include "prefix.h" #include "privs.h" #include "zebra/ipforward.h" /* ** Solaris should define IP_DEV_NAME in , but we'll save ** configure.in changes for another day. We can use the same device ** for both IPv4 and IPv6. */ /* #include */ #ifndef IP_DEV_NAME #define IP_DEV_NAME "/dev/ip" #endif extern struct zebra_privs_t zserv_privs; /* This is a limited ndd style function that operates one integer ** value only. Errors return -1. ND_SET commands return 0 on ** success. ND_GET commands return the value on success (which could ** be -1 and be confused for an error). The parameter is the string ** name of the parameter being referenced. */ static int solaris_nd(const int cmd, const char* parameter, const int value) { #define ND_BUFFER_SIZE 1024 int fd; char nd_buf[ND_BUFFER_SIZE]; struct strioctl strioctl; const char* device = IP_DEV_NAME; int retval; memset(nd_buf, '\0', ND_BUFFER_SIZE); /* ** ND_SET takes a NULL delimited list of strings further terminated ** buy a NULL. ND_GET returns a list in a similar layout, although ** here we only use the first result. */ if (cmd == ND_SET) snprintf(nd_buf, ND_BUFFER_SIZE, "%s%c%d%c", parameter, '\0', value,'\0'); else if (cmd == ND_GET) snprintf(nd_buf, ND_BUFFER_SIZE, "%s", parameter); else { zlog_err("internal error - inappropriate command given to " "solaris_nd()%s:%d", __FILE__, __LINE__); return -1; } strioctl.ic_cmd = cmd; strioctl.ic_timout = 0; strioctl.ic_len = ND_BUFFER_SIZE; strioctl.ic_dp = nd_buf; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("solaris_nd: Can't raise privileges"); if ((fd = open (device, O_RDWR)) < 0) { zlog_warn("failed to open device %s - %s", device, safe_strerror(errno)); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); return -1; } if (ioctl (fd, I_STR, &strioctl) < 0) { int save_errno = errno; if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); close (fd); zlog_warn("ioctl I_STR failed on device %s - %s", device, safe_strerror(save_errno)); return -1; } close(fd); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("solaris_nd: Can't lower privileges"); if (cmd == ND_GET) { errno = 0; retval = atoi(nd_buf); if (errno) { zlog_warn("failed to convert returned value to integer - %s", safe_strerror(errno)); retval = -1; } } else { retval = 0; } return retval; } static int solaris_nd_set(const char* parameter, const int value) { return solaris_nd(ND_SET, parameter, value); } static int solaris_nd_get(const char* parameter) { return solaris_nd(ND_GET, parameter, 0); } int ipforward(void) { return solaris_nd_get("ip_forwarding"); } int ipforward_on (void) { (void) solaris_nd_set("ip_forwarding", 1); return ipforward(); } int ipforward_off (void) { (void) solaris_nd_set("ip_forwarding", 0); return ipforward(); } #ifdef HAVE_IPV6 int ipforward_ipv6(void) { return solaris_nd_get("ip6_forwarding"); } int ipforward_ipv6_on (void) { (void) solaris_nd_set("ip6_forwarding", 1); return ipforward_ipv6(); } int ipforward_ipv6_off (void) { (void) solaris_nd_set("ip6_forwarding", 0); return ipforward_ipv6(); } #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/ipforward_proc.c0000644000175000017500000001016212476520570014523 00000000000000/* * Fetch ipforward value by reading /proc filesystem. * Copyright (C) 1997 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "log.h" #include "privs.h" #include "zebra/ipforward.h" extern struct zebra_privs_t zserv_privs; char proc_net_snmp[] = "/proc/net/snmp"; static void dropline (FILE *fp) { int c; while ((c = getc (fp)) != '\n') ; } int ipforward (void) { FILE *fp; int ipforwarding = 0; char buf[10]; fp = fopen (proc_net_snmp, "r"); if (fp == NULL) return -1; /* We don't care about the first line. */ dropline (fp); /* Get ip_statistics.IpForwarding : 1 => ip forwarding enabled 2 => ip forwarding off. */ if (fgets (buf, 6, fp)) sscanf (buf, "Ip: %d", &ipforwarding); fclose(fp); if (ipforwarding == 1) return 1; return 0; } /* char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/conf/all/forwarding"; */ char proc_ipv4_forwarding[] = "/proc/sys/net/ipv4/ip_forward"; int ipforward_on (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno) ); fp = fopen (proc_ipv4_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "1\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward (); } int ipforward_off (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv4_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "0\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward (); } #ifdef HAVE_IPV6 char proc_ipv6_forwarding[] = "/proc/sys/net/ipv6/conf/all/forwarding"; int ipforward_ipv6 (void) { FILE *fp; char buf[5]; int ipforwarding = 0; fp = fopen (proc_ipv6_forwarding, "r"); if (fp == NULL) return -1; if (fgets (buf, 2, fp)) sscanf (buf, "%d", &ipforwarding); fclose (fp); return ipforwarding; } int ipforward_ipv6_on (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv6_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "1\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward_ipv6 (); } int ipforward_ipv6_off (void) { FILE *fp; if ( zserv_privs.change(ZPRIVS_RAISE) ) zlog_err ("Can't raise privileges, %s", safe_strerror (errno)); fp = fopen (proc_ipv6_forwarding, "w"); if (fp == NULL) { if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return -1; } fprintf (fp, "0\n"); fclose (fp); if ( zserv_privs.change(ZPRIVS_LOWER) ) zlog_err ("Can't lower privileges, %s", safe_strerror (errno)); return ipforward_ipv6 (); } #endif /* HAVE_IPV6 */ quagga-0.99.24.1/zebra/if_sysctl.c0000644000175000017500000000666712476520570013521 00000000000000/* * Get interface's address and mask information by sysctl() function. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "sockunion.h" #include "prefix.h" #include "connected.h" #include "memory.h" #include "ioctl.h" #include "log.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" void ifstat_update_sysctl (void) { caddr_t ref, buf, end; size_t bufsiz; struct if_msghdr *ifm; struct interface *ifp; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, /* AF_INET & AF_INET6 */ NET_RT_IFLIST, 0 }; /* Query buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog_warn ("sysctl() error by %s", safe_strerror (errno)); return; } /* We free this memory at the end of this function. */ ref = buf = XMALLOC (MTYPE_TMP, bufsiz); /* Fetch interface informations into allocated buffer. */ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) { zlog (NULL, LOG_WARNING, "sysctl error by %s", safe_strerror (errno)); return; } /* Parse both interfaces and addresses. */ for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { ifm = (struct if_msghdr *) buf; if (ifm->ifm_type == RTM_IFINFO) { ifp = if_lookup_by_index (ifm->ifm_index); if (ifp) ifp->stats = ifm->ifm_data; } } /* Free sysctl buffer. */ XFREE (MTYPE_TMP, ref); return; } /* Interface listing up function using sysctl(). */ void interface_list () { caddr_t ref, buf, end; size_t bufsiz; struct if_msghdr *ifm; #define MIBSIZ 6 int mib[MIBSIZ] = { CTL_NET, PF_ROUTE, 0, 0, /* AF_INET & AF_INET6 */ NET_RT_IFLIST, 0 }; /* Query buffer size. */ if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0) { zlog (NULL, LOG_WARNING, "sysctl() error by %s", safe_strerror (errno)); return; } /* We free this memory at the end of this function. */ ref = buf = XMALLOC (MTYPE_TMP, bufsiz); /* Fetch interface informations into allocated buffer. */ if (sysctl (mib, MIBSIZ, buf, &bufsiz, NULL, 0) < 0) { zlog (NULL, LOG_WARNING, "sysctl error by %s", safe_strerror (errno)); return; } /* Parse both interfaces and addresses. */ for (end = buf + bufsiz; buf < end; buf += ifm->ifm_msglen) { ifm = (struct if_msghdr *) buf; switch (ifm->ifm_type) { case RTM_IFINFO: ifm_read (ifm); break; case RTM_NEWADDR: ifam_read ((struct ifa_msghdr *) ifm); break; default: zlog_info ("interfaces_list(): unexpected message type"); XFREE (MTYPE_TMP, ref); return; break; } } /* Free sysctl buffer. */ XFREE (MTYPE_TMP, ref); } quagga-0.99.24.1/zebra/if_netlink.c0000644000175000017500000000202312476520570013622 00000000000000/* * Interface looking up by netlink. * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "zebra/zserv.h" extern int interface_lookup_netlink (void); /* Interface information read by netlink. */ void interface_list (void) { interface_lookup_netlink (); } quagga-0.99.24.1/zebra/if_ioctl_solaris.c0000644000175000017500000002416612476520570015040 00000000000000/* * Interface looking up by ioctl () on Solaris. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "sockunion.h" #include "prefix.h" #include "ioctl.h" #include "connected.h" #include "memory.h" #include "log.h" #include "privs.h" #include "zebra/interface.h" void lifreq_set_name (struct lifreq *, const char *); int if_get_flags_direct (const char *, uint64_t *, unsigned int af); static int if_get_addr (struct interface *, struct sockaddr *, const char *); static void interface_info_ioctl (struct interface *); extern struct zebra_privs_t zserv_privs; int interface_list_ioctl (int af) { int ret; int sock; #define IFNUM_BASE 32 struct lifnum lifn; int ifnum; struct lifreq *lifreq; struct lifconf lifconf; struct interface *ifp; int n; int save_errno; size_t needed, lastneeded = 0; char *buf = NULL; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); sock = socket (af, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("Can't make %s socket stream: %s", (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno)); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); return -1; } calculate_lifc_len: /* must hold privileges to enter here */ lifn.lifn_family = af; lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */ ret = ioctl (sock, SIOCGLIFNUM, &lifn); save_errno = errno; if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); if (ret < 0) { zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s", safe_strerror (save_errno)); close (sock); return -1; } ifnum = lifn.lifn_count; /* * When calculating the buffer size needed, add a small number * of interfaces to those we counted. We do this to capture * the interface status of potential interfaces which may have * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. */ needed = (ifnum + 4) * sizeof (struct lifreq); if (needed > lastneeded || needed < lastneeded / 2) { if (buf != NULL) XFREE (MTYPE_TMP, buf); if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL) { zlog_warn ("interface_list_ioctl: malloc failed"); close (sock); return -1; } } lastneeded = needed; lifconf.lifc_family = af; lifconf.lifc_flags = LIFC_NOXMIT; lifconf.lifc_len = needed; lifconf.lifc_buf = buf; if (zserv_privs.change(ZPRIVS_RAISE)) zlog (NULL, LOG_ERR, "Can't raise privileges"); ret = ioctl (sock, SIOCGLIFCONF, &lifconf); if (ret < 0) { if (errno == EINVAL) goto calculate_lifc_len; /* deliberately hold privileges */ zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno)); if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); goto end; } if (zserv_privs.change(ZPRIVS_LOWER)) zlog (NULL, LOG_ERR, "Can't lower privileges"); /* Allocate interface. */ lifreq = lifconf.lifc_req; for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq)) { /* we treat Solaris logical interfaces as addresses, because that is * how PF_ROUTE on Solaris treats them. Hence we can not directly use * the lifreq_name to get the ifp. We need to normalise the name * before attempting get. * * Solaris logical interface names are in the form of: * : */ unsigned int normallen = 0; uint64_t lifflags; /* We should exclude ~IFF_UP interfaces, as we'll find out about them * coming up later through RTM_NEWADDR message on the route socket. */ if (if_get_flags_direct (lifreq->lifr_name, &lifflags, lifreq->lifr_addr.ss_family) || !CHECK_FLAG (lifflags, IFF_UP)) { lifreq++; continue; } /* Find the normalised name */ while ( (normallen < sizeof(lifreq->lifr_name)) && ( *(lifreq->lifr_name + normallen) != '\0') && ( *(lifreq->lifr_name + normallen) != ':') ) normallen++; ifp = if_get_by_name_len(lifreq->lifr_name, normallen); if (lifreq->lifr_addr.ss_family == AF_INET) ifp->flags |= IFF_IPV4; if (lifreq->lifr_addr.ss_family == AF_INET6) { #ifdef HAVE_IPV6 ifp->flags |= IFF_IPV6; #else lifreq++; continue; #endif /* HAVE_IPV6 */ } if_add_update (ifp); interface_info_ioctl (ifp); /* If a logical interface pass the full name so it can be * as a label on the address */ if ( *(lifreq->lifr_name + normallen) != '\0') if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, lifreq->lifr_name); else if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL); /* Poke the interface flags. Lets IFF_UP mangling kick in */ if_flags_update (ifp, ifp->flags); lifreq++; } end: close (sock); XFREE (MTYPE_TMP, lifconf.lifc_buf); return ret; } /* Get interface's index by ioctl. */ int if_get_index (struct interface *ifp) { int ret; struct lifreq lifreq; lifreq_set_name (&lifreq, ifp->name); if (ifp->flags & IFF_IPV4) ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq); else if (ifp->flags & IFF_IPV6) ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq); else ret = -1; if (ret < 0) { zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name); return ret; } /* OK we got interface index. */ #ifdef ifr_ifindex ifp->ifindex = lifreq.lifr_ifindex; #else ifp->ifindex = lifreq.lifr_index; #endif return ifp->ifindex; } /* Interface address lookup by ioctl. This function only looks up IPv4 address. */ #define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \ sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6))) #define SIN(s) ((struct sockaddr_in *)(s)) #define SIN6(s) ((struct sockaddr_in6 *)(s)) /* Retrieve address information for the given ifp */ static int if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) { int ret; struct lifreq lifreq; struct sockaddr_storage mask, dest; char *dest_pnt = NULL; u_char prefixlen = 0; afi_t af; int flags = 0; /* Interface's name and address family. * We need to use the logical interface name / label, if we've been * given one, in order to get the right address */ strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ); /* Interface's address. */ memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr)); af = addr->sa_family; /* Point to point or broad cast address pointer init. */ dest_pnt = NULL; if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0) { memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr)); if (af == AF_INET) dest_pnt = (char *) &(SIN (&dest)->sin_addr); else dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr); flags = ZEBRA_IFA_PEER; } if (af == AF_INET) { ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name, safe_strerror (errno)); return ret; } return 0; } memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr)); prefixlen = ip_masklen (SIN (&mask)->sin_addr); if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0)) { memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = (char *) &SIN (&dest)->sin_addr; } } #ifdef HAVE_IPV6 else if (af == AF_INET6) { if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0) { if (ifp->flags & IFF_POINTOPOINT) prefixlen = IPV6_MAX_BITLEN; else zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s", ifp->name, safe_strerror (errno)); } else { prefixlen = lifreq.lifr_addrlen; } } #endif /* HAVE_IPV6 */ /* Set address to the interface. */ if (af == AF_INET) connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen, (struct in_addr *) dest_pnt, label); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, (struct in6_addr *) dest_pnt, label); #endif /* HAVE_IPV6 */ return 0; } /* Fetch interface information via ioctl(). */ static void interface_info_ioctl (struct interface *ifp) { if_get_index (ifp); if_get_flags (ifp); if_get_mtu (ifp); if_get_metric (ifp); } /* Lookup all interface information. */ void interface_list () { interface_list_ioctl (AF_INET); interface_list_ioctl (AF_INET6); interface_list_ioctl (AF_UNSPEC); } struct connected * if_lookup_linklocal (struct interface *ifp) { #ifdef HAVE_IPV6 struct listnode *node; struct connected *ifc; if (ifp == NULL) return NULL; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { if ((ifc->address->family == AF_INET6) && (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6))) return ifc; } #endif /* HAVE_IPV6 */ return NULL; } quagga-0.99.24.1/zebra/if_ioctl.c0000644000175000017500000002656412476520570013310 00000000000000/* * Interface looking up by ioctl (). * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "sockunion.h" #include "prefix.h" #include "ioctl.h" #include "connected.h" #include "memory.h" #include "log.h" #include "zebra/interface.h" /* Interface looking up using infamous SIOCGIFCONF. */ static int interface_list_ioctl (void) { int ret; int sock; #define IFNUM_BASE 32 int ifnum; struct ifreq *ifreq; struct ifconf ifconf; struct interface *ifp; int n; int lastlen; /* Normally SIOCGIFCONF works with AF_INET socket. */ sock = socket (AF_INET, SOCK_DGRAM, 0); if (sock < 0) { zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno)); return -1; } /* Set initial ifreq count. This will be double when SIOCGIFCONF fail. Solaris has SIOCGIFNUM. */ #ifdef SIOCGIFNUM ret = ioctl (sock, SIOCGIFNUM, &ifnum); if (ret < 0) ifnum = IFNUM_BASE; else ifnum++; #else ifnum = IFNUM_BASE; #endif /* SIOCGIFNUM */ ifconf.ifc_buf = NULL; lastlen = 0; /* Loop until SIOCGIFCONF success. */ for (;;) { ifconf.ifc_len = sizeof (struct ifreq) * ifnum; ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len); ret = ioctl(sock, SIOCGIFCONF, &ifconf); if (ret < 0) { zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno)); goto end; } /* Repeatedly get info til buffer fails to grow. */ if (ifconf.ifc_len > lastlen) { lastlen = ifconf.ifc_len; ifnum += 10; continue; } /* Success. */ break; } /* Allocate interface. */ ifreq = ifconf.ifc_req; #ifdef OPEN_BSD for (n = 0; n < ifconf.ifc_len; ) { int size; ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n); ifp = if_get_by_name_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name))); if_add_update (ifp); size = ifreq->ifr_addr.sa_len; if (size < sizeof (ifreq->ifr_addr)) size = sizeof (ifreq->ifr_addr); size += sizeof (ifreq->ifr_name); n += size; } #else for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) { ifp = if_get_by_name_len(ifreq->ifr_name, strnlen(ifreq->ifr_name, sizeof(ifreq->ifr_name))); if_add_update (ifp); ifreq++; } #endif /* OPEN_BSD */ end: close (sock); XFREE (MTYPE_TMP, ifconf.ifc_buf); return ret; } /* Get interface's index by ioctl. */ static int if_get_index (struct interface *ifp) { #if defined(HAVE_IF_NAMETOINDEX) /* Modern systems should have if_nametoindex(3). */ ifp->ifindex = if_nametoindex(ifp->name); #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES) /* Fall-back for older linuxes. */ int ret; struct ifreq ifreq; static int if_fake_index; ifreq_set_name (&ifreq, ifp); ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq); if (ret < 0) { /* Linux 2.0.X does not have interface index. */ ifp->ifindex = if_fake_index++; return ifp->ifindex; } /* OK we got interface index. */ #ifdef ifr_ifindex ifp->ifindex = ifreq.ifr_ifindex; #else ifp->ifindex = ifreq.ifr_index; #endif #else /* Linux 2.2.X does not provide individual interface index for aliases and we know it. For others issue a warning. */ #if !defined(HAVE_BROKEN_ALIASES) #warning "Using if_fake_index. You may want to add appropriate" #warning "mapping from ifname to ifindex for your system..." #endif /* This branch probably won't provide usable results, but anyway... */ static int if_fake_index = 1; ifp->ifindex = if_fake_index++; #endif return ifp->ifindex; } #ifdef SIOCGIFHWADDR static int if_get_hwaddr (struct interface *ifp) { int ret; struct ifreq ifreq; int i; strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq); if (ret < 0) ifp->hw_addr_len = 0; else { memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6); for (i = 0; i < 6; i++) if (ifp->hw_addr[i] != 0) break; if (i == 6) ifp->hw_addr_len = 0; else ifp->hw_addr_len = 6; } return 0; } #endif /* SIOCGIFHWADDR */ #ifdef HAVE_GETIFADDRS #include static int if_getaddrs (void) { int ret; struct ifaddrs *ifap; struct ifaddrs *ifapfree; struct interface *ifp; int prefixlen; ret = getifaddrs (&ifap); if (ret != 0) { zlog_err ("getifaddrs(): %s", safe_strerror (errno)); return -1; } for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) { if (ifap->ifa_addr == NULL) { zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s", __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)")); continue; } ifp = if_lookup_by_name (ifap->ifa_name); if (ifp == NULL) { zlog_err ("if_getaddrs(): Can't lookup interface %s\n", ifap->ifa_name); continue; } if (ifap->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *addr; struct sockaddr_in *mask; struct sockaddr_in *dest; struct in_addr *dest_pnt; int flags = 0; addr = (struct sockaddr_in *) ifap->ifa_addr; mask = (struct sockaddr_in *) ifap->ifa_netmask; prefixlen = ip_masklen (mask->sin_addr); dest_pnt = NULL; if (ifap->ifa_dstaddr && !IPV4_ADDR_SAME(&addr->sin_addr, &((struct sockaddr_in *) ifap->ifa_dstaddr)->sin_addr)) { dest = (struct sockaddr_in *) ifap->ifa_dstaddr; dest_pnt = &dest->sin_addr; flags = ZEBRA_IFA_PEER; } else if (ifap->ifa_broadaddr && !IPV4_ADDR_SAME(&addr->sin_addr, &((struct sockaddr_in *) ifap->ifa_broadaddr)->sin_addr)) { dest = (struct sockaddr_in *) ifap->ifa_broadaddr; dest_pnt = &dest->sin_addr; } connected_add_ipv4 (ifp, flags, &addr->sin_addr, prefixlen, dest_pnt, NULL); } #ifdef HAVE_IPV6 if (ifap->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6 *addr; struct sockaddr_in6 *mask; struct sockaddr_in6 *dest; struct in6_addr *dest_pnt; int flags = 0; addr = (struct sockaddr_in6 *) ifap->ifa_addr; mask = (struct sockaddr_in6 *) ifap->ifa_netmask; prefixlen = ip6_masklen (mask->sin6_addr); dest_pnt = NULL; if (ifap->ifa_dstaddr && !IPV6_ADDR_SAME(&addr->sin6_addr, &((struct sockaddr_in6 *) ifap->ifa_dstaddr)->sin6_addr)) { dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr; dest_pnt = &dest->sin6_addr; flags = ZEBRA_IFA_PEER; } else if (ifap->ifa_broadaddr && !IPV6_ADDR_SAME(&addr->sin6_addr, &((struct sockaddr_in6 *) ifap->ifa_broadaddr)->sin6_addr)) { dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr; dest_pnt = &dest->sin6_addr; } #if defined(KAME) if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { addr->sin6_scope_id = ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]); addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0; } #endif connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, dest_pnt, NULL); } #endif /* HAVE_IPV6 */ } freeifaddrs (ifapfree); return 0; } #else /* HAVE_GETIFADDRS */ /* Interface address lookup by ioctl. This function only looks up IPv4 address. */ int if_get_addr (struct interface *ifp) { int ret; struct ifreq ifreq; struct sockaddr_in addr; struct sockaddr_in mask; struct sockaddr_in dest; struct in_addr *dest_pnt; u_char prefixlen; int flags = 0; /* Interface's name and address family. */ strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ); ifreq.ifr_addr.sa_family = AF_INET; /* Interface's address. */ ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno)); return ret; } return 0; } memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); /* Interface's network mask. */ ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) { zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno)); return ret; } return 0; } #ifdef ifr_netmask memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in)); #else memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in)); #endif /* ifr_netmask */ prefixlen = ip_masklen (mask.sin_addr); /* Point to point or borad cast address pointer init. */ dest_pnt = NULL; ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr)) { memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; flags = ZEBRA_IFA_PEER; } if (!dest_pnt) { ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq); if (ret < 0) { if (errno != EADDRNOTAVAIL) zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno)); } else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr)) { memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in)); dest_pnt = &dest.sin_addr; } } /* Set address to the interface. */ connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL); return 0; } #endif /* HAVE_GETIFADDRS */ /* Fetch interface information via ioctl(). */ static void interface_info_ioctl () { struct listnode *node, *nnode; struct interface *ifp; for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { if_get_index (ifp); #ifdef SIOCGIFHWADDR if_get_hwaddr (ifp); #endif /* SIOCGIFHWADDR */ if_get_flags (ifp); #ifndef HAVE_GETIFADDRS if_get_addr (ifp); #endif /* ! HAVE_GETIFADDRS */ if_get_mtu (ifp); if_get_metric (ifp); } } /* Lookup all interface information. */ void interface_list () { /* Linux can do both proc & ioctl, ioctl is the only way to get interface aliases in 2.2 series kernels. */ #ifdef HAVE_PROC_NET_DEV interface_list_proc (); #endif /* HAVE_PROC_NET_DEV */ interface_list_ioctl (); /* After listing is done, get index, address, flags and other interface's information. */ interface_info_ioctl (); #ifdef HAVE_GETIFADDRS if_getaddrs (); #endif /* HAVE_GETIFADDRS */ #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6) /* Linux provides interface's IPv6 address via /proc/net/if_inet6. */ ifaddr_proc_ipv6 (); #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */ } quagga-0.99.24.1/zebra/zebra_fpm_netlink.c0000644000175000017500000002475312476520570015207 00000000000000/* * Code for encoding/decoding FPM messages that are in netlink format. * * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "log.h" #include "rib.h" #include "rt_netlink.h" #include "zebra_fpm_private.h" /* * addr_to_a * * Returns string representation of an address of the given AF. */ static inline const char * addr_to_a (u_char af, void *addr) { if (!addr) return ""; switch (af) { case AF_INET: return inet_ntoa (*((struct in_addr *) addr)); #ifdef HAVE_IPV6 case AF_INET6: return inet6_ntoa (*((struct in6_addr *) addr)); #endif default: return ""; } } /* * prefix_addr_to_a * * Convience wrapper that returns a human-readable string for the * address in a prefix. */ static const char * prefix_addr_to_a (struct prefix *prefix) { if (!prefix) return ""; return addr_to_a (prefix->family, &prefix->u.prefix); } /* * af_addr_size * * The size of an address in a given address family. */ static size_t af_addr_size (u_char af) { switch (af) { case AF_INET: return 4; #ifdef HAVE_IPV6 case AF_INET6: return 16; #endif default: assert(0); return 16; } } /* * netlink_nh_info_t * * Holds information about a single nexthop for netlink. These info * structures are transient and may contain pointers into rib * data structures for convenience. */ typedef struct netlink_nh_info_t_ { uint32_t if_index; union g_addr *gateway; /* * Information from the struct nexthop from which this nh was * derived. For debug purposes only. */ int recursive; enum nexthop_types_t type; } netlink_nh_info_t; /* * netlink_route_info_t * * A structure for holding information for a netlink route message. */ typedef struct netlink_route_info_t_ { uint16_t nlmsg_type; u_char rtm_type; uint32_t rtm_table; u_char rtm_protocol; u_char af; struct prefix *prefix; uint32_t *metric; int num_nhs; /* * Nexthop structures. We keep things simple for now by enforcing a * maximum of 64 in case MULTIPATH_NUM is 0; */ netlink_nh_info_t nhs[MAX (MULTIPATH_NUM, 64)]; union g_addr *pref_src; } netlink_route_info_t; /* * netlink_route_info_add_nh * * Add information about the given nexthop to the given route info * structure. * * Returns TRUE if a nexthop was added, FALSE otherwise. */ static int netlink_route_info_add_nh (netlink_route_info_t *ri, struct nexthop *nexthop, int recursive) { netlink_nh_info_t nhi; union g_addr *src; memset (&nhi, 0, sizeof (nhi)); src = NULL; if (ri->num_nhs >= (int) ZEBRA_NUM_OF (ri->nhs)) return 0; nhi.recursive = recursive; nhi.type = nexthop->type; nhi.if_index = nexthop->ifindex; if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { nhi.gateway = &nexthop->gate; if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } #ifdef HAVE_IPV6 if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { nhi.gateway = &nexthop->gate; } #endif /* HAVE_IPV6 */ if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) { if (nexthop->src.ipv4.s_addr) src = &nexthop->src; } if (!nhi.gateway && nhi.if_index == 0) return 0; /* * We have a valid nhi. Copy the structure over to the route_info. */ ri->nhs[ri->num_nhs] = nhi; ri->num_nhs++; if (src && !ri->pref_src) ri->pref_src = src; return 1; } /* * netlink_proto_from_route_type */ static u_char netlink_proto_from_route_type (int type) { switch (type) { case ZEBRA_ROUTE_KERNEL: case ZEBRA_ROUTE_CONNECT: return RTPROT_KERNEL; default: return RTPROT_ZEBRA; } } /* * netlink_route_info_fill * * Fill out the route information object from the given route. * * Returns TRUE on success and FALSE on failure. */ static int netlink_route_info_fill (netlink_route_info_t *ri, int cmd, rib_dest_t *dest, struct rib *rib) { struct nexthop *nexthop, *tnexthop; int recursing; int discard; memset (ri, 0, sizeof (*ri)); ri->prefix = rib_dest_prefix (dest); ri->af = rib_dest_af (dest); ri->nlmsg_type = cmd; ri->rtm_table = rib_dest_vrf (dest)->id; ri->rtm_protocol = RTPROT_UNSPEC; /* * An RTM_DELROUTE need not be accompanied by any nexthops, * particularly in our communication with the FPM. */ if (cmd == RTM_DELROUTE && !rib) goto skip; if (rib) ri->rtm_protocol = netlink_proto_from_route_type (rib->type); if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) discard = 1; else discard = 0; if (cmd == RTM_NEWROUTE) { if (discard) { if (rib->flags & ZEBRA_FLAG_BLACKHOLE) ri->rtm_type = RTN_BLACKHOLE; else if (rib->flags & ZEBRA_FLAG_REJECT) ri->rtm_type = RTN_UNREACHABLE; else assert (0); } else ri->rtm_type = RTN_UNICAST; } ri->metric = &rib->metric; if (discard) { goto skip; } for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { if (MULTIPATH_NUM != 0 && ri->num_nhs >= MULTIPATH_NUM) break; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; if ((cmd == RTM_NEWROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) || (cmd == RTM_DELROUTE && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) { netlink_route_info_add_nh (ri, nexthop, recursing); } } /* If there is no useful nexthop then return. */ if (ri->num_nhs == 0) { zfpm_debug ("netlink_encode_route(): No useful nexthop."); return 0; } skip: return 1; } /* * netlink_route_info_encode * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ static int netlink_route_info_encode (netlink_route_info_t *ri, char *in_buf, size_t in_buf_len) { int bytelen; int nexthop_num = 0; size_t buf_offset; netlink_nh_info_t *nhi; struct { struct nlmsghdr n; struct rtmsg r; char buf[1]; } *req; req = (void *) in_buf; buf_offset = ((char *) req->buf) - ((char *) req); if (in_buf_len < buf_offset) { assert(0); return 0; } memset (req, 0, buf_offset); bytelen = af_addr_size (ri->af); req->n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; req->n.nlmsg_type = ri->nlmsg_type; req->r.rtm_family = ri->af; req->r.rtm_table = ri->rtm_table; req->r.rtm_dst_len = ri->prefix->prefixlen; req->r.rtm_protocol = ri->rtm_protocol; req->r.rtm_scope = RT_SCOPE_UNIVERSE; addattr_l (&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen); req->r.rtm_type = ri->rtm_type; /* Metric. */ if (ri->metric) addattr32 (&req->n, in_buf_len, RTA_PRIORITY, *ri->metric); if (ri->num_nhs == 0) goto done; if (ri->num_nhs == 1) { nhi = &ri->nhs[0]; if (nhi->gateway) { addattr_l (&req->n, in_buf_len, RTA_GATEWAY, nhi->gateway, bytelen); } if (nhi->if_index) { addattr32 (&req->n, in_buf_len, RTA_OIF, nhi->if_index); } goto done; } /* * Multipath case. */ char buf[NL_PKT_BUF_SIZE]; struct rtattr *rta = (void *) buf; struct rtnexthop *rtnh; rta->rta_type = RTA_MULTIPATH; rta->rta_len = RTA_LENGTH (0); rtnh = RTA_DATA (rta); for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++) { nhi = &ri->nhs[nexthop_num]; rtnh->rtnh_len = sizeof (*rtnh); rtnh->rtnh_flags = 0; rtnh->rtnh_hops = 0; rtnh->rtnh_ifindex = 0; rta->rta_len += rtnh->rtnh_len; if (nhi->gateway) { rta_addattr_l (rta, sizeof (buf), RTA_GATEWAY, nhi->gateway, bytelen); rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; } if (nhi->if_index) { rtnh->rtnh_ifindex = nhi->if_index; } rtnh = RTNH_NEXT (rtnh); } assert (rta->rta_len > RTA_LENGTH (0)); addattr_l (&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA (rta), RTA_PAYLOAD (rta)); done: if (ri->pref_src) { addattr_l (&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, bytelen); } assert (req->n.nlmsg_len < in_buf_len); return req->n.nlmsg_len; } /* * zfpm_log_route_info * * Helper function to log the information in a route_info structure. */ static void zfpm_log_route_info (netlink_route_info_t *ri, const char *label) { netlink_nh_info_t *nhi; int i; zfpm_debug ("%s : %s %s/%d, Proto: %s, Metric: %u", label, nl_msg_type_to_str (ri->nlmsg_type), prefix_addr_to_a (ri->prefix), ri->prefix->prefixlen, nl_rtproto_to_str (ri->rtm_protocol), ri->metric ? *ri->metric : 0); for (i = 0; i < ri->num_nhs; i++) { nhi = &ri->nhs[i]; zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s", nhi->if_index, addr_to_a (ri->af, nhi->gateway), nhi->recursive ? "yes" : "no", nexthop_type_to_str (nhi->type)); } } /* * zfpm_netlink_encode_route * * Create a netlink message corresponding to the given route in the * given buffer space. * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ int zfpm_netlink_encode_route (int cmd, rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len) { netlink_route_info_t ri_space, *ri; ri = &ri_space; if (!netlink_route_info_fill (ri, cmd, dest, rib)) return 0; zfpm_log_route_info (ri, __FUNCTION__); return netlink_route_info_encode (ri, in_buf, in_buf_len); } quagga-0.99.24.1/zebra/zebra_fpm.c0000644000175000017500000007717612476520570013472 00000000000000/* * Main implementation file for interface to Forwarding Plane Manager. * * Copyright (C) 2012 by Open Source Routing. * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC") * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "log.h" #include "stream.h" #include "thread.h" #include "network.h" #include "command.h" #include "zebra/rib.h" #include "fpm/fpm.h" #include "zebra_fpm.h" #include "zebra_fpm_private.h" /* * Interval at which we attempt to connect to the FPM. */ #define ZFPM_CONNECT_RETRY_IVL 5 /* * Sizes of outgoing and incoming stream buffers for writing/reading * FPM messages. */ #define ZFPM_OBUF_SIZE (2 * FPM_MAX_MSG_LEN) #define ZFPM_IBUF_SIZE (FPM_MAX_MSG_LEN) /* * The maximum number of times the FPM socket write callback can call * 'write' before it yields. */ #define ZFPM_MAX_WRITES_PER_RUN 10 /* * Interval over which we collect statistics. */ #define ZFPM_STATS_IVL_SECS 10 /* * Structure that holds state for iterating over all route_node * structures that are candidates for being communicated to the FPM. */ typedef struct zfpm_rnodes_iter_t_ { rib_tables_iter_t tables_iter; route_table_iter_t iter; } zfpm_rnodes_iter_t; /* * Statistics. */ typedef struct zfpm_stats_t_ { unsigned long connect_calls; unsigned long connect_no_sock; unsigned long read_cb_calls; unsigned long write_cb_calls; unsigned long write_calls; unsigned long partial_writes; unsigned long max_writes_hit; unsigned long t_write_yields; unsigned long nop_deletes_skipped; unsigned long route_adds; unsigned long route_dels; unsigned long updates_triggered; unsigned long redundant_triggers; unsigned long non_fpm_table_triggers; unsigned long dests_del_after_update; unsigned long t_conn_down_starts; unsigned long t_conn_down_dests_processed; unsigned long t_conn_down_yields; unsigned long t_conn_down_finishes; unsigned long t_conn_up_starts; unsigned long t_conn_up_dests_processed; unsigned long t_conn_up_yields; unsigned long t_conn_up_aborts; unsigned long t_conn_up_finishes; } zfpm_stats_t; /* * States for the FPM state machine. */ typedef enum { /* * In this state we are not yet ready to connect to the FPM. This * can happen when this module is disabled, or if we're cleaning up * after a connection has gone down. */ ZFPM_STATE_IDLE, /* * Ready to talk to the FPM and periodically trying to connect to * it. */ ZFPM_STATE_ACTIVE, /* * In the middle of bringing up a TCP connection. Specifically, * waiting for a connect() call to complete asynchronously. */ ZFPM_STATE_CONNECTING, /* * TCP connection to the FPM is up. */ ZFPM_STATE_ESTABLISHED } zfpm_state_t; /* * Globals. */ typedef struct zfpm_glob_t_ { /* * True if the FPM module has been enabled. */ int enabled; struct thread_master *master; zfpm_state_t state; /* * Port on which the FPM is running. */ int fpm_port; /* * List of rib_dest_t structures to be processed */ TAILQ_HEAD (zfpm_dest_q, rib_dest_t_) dest_q; /* * Stream socket to the FPM. */ int sock; /* * Buffers for messages to/from the FPM. */ struct stream *obuf; struct stream *ibuf; /* * Threads for I/O. */ struct thread *t_connect; struct thread *t_write; struct thread *t_read; /* * Thread to clean up after the TCP connection to the FPM goes down * and the state that belongs to it. */ struct thread *t_conn_down; struct { zfpm_rnodes_iter_t iter; } t_conn_down_state; /* * Thread to take actions once the TCP conn to the FPM comes up, and * the state that belongs to it. */ struct thread *t_conn_up; struct { zfpm_rnodes_iter_t iter; } t_conn_up_state; unsigned long connect_calls; time_t last_connect_call_time; /* * Stats from the start of the current statistics interval up to * now. These are the counters we typically update in the code. */ zfpm_stats_t stats; /* * Statistics that were gathered in the last collection interval. */ zfpm_stats_t last_ivl_stats; /* * Cumulative stats from the last clear to the start of the current * statistics interval. */ zfpm_stats_t cumulative_stats; /* * Stats interval timer. */ struct thread *t_stats; /* * If non-zero, the last time when statistics were cleared. */ time_t last_stats_clear_time; } zfpm_glob_t; static zfpm_glob_t zfpm_glob_space; static zfpm_glob_t *zfpm_g = &zfpm_glob_space; static int zfpm_read_cb (struct thread *thread); static int zfpm_write_cb (struct thread *thread); static void zfpm_set_state (zfpm_state_t state, const char *reason); static void zfpm_start_connect_timer (const char *reason); static void zfpm_start_stats_timer (void); /* * zfpm_thread_should_yield */ static inline int zfpm_thread_should_yield (struct thread *t) { return thread_should_yield (t); } /* * zfpm_state_to_str */ static const char * zfpm_state_to_str (zfpm_state_t state) { switch (state) { case ZFPM_STATE_IDLE: return "idle"; case ZFPM_STATE_ACTIVE: return "active"; case ZFPM_STATE_CONNECTING: return "connecting"; case ZFPM_STATE_ESTABLISHED: return "established"; default: return "unknown"; } } /* * zfpm_get_time */ static time_t zfpm_get_time (void) { struct timeval tv; if (quagga_gettime (QUAGGA_CLK_MONOTONIC, &tv) < 0) zlog_warn ("FPM: quagga_gettime failed!!"); return tv.tv_sec; } /* * zfpm_get_elapsed_time * * Returns the time elapsed (in seconds) since the given time. */ static time_t zfpm_get_elapsed_time (time_t reference) { time_t now; now = zfpm_get_time (); if (now < reference) { assert (0); return 0; } return now - reference; } /* * zfpm_is_table_for_fpm * * Returns TRUE if the the given table is to be communicated to the * FPM. */ static inline int zfpm_is_table_for_fpm (struct route_table *table) { rib_table_info_t *info; info = rib_table_info (table); /* * We only send the unicast tables in the main instance to the FPM * at this point. */ if (info->vrf->id != 0) return 0; if (info->safi != SAFI_UNICAST) return 0; return 1; } /* * zfpm_rnodes_iter_init */ static inline void zfpm_rnodes_iter_init (zfpm_rnodes_iter_t *iter) { memset (iter, 0, sizeof (*iter)); rib_tables_iter_init (&iter->tables_iter); /* * This is a hack, but it makes implementing 'next' easier by * ensuring that route_table_iter_next() will return NULL the first * time we call it. */ route_table_iter_init (&iter->iter, NULL); route_table_iter_cleanup (&iter->iter); } /* * zfpm_rnodes_iter_next */ static inline struct route_node * zfpm_rnodes_iter_next (zfpm_rnodes_iter_t *iter) { struct route_node *rn; struct route_table *table; while (1) { rn = route_table_iter_next (&iter->iter); if (rn) return rn; /* * We've made our way through this table, go to the next one. */ route_table_iter_cleanup (&iter->iter); while ((table = rib_tables_iter_next (&iter->tables_iter))) { if (zfpm_is_table_for_fpm (table)) break; } if (!table) return NULL; route_table_iter_init (&iter->iter, table); } return NULL; } /* * zfpm_rnodes_iter_pause */ static inline void zfpm_rnodes_iter_pause (zfpm_rnodes_iter_t *iter) { route_table_iter_pause (&iter->iter); } /* * zfpm_rnodes_iter_cleanup */ static inline void zfpm_rnodes_iter_cleanup (zfpm_rnodes_iter_t *iter) { route_table_iter_cleanup (&iter->iter); rib_tables_iter_cleanup (&iter->tables_iter); } /* * zfpm_stats_init * * Initialize a statistics block. */ static inline void zfpm_stats_init (zfpm_stats_t *stats) { memset (stats, 0, sizeof (*stats)); } /* * zfpm_stats_reset */ static inline void zfpm_stats_reset (zfpm_stats_t *stats) { zfpm_stats_init (stats); } /* * zfpm_stats_copy */ static inline void zfpm_stats_copy (const zfpm_stats_t *src, zfpm_stats_t *dest) { memcpy (dest, src, sizeof (*dest)); } /* * zfpm_stats_compose * * Total up the statistics in two stats structures ('s1 and 's2') and * return the result in the third argument, 'result'. Note that the * pointer 'result' may be the same as 's1' or 's2'. * * For simplicity, the implementation below assumes that the stats * structure is composed entirely of counters. This can easily be * changed when necessary. */ static void zfpm_stats_compose (const zfpm_stats_t *s1, const zfpm_stats_t *s2, zfpm_stats_t *result) { const unsigned long *p1, *p2; unsigned long *result_p; int i, num_counters; p1 = (const unsigned long *) s1; p2 = (const unsigned long *) s2; result_p = (unsigned long *) result; num_counters = (sizeof (zfpm_stats_t) / sizeof (unsigned long)); for (i = 0; i < num_counters; i++) { result_p[i] = p1[i] + p2[i]; } } /* * zfpm_read_on */ static inline void zfpm_read_on (void) { assert (!zfpm_g->t_read); assert (zfpm_g->sock >= 0); THREAD_READ_ON (zfpm_g->master, zfpm_g->t_read, zfpm_read_cb, 0, zfpm_g->sock); } /* * zfpm_write_on */ static inline void zfpm_write_on (void) { assert (!zfpm_g->t_write); assert (zfpm_g->sock >= 0); THREAD_WRITE_ON (zfpm_g->master, zfpm_g->t_write, zfpm_write_cb, 0, zfpm_g->sock); } /* * zfpm_read_off */ static inline void zfpm_read_off (void) { THREAD_READ_OFF (zfpm_g->t_read); } /* * zfpm_write_off */ static inline void zfpm_write_off (void) { THREAD_WRITE_OFF (zfpm_g->t_write); } /* * zfpm_conn_up_thread_cb * * Callback for actions to be taken when the connection to the FPM * comes up. */ static int zfpm_conn_up_thread_cb (struct thread *thread) { struct route_node *rnode; zfpm_rnodes_iter_t *iter; rib_dest_t *dest; assert (zfpm_g->t_conn_up); zfpm_g->t_conn_up = NULL; iter = &zfpm_g->t_conn_up_state.iter; if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) { zfpm_debug ("Connection not up anymore, conn_up thread aborting"); zfpm_g->stats.t_conn_up_aborts++; goto done; } while ((rnode = zfpm_rnodes_iter_next (iter))) { dest = rib_dest_from_rnode (rnode); if (dest) { zfpm_g->stats.t_conn_up_dests_processed++; zfpm_trigger_update (rnode, NULL); } /* * Yield if need be. */ if (!zfpm_thread_should_yield (thread)) continue; zfpm_g->stats.t_conn_up_yields++; zfpm_rnodes_iter_pause (iter); zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, zfpm_conn_up_thread_cb, 0, 0); return 0; } zfpm_g->stats.t_conn_up_finishes++; done: zfpm_rnodes_iter_cleanup (iter); return 0; } /* * zfpm_connection_up * * Called when the connection to the FPM comes up. */ static void zfpm_connection_up (const char *detail) { assert (zfpm_g->sock >= 0); zfpm_read_on (); zfpm_write_on (); zfpm_set_state (ZFPM_STATE_ESTABLISHED, detail); /* * Start thread to push existing routes to the FPM. */ assert (!zfpm_g->t_conn_up); zfpm_rnodes_iter_init (&zfpm_g->t_conn_up_state.iter); zfpm_debug ("Starting conn_up thread"); zfpm_g->t_conn_up = thread_add_background (zfpm_g->master, zfpm_conn_up_thread_cb, 0, 0); zfpm_g->stats.t_conn_up_starts++; } /* * zfpm_connect_check * * Check if an asynchronous connect() to the FPM is complete. */ static void zfpm_connect_check () { int status; socklen_t slen; int ret; zfpm_read_off (); zfpm_write_off (); slen = sizeof (status); ret = getsockopt (zfpm_g->sock, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); if (ret >= 0 && status == 0) { zfpm_connection_up ("async connect complete"); return; } /* * getsockopt() failed or indicated an error on the socket. */ close (zfpm_g->sock); zfpm_g->sock = -1; zfpm_start_connect_timer ("getsockopt() after async connect failed"); return; } /* * zfpm_conn_down_thread_cb * * Callback that is invoked to clean up state after the TCP connection * to the FPM goes down. */ static int zfpm_conn_down_thread_cb (struct thread *thread) { struct route_node *rnode; zfpm_rnodes_iter_t *iter; rib_dest_t *dest; assert (zfpm_g->state == ZFPM_STATE_IDLE); assert (zfpm_g->t_conn_down); zfpm_g->t_conn_down = NULL; iter = &zfpm_g->t_conn_down_state.iter; while ((rnode = zfpm_rnodes_iter_next (iter))) { dest = rib_dest_from_rnode (rnode); if (dest) { if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); } UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); zfpm_g->stats.t_conn_down_dests_processed++; /* * Check if the dest should be deleted. */ rib_gc_dest(rnode); } /* * Yield if need be. */ if (!zfpm_thread_should_yield (thread)) continue; zfpm_g->stats.t_conn_down_yields++; zfpm_rnodes_iter_pause (iter); zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, zfpm_conn_down_thread_cb, 0, 0); return 0; } zfpm_g->stats.t_conn_down_finishes++; zfpm_rnodes_iter_cleanup (iter); /* * Start the process of connecting to the FPM again. */ zfpm_start_connect_timer ("cleanup complete"); return 0; } /* * zfpm_connection_down * * Called when the connection to the FPM has gone down. */ static void zfpm_connection_down (const char *detail) { if (!detail) detail = "unknown"; assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); zlog_info ("connection to the FPM has gone down: %s", detail); zfpm_read_off (); zfpm_write_off (); stream_reset (zfpm_g->ibuf); stream_reset (zfpm_g->obuf); if (zfpm_g->sock >= 0) { close (zfpm_g->sock); zfpm_g->sock = -1; } /* * Start thread to clean up state after the connection goes down. */ assert (!zfpm_g->t_conn_down); zfpm_debug ("Starting conn_down thread"); zfpm_rnodes_iter_init (&zfpm_g->t_conn_down_state.iter); zfpm_g->t_conn_down = thread_add_background (zfpm_g->master, zfpm_conn_down_thread_cb, 0, 0); zfpm_g->stats.t_conn_down_starts++; zfpm_set_state (ZFPM_STATE_IDLE, detail); } /* * zfpm_read_cb */ static int zfpm_read_cb (struct thread *thread) { size_t already; struct stream *ibuf; uint16_t msg_len; fpm_msg_hdr_t *hdr; zfpm_g->stats.read_cb_calls++; assert (zfpm_g->t_read); zfpm_g->t_read = NULL; /* * Check if async connect is now done. */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check(); return 0; } assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); assert (zfpm_g->sock >= 0); ibuf = zfpm_g->ibuf; already = stream_get_endp (ibuf); if (already < FPM_MSG_HDR_LEN) { ssize_t nbyte; nbyte = stream_read_try (ibuf, zfpm_g->sock, FPM_MSG_HDR_LEN - already); if (nbyte == 0 || nbyte == -1) { zfpm_connection_down ("closed socket in read"); return 0; } if (nbyte != (ssize_t) (FPM_MSG_HDR_LEN - already)) goto done; already = FPM_MSG_HDR_LEN; } stream_set_getp (ibuf, 0); hdr = (fpm_msg_hdr_t *) stream_pnt (ibuf); if (!fpm_msg_hdr_ok (hdr)) { zfpm_connection_down ("invalid message header"); return 0; } msg_len = fpm_msg_len (hdr); /* * Read out the rest of the packet. */ if (already < msg_len) { ssize_t nbyte; nbyte = stream_read_try (ibuf, zfpm_g->sock, msg_len - already); if (nbyte == 0 || nbyte == -1) { zfpm_connection_down ("failed to read message"); return 0; } if (nbyte != (ssize_t) (msg_len - already)) goto done; } zfpm_debug ("Read out a full fpm message"); /* * Just throw it away for now. */ stream_reset (ibuf); done: zfpm_read_on (); return 0; } /* * zfpm_writes_pending * * Returns TRUE if we may have something to write to the FPM. */ static int zfpm_writes_pending (void) { /* * Check if there is any data in the outbound buffer that has not * been written to the socket yet. */ if (stream_get_endp (zfpm_g->obuf) - stream_get_getp (zfpm_g->obuf)) return 1; /* * Check if there are any prefixes on the outbound queue. */ if (!TAILQ_EMPTY (&zfpm_g->dest_q)) return 1; return 0; } /* * zfpm_encode_route * * Encode a message to the FPM with information about the given route. * * Returns the number of bytes written to the buffer. 0 or a negative * value indicates an error. */ static inline int zfpm_encode_route (rib_dest_t *dest, struct rib *rib, char *in_buf, size_t in_buf_len) { #ifndef HAVE_NETLINK return 0; #else int cmd; cmd = rib ? RTM_NEWROUTE : RTM_DELROUTE; return zfpm_netlink_encode_route (cmd, dest, rib, in_buf, in_buf_len); #endif /* HAVE_NETLINK */ } /* * zfpm_route_for_update * * Returns the rib that is to be sent to the FPM for a given dest. */ static struct rib * zfpm_route_for_update (rib_dest_t *dest) { struct rib *rib; RIB_DEST_FOREACH_ROUTE (dest, rib) { if (!CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) continue; return rib; } /* * We have no route for this destination. */ return NULL; } /* * zfpm_build_updates * * Process the outgoing queue and write messages to the outbound * buffer. */ static void zfpm_build_updates (void) { struct stream *s; rib_dest_t *dest; unsigned char *buf, *data, *buf_end; size_t msg_len; size_t data_len; fpm_msg_hdr_t *hdr; struct rib *rib; int is_add, write_msg; s = zfpm_g->obuf; assert (stream_empty (s)); do { /* * Make sure there is enough space to write another message. */ if (STREAM_WRITEABLE (s) < FPM_MAX_MSG_LEN) break; buf = STREAM_DATA (s) + stream_get_endp (s); buf_end = buf + STREAM_WRITEABLE (s); dest = TAILQ_FIRST (&zfpm_g->dest_q); if (!dest) break; assert (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)); hdr = (fpm_msg_hdr_t *) buf; hdr->version = FPM_PROTO_VERSION; hdr->msg_type = FPM_MSG_TYPE_NETLINK; data = fpm_msg_data (hdr); rib = zfpm_route_for_update (dest); is_add = rib ? 1 : 0; write_msg = 1; /* * If this is a route deletion, and we have not sent the route to * the FPM previously, skip it. */ if (!is_add && !CHECK_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM)) { write_msg = 0; zfpm_g->stats.nop_deletes_skipped++; } if (write_msg) { data_len = zfpm_encode_route (dest, rib, (char *) data, buf_end - data); assert (data_len); if (data_len) { msg_len = fpm_data_len_to_msg_len (data_len); hdr->msg_len = htons (msg_len); stream_forward_endp (s, msg_len); if (is_add) zfpm_g->stats.route_adds++; else zfpm_g->stats.route_dels++; } } /* * Remove the dest from the queue, and reset the flag. */ UNSET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); TAILQ_REMOVE (&zfpm_g->dest_q, dest, fpm_q_entries); if (is_add) { SET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); } else { UNSET_FLAG (dest->flags, RIB_DEST_SENT_TO_FPM); } /* * Delete the destination if necessary. */ if (rib_gc_dest (dest->rnode)) zfpm_g->stats.dests_del_after_update++; } while (1); } /* * zfpm_write_cb */ static int zfpm_write_cb (struct thread *thread) { struct stream *s; int num_writes; zfpm_g->stats.write_cb_calls++; assert (zfpm_g->t_write); zfpm_g->t_write = NULL; /* * Check if async connect is now done. */ if (zfpm_g->state == ZFPM_STATE_CONNECTING) { zfpm_connect_check (); return 0; } assert (zfpm_g->state == ZFPM_STATE_ESTABLISHED); assert (zfpm_g->sock >= 0); num_writes = 0; do { int bytes_to_write, bytes_written; s = zfpm_g->obuf; /* * If the stream is empty, try fill it up with data. */ if (stream_empty (s)) { zfpm_build_updates (); } bytes_to_write = stream_get_endp (s) - stream_get_getp (s); if (!bytes_to_write) break; bytes_written = write (zfpm_g->sock, STREAM_PNT (s), bytes_to_write); zfpm_g->stats.write_calls++; num_writes++; if (bytes_written < 0) { if (ERRNO_IO_RETRY (errno)) break; zfpm_connection_down ("failed to write to socket"); return 0; } if (bytes_written != bytes_to_write) { /* * Partial write. */ stream_forward_getp (s, bytes_written); zfpm_g->stats.partial_writes++; break; } /* * We've written out the entire contents of the stream. */ stream_reset (s); if (num_writes >= ZFPM_MAX_WRITES_PER_RUN) { zfpm_g->stats.max_writes_hit++; break; } if (zfpm_thread_should_yield (thread)) { zfpm_g->stats.t_write_yields++; break; } } while (1); if (zfpm_writes_pending ()) zfpm_write_on (); return 0; } /* * zfpm_connect_cb */ static int zfpm_connect_cb (struct thread *t) { int sock, ret; struct sockaddr_in serv; assert (zfpm_g->t_connect); zfpm_g->t_connect = NULL; assert (zfpm_g->state == ZFPM_STATE_ACTIVE); sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zfpm_debug ("Failed to create socket for connect(): %s", strerror(errno)); zfpm_g->stats.connect_no_sock++; return 0; } set_nonblocking(sock); /* Make server socket. */ memset (&serv, 0, sizeof (serv)); serv.sin_family = AF_INET; serv.sin_port = htons (zfpm_g->fpm_port); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* * Connect to the FPM. */ zfpm_g->connect_calls++; zfpm_g->stats.connect_calls++; zfpm_g->last_connect_call_time = zfpm_get_time (); ret = connect (sock, (struct sockaddr *) &serv, sizeof (serv)); if (ret >= 0) { zfpm_g->sock = sock; zfpm_connection_up ("connect succeeded"); return 1; } if (errno == EINPROGRESS) { zfpm_g->sock = sock; zfpm_read_on (); zfpm_write_on (); zfpm_set_state (ZFPM_STATE_CONNECTING, "async connect in progress"); return 0; } zlog_info ("can't connect to FPM %d: %s", sock, safe_strerror (errno)); close (sock); /* * Restart timer for retrying connection. */ zfpm_start_connect_timer ("connect() failed"); return 0; } /* * zfpm_set_state * * Move state machine into the given state. */ static void zfpm_set_state (zfpm_state_t state, const char *reason) { zfpm_state_t cur_state = zfpm_g->state; if (!reason) reason = "Unknown"; if (state == cur_state) return; zfpm_debug("beginning state transition %s -> %s. Reason: %s", zfpm_state_to_str (cur_state), zfpm_state_to_str (state), reason); switch (state) { case ZFPM_STATE_IDLE: assert (cur_state == ZFPM_STATE_ESTABLISHED); break; case ZFPM_STATE_ACTIVE: assert (cur_state == ZFPM_STATE_IDLE || cur_state == ZFPM_STATE_CONNECTING); assert (zfpm_g->t_connect); break; case ZFPM_STATE_CONNECTING: assert (zfpm_g->sock); assert (cur_state == ZFPM_STATE_ACTIVE); assert (zfpm_g->t_read); assert (zfpm_g->t_write); break; case ZFPM_STATE_ESTABLISHED: assert (cur_state == ZFPM_STATE_ACTIVE || cur_state == ZFPM_STATE_CONNECTING); assert (zfpm_g->sock); assert (zfpm_g->t_read); assert (zfpm_g->t_write); break; } zfpm_g->state = state; } /* * zfpm_calc_connect_delay * * Returns the number of seconds after which we should attempt to * reconnect to the FPM. */ static long zfpm_calc_connect_delay (void) { time_t elapsed; /* * Return 0 if this is our first attempt to connect. */ if (zfpm_g->connect_calls == 0) { return 0; } elapsed = zfpm_get_elapsed_time (zfpm_g->last_connect_call_time); if (elapsed > ZFPM_CONNECT_RETRY_IVL) { return 0; } return ZFPM_CONNECT_RETRY_IVL - elapsed; } /* * zfpm_start_connect_timer */ static void zfpm_start_connect_timer (const char *reason) { long delay_secs; assert (!zfpm_g->t_connect); assert (zfpm_g->sock < 0); assert(zfpm_g->state == ZFPM_STATE_IDLE || zfpm_g->state == ZFPM_STATE_ACTIVE || zfpm_g->state == ZFPM_STATE_CONNECTING); delay_secs = zfpm_calc_connect_delay(); zfpm_debug ("scheduling connect in %ld seconds", delay_secs); THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_connect, zfpm_connect_cb, 0, delay_secs); zfpm_set_state (ZFPM_STATE_ACTIVE, reason); } /* * zfpm_is_enabled * * Returns TRUE if the zebra FPM module has been enabled. */ static inline int zfpm_is_enabled (void) { return zfpm_g->enabled; } /* * zfpm_conn_is_up * * Returns TRUE if the connection to the FPM is up. */ static inline int zfpm_conn_is_up (void) { if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) return 0; assert (zfpm_g->sock >= 0); return 1; } /* * zfpm_trigger_update * * The zebra code invokes this function to indicate that we should * send an update to the FPM about the given route_node. */ void zfpm_trigger_update (struct route_node *rn, const char *reason) { rib_dest_t *dest; char buf[INET6_ADDRSTRLEN]; /* * Ignore if the connection is down. We will update the FPM about * all destinations once the connection comes up. */ if (!zfpm_conn_is_up ()) return; dest = rib_dest_from_rnode (rn); /* * Ignore the trigger if the dest is not in a table that we would * send to the FPM. */ if (!zfpm_is_table_for_fpm (rib_dest_table (dest))) { zfpm_g->stats.non_fpm_table_triggers++; return; } if (CHECK_FLAG (dest->flags, RIB_DEST_UPDATE_FPM)) { zfpm_g->stats.redundant_triggers++; return; } if (reason) { zfpm_debug ("%s/%d triggering update to FPM - Reason: %s", inet_ntop (rn->p.family, &rn->p.u.prefix, buf, sizeof (buf)), rn->p.prefixlen, reason); } SET_FLAG (dest->flags, RIB_DEST_UPDATE_FPM); TAILQ_INSERT_TAIL (&zfpm_g->dest_q, dest, fpm_q_entries); zfpm_g->stats.updates_triggered++; /* * Make sure that writes are enabled. */ if (zfpm_g->t_write) return; zfpm_write_on (); } /* * zfpm_stats_timer_cb */ static int zfpm_stats_timer_cb (struct thread *t) { assert (zfpm_g->t_stats); zfpm_g->t_stats = NULL; /* * Remember the stats collected in the last interval for display * purposes. */ zfpm_stats_copy (&zfpm_g->stats, &zfpm_g->last_ivl_stats); /* * Add the current set of stats into the cumulative statistics. */ zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, &zfpm_g->cumulative_stats); /* * Start collecting stats afresh over the next interval. */ zfpm_stats_reset (&zfpm_g->stats); zfpm_start_stats_timer (); return 0; } /* * zfpm_stop_stats_timer */ static void zfpm_stop_stats_timer (void) { if (!zfpm_g->t_stats) return; zfpm_debug ("Stopping existing stats timer"); THREAD_TIMER_OFF (zfpm_g->t_stats); } /* * zfpm_start_stats_timer */ void zfpm_start_stats_timer (void) { assert (!zfpm_g->t_stats); THREAD_TIMER_ON (zfpm_g->master, zfpm_g->t_stats, zfpm_stats_timer_cb, 0, ZFPM_STATS_IVL_SECS); } /* * Helper macro for zfpm_show_stats() below. */ #define ZFPM_SHOW_STAT(counter) \ do { \ vty_out (vty, "%-40s %10lu %16lu%s", #counter, total_stats.counter, \ zfpm_g->last_ivl_stats.counter, VTY_NEWLINE); \ } while (0) /* * zfpm_show_stats */ static void zfpm_show_stats (struct vty *vty) { zfpm_stats_t total_stats; time_t elapsed; vty_out (vty, "%s%-40s %10s Last %2d secs%s%s", VTY_NEWLINE, "Counter", "Total", ZFPM_STATS_IVL_SECS, VTY_NEWLINE, VTY_NEWLINE); /* * Compute the total stats up to this instant. */ zfpm_stats_compose (&zfpm_g->cumulative_stats, &zfpm_g->stats, &total_stats); ZFPM_SHOW_STAT (connect_calls); ZFPM_SHOW_STAT (connect_no_sock); ZFPM_SHOW_STAT (read_cb_calls); ZFPM_SHOW_STAT (write_cb_calls); ZFPM_SHOW_STAT (write_calls); ZFPM_SHOW_STAT (partial_writes); ZFPM_SHOW_STAT (max_writes_hit); ZFPM_SHOW_STAT (t_write_yields); ZFPM_SHOW_STAT (nop_deletes_skipped); ZFPM_SHOW_STAT (route_adds); ZFPM_SHOW_STAT (route_dels); ZFPM_SHOW_STAT (updates_triggered); ZFPM_SHOW_STAT (non_fpm_table_triggers); ZFPM_SHOW_STAT (redundant_triggers); ZFPM_SHOW_STAT (dests_del_after_update); ZFPM_SHOW_STAT (t_conn_down_starts); ZFPM_SHOW_STAT (t_conn_down_dests_processed); ZFPM_SHOW_STAT (t_conn_down_yields); ZFPM_SHOW_STAT (t_conn_down_finishes); ZFPM_SHOW_STAT (t_conn_up_starts); ZFPM_SHOW_STAT (t_conn_up_dests_processed); ZFPM_SHOW_STAT (t_conn_up_yields); ZFPM_SHOW_STAT (t_conn_up_aborts); ZFPM_SHOW_STAT (t_conn_up_finishes); if (!zfpm_g->last_stats_clear_time) return; elapsed = zfpm_get_elapsed_time (zfpm_g->last_stats_clear_time); vty_out (vty, "%sStats were cleared %lu seconds ago%s", VTY_NEWLINE, (unsigned long) elapsed, VTY_NEWLINE); } /* * zfpm_clear_stats */ static void zfpm_clear_stats (struct vty *vty) { if (!zfpm_is_enabled ()) { vty_out (vty, "The FPM module is not enabled...%s", VTY_NEWLINE); return; } zfpm_stats_reset (&zfpm_g->stats); zfpm_stats_reset (&zfpm_g->last_ivl_stats); zfpm_stats_reset (&zfpm_g->cumulative_stats); zfpm_stop_stats_timer (); zfpm_start_stats_timer (); zfpm_g->last_stats_clear_time = zfpm_get_time(); vty_out (vty, "Cleared FPM stats%s", VTY_NEWLINE); } /* * show_zebra_fpm_stats */ DEFUN (show_zebra_fpm_stats, show_zebra_fpm_stats_cmd, "show zebra fpm stats", SHOW_STR "Zebra information\n" "Forwarding Path Manager information\n" "Statistics\n") { zfpm_show_stats (vty); return CMD_SUCCESS; } /* * clear_zebra_fpm_stats */ DEFUN (clear_zebra_fpm_stats, clear_zebra_fpm_stats_cmd, "clear zebra fpm stats", CLEAR_STR "Zebra information\n" "Clear Forwarding Path Manager information\n" "Statistics\n") { zfpm_clear_stats (vty); return CMD_SUCCESS; } /** * zfpm_init * * One-time initialization of the Zebra FPM module. * * @param[in] port port at which FPM is running. * @param[in] enable TRUE if the zebra FPM module should be enabled * * Returns TRUE on success. */ int zfpm_init (struct thread_master *master, int enable, uint16_t port) { static int initialized = 0; if (initialized) { return 1; } initialized = 1; memset (zfpm_g, 0, sizeof (*zfpm_g)); zfpm_g->master = master; TAILQ_INIT(&zfpm_g->dest_q); zfpm_g->sock = -1; zfpm_g->state = ZFPM_STATE_IDLE; /* * Netlink must currently be available for the Zebra-FPM interface * to be enabled. */ #ifndef HAVE_NETLINK enable = 0; #endif zfpm_g->enabled = enable; zfpm_stats_init (&zfpm_g->stats); zfpm_stats_init (&zfpm_g->last_ivl_stats); zfpm_stats_init (&zfpm_g->cumulative_stats); install_element (ENABLE_NODE, &show_zebra_fpm_stats_cmd); install_element (ENABLE_NODE, &clear_zebra_fpm_stats_cmd); if (!enable) { return 1; } if (!port) port = FPM_DEFAULT_PORT; zfpm_g->fpm_port = port; zfpm_g->obuf = stream_new (ZFPM_OBUF_SIZE); zfpm_g->ibuf = stream_new (ZFPM_IBUF_SIZE); zfpm_start_stats_timer (); zfpm_start_connect_timer ("initialized"); return 1; } quagga-0.99.24.1/zebra/router-id.c0000644000175000017500000001360412476520570013421 00000000000000/* * Router ID for zebra daemon. * * Copyright (C) 2004 James R. Leu * * This file is part of Quagga routing suite. * * Quagga is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * Quagga is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "if.h" #include "vty.h" #include "sockunion.h" #include "prefix.h" #include "stream.h" #include "command.h" #include "memory.h" #include "ioctl.h" #include "connected.h" #include "network.h" #include "log.h" #include "table.h" #include "rib.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" /* 2nd pointer type used primarily to quell a warning on * ALL_LIST_ELEMENTS_RO */ static struct list _rid_all_sorted_list; static struct list _rid_lo_sorted_list; static struct list *rid_all_sorted_list = &_rid_all_sorted_list; static struct list *rid_lo_sorted_list = &_rid_lo_sorted_list; static struct prefix rid_user_assigned; /* master zebra server structure */ extern struct zebra_t zebrad; static struct connected * router_id_find_node (struct list *l, struct connected *ifc) { struct listnode *node; struct connected *c; for (ALL_LIST_ELEMENTS_RO (l, node, c)) if (prefix_same (ifc->address, c->address)) return c; return NULL; } static int router_id_bad_address (struct connected *ifc) { if (ifc->address->family != AF_INET) return 1; /* non-redistributable addresses shouldn't be used for RIDs either */ if (!zebra_check_addr (ifc->address)) return 1; return 0; } void router_id_get (struct prefix *p) { struct listnode *node; struct connected *c; p->u.prefix4.s_addr = 0; p->family = AF_INET; p->prefixlen = 32; if (rid_user_assigned.u.prefix4.s_addr) p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr; else if (!list_isempty (rid_lo_sorted_list)) { node = listtail (rid_lo_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } else if (!list_isempty (rid_all_sorted_list)) { node = listtail (rid_all_sorted_list); c = listgetdata (node); p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; } } static void router_id_set (struct prefix *p) { struct prefix p2; struct listnode *node; struct zserv *client; rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; router_id_get (&p2); for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &p2); } void router_id_add_address (struct connected *ifc) { struct list *l = NULL; struct listnode *node; struct prefix before; struct prefix after; struct zserv *client; if (router_id_bad_address (ifc)) return; router_id_get (&before); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = rid_lo_sorted_list; else l = rid_all_sorted_list; if (!router_id_find_node (l, ifc)) listnode_add_sort (l, ifc); router_id_get (&after); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after); } void router_id_del_address (struct connected *ifc) { struct connected *c; struct list *l; struct prefix after; struct prefix before; struct listnode *node; struct zserv *client; if (router_id_bad_address (ifc)) return; router_id_get (&before); if (!strncmp (ifc->ifp->name, "lo", 2) || !strncmp (ifc->ifp->name, "dummy", 5)) l = rid_lo_sorted_list; else l = rid_all_sorted_list; if ((c = router_id_find_node (l, ifc))) listnode_delete (l, c); router_id_get (&after); if (prefix_same (&before, &after)) return; for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client)) zsend_router_id_update (client, &after); } void router_id_write (struct vty *vty) { if (rid_user_assigned.u.prefix4.s_addr) vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4), VTY_NEWLINE); } DEFUN (router_id, router_id_cmd, "router-id A.B.C.D", "Manually set the router-id\n" "IP address to use for router-id\n") { struct prefix rid; rid.u.prefix4.s_addr = inet_addr (argv[0]); if (!rid.u.prefix4.s_addr) return CMD_WARNING; rid.prefixlen = 32; rid.family = AF_INET; router_id_set (&rid); return CMD_SUCCESS; } DEFUN (no_router_id, no_router_id_cmd, "no router-id", NO_STR "Remove the manually configured router-id\n") { struct prefix rid; rid.u.prefix4.s_addr = 0; rid.prefixlen = 0; rid.family = AF_INET; router_id_set (&rid); return CMD_SUCCESS; } static int router_id_cmp (void *a, void *b) { const struct connected *ifa = (const struct connected *)a; const struct connected *ifb = (const struct connected *)b; return IPV4_ADDR_CMP(&ifa->address->u.prefix4.s_addr,&ifb->address->u.prefix4.s_addr); } void router_id_init (void) { install_element (CONFIG_NODE, &router_id_cmd); install_element (CONFIG_NODE, &no_router_id_cmd); memset (rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); memset (rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); rid_all_sorted_list->cmp = router_id_cmp; rid_lo_sorted_list->cmp = router_id_cmp; rid_user_assigned.family = AF_INET; rid_user_assigned.prefixlen = 32; } quagga-0.99.24.1/zebra/irdp_packet.c0000644000175000017500000002117712476520570014000 00000000000000/* * * Copyright (C) 2000 Robert Olsson. * Swedish University of Agricultural Sciences * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * This work includes work with the following copywrite: * * Copyright (C) 1997, 2000 Kunihiro Ishiguro * */ /* * Thanks to Jens Låås at Swedish University of Agricultural Sciences * for reviewing and tests. */ #include #ifdef HAVE_IRDP #include "if.h" #include "vty.h" #include "sockunion.h" #include "prefix.h" #include "command.h" #include "memory.h" #include "stream.h" #include "ioctl.h" #include "connected.h" #include "log.h" #include "zclient.h" #include "thread.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include #include "if.h" #include "checksum.h" #include "sockunion.h" #include "log.h" #include "sockopt.h" /* GLOBAL VARS */ int irdp_sock = -1; extern struct zebra_t zebrad; extern struct thread *t_irdp_raw; static void parse_irdp_packet(char *p, int len, struct interface *ifp) { struct ip *ip = (struct ip *)p ; struct icmphdr *icmp; struct in_addr src; int ip_hlen, iplen, datalen; struct zebra_if *zi; struct irdp_interface *irdp; zi = ifp->info; if (!zi) return; irdp = &zi->irdp; if (!irdp) return; ip_hlen = ip->ip_hl << 2; sockopt_iphdrincl_swab_systoh (ip); iplen = ip->ip_len; datalen = len - ip_hlen; src = ip->ip_src; if (len != iplen) { zlog_err ("IRDP: RX length doesnt match IP length"); return; } if (iplen < ICMP_MINLEN) { zlog_err ("IRDP: RX ICMP packet too short from %s\n", inet_ntoa (src)); return; } /* XXX: RAW doesnt receive link-layer, surely? ??? */ /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen + len of IP-header) 14+20 */ if (iplen > IRDP_RX_BUF-34) { zlog_err ("IRDP: RX ICMP packet too long from %s\n", inet_ntoa (src)); return; } icmp = (struct icmphdr *) (p+ip_hlen); /* check icmp checksum */ if (in_cksum (icmp, datalen) != icmp->checksum) { zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", inet_ntoa (src)); return; } /* Handle just only IRDP */ if (!(icmp->type == ICMP_ROUTERADVERT || icmp->type == ICMP_ROUTERSOLICIT)) return; if (icmp->code != 0) { zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code," " silently ignored", icmp->type, inet_ntoa (src)); return; } if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST) && (irdp->flags & IF_BROADCAST)) || (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP && !(irdp->flags & IF_BROADCAST))) { zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n", inet_ntoa (src), ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ? "multicast" : inet_ntoa (ip->ip_dst), ifp->name, irdp->flags & IF_BROADCAST ? "broadcast" : "multicast"); zlog_warn ("IRDP: Please correct settings\n"); return; } switch (icmp->type) { case ICMP_ROUTERADVERT: break; case ICMP_ROUTERSOLICIT: if(irdp->flags & IF_DEBUG_MESSAGES) zlog_debug ("IRDP: RX Solicit on %s from %s\n", ifp->name, inet_ntoa (src)); process_solicit(ifp); break; default: zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored", icmp->type, inet_ntoa (src)); } } static int irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex) { struct msghdr msg; struct iovec iov; char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )]; int ret; msg.msg_name = (void *)0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = size; ret = recvmsg (sock, &msg, 0); if (ret < 0) { zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno)); return ret; } if (msg.msg_flags & MSG_TRUNC) { zlog_warn("IRDP: recvmsg: truncated message"); return ret; } if (msg.msg_flags & MSG_CTRUNC) { zlog_warn("IRDP: recvmsg: truncated control message"); return ret; } *ifindex = getsockopt_ifindex (AF_INET, &msg); return ret; } int irdp_read_raw(struct thread *r) { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; char buf[IRDP_RX_BUF]; int ret, ifindex = 0; int irdp_sock = THREAD_FD (r); t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock); ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex); if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret); ifp = if_lookup_by_index(ifindex); if(! ifp ) return ret; zi= ifp->info; if(! zi ) return ret; irdp = &zi->irdp; if(! irdp ) return ret; if(! (irdp->flags & IF_ACTIVE)) { if(irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name); return 0; } if(irdp->flags & IF_DEBUG_PACKET) { int i; zlog_debug("IRDP: RX (idx %d) ", ifindex); for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF); } parse_irdp_packet(buf, ret, ifp); return ret; } void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst, struct prefix *p, u_int32_t ttl) { static struct sockaddr_in sockdst = {AF_INET}; struct ip *ip; struct icmphdr *icmp; struct msghdr *msg; struct cmsghdr *cmsg; struct iovec iovector; char msgbuf[256]; char buf[256]; struct in_pktinfo *pktinfo; u_long src; int on; if (!(ifp->flags & IFF_UP)) return; if (p) src = ntohl(p->u.prefix4.s_addr); else src = 0; /* Is filled in */ ip = (struct ip *) buf; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_v = IPVERSION; ip->ip_tos = 0xC0; ip->ip_off = 0L; ip->ip_p = 1; /* IP_ICMP */ ip->ip_ttl = ttl; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; icmp = (struct icmphdr *) (buf + sizeof (struct ip)); /* Merge IP header with icmp packet */ assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip))); stream_get(icmp, s, stream_get_endp(s)); /* icmp->checksum is already calculated */ ip->ip_len = sizeof(struct ip) + stream_get_endp(s); on = 1; if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0) zlog_warn("sendto %s", safe_strerror (errno)); if(dst == INADDR_BROADCAST ) { on = 1; if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, sizeof(on)) < 0) zlog_warn("sendto %s", safe_strerror (errno)); } if(dst != INADDR_BROADCAST) { on = 0; if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&on,sizeof(on)) < 0) zlog_warn("sendto %s", safe_strerror (errno)); } memset(&sockdst,0,sizeof(sockdst)); sockdst.sin_family=AF_INET; sockdst.sin_addr.s_addr = dst; cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr)); cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); pktinfo->ipi_ifindex = ifp->ifindex; pktinfo->ipi_spec_dst.s_addr = src; pktinfo->ipi_addr.s_addr = src; iovector.iov_base = (void *) buf; iovector.iov_len = ip->ip_len; msg = (struct msghdr *) msgbuf; msg->msg_name = &sockdst; msg->msg_namelen = sizeof(sockdst); msg->msg_iov = &iovector; msg->msg_iovlen = 1; msg->msg_control = cmsg; msg->msg_controllen = cmsg->cmsg_len; sockopt_iphdrincl_swab_htosys (ip); if (sendmsg(irdp_sock, msg, 0) < 0) { zlog_warn("sendto %s", safe_strerror (errno)); } /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ } #endif /* HAVE_IRDP */ quagga-0.99.24.1/zebra/irdp_interface.c0000644000175000017500000004263112476520570014467 00000000000000/* * * Copyright (C) 2000 Robert Olsson. * Swedish University of Agricultural Sciences * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * This work includes work with the following copywrite: * * Copyright (C) 1997, 2000 Kunihiro Ishiguro * */ /* * Thanks to Jens Låås at Swedish University of Agricultural Sciences * for reviewing and tests. */ #include #ifdef HAVE_IRDP #include "if.h" #include "vty.h" #include "sockunion.h" #include "prefix.h" #include "command.h" #include "memory.h" #include "stream.h" #include "ioctl.h" #include "connected.h" #include "log.h" #include "zclient.h" #include "thread.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include #include "if.h" #include "sockunion.h" #include "log.h" /* Master of threads. */ extern struct zebra_t zebrad; extern int irdp_sock; static const char * inet_2a(u_int32_t a, char *b) { sprintf(b, "%u.%u.%u.%u", (a ) & 0xFF, (a>> 8) & 0xFF, (a>>16) & 0xFF, (a>>24) & 0xFF); return b; } static struct prefix * irdp_get_prefix(struct interface *ifp) { struct listnode *node; struct connected *ifc; if (ifp->connected) for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) return ifc->address; return NULL; } /* Join to the add/leave multicast group. */ static int if_group (struct interface *ifp, int sock, u_int32_t group, int add_leave) { struct ip_mreq m; struct prefix *p; int ret; char b1[INET_ADDRSTRLEN]; memset (&m, 0, sizeof (m)); m.imr_multiaddr.s_addr = htonl (group); p = irdp_get_prefix(ifp); if(!p) { zlog_warn ("IRDP: can't get address for %s", ifp->name); return 1; } m.imr_interface = p->u.prefix4; ret = setsockopt (sock, IPPROTO_IP, add_leave, (char *) &m, sizeof (struct ip_mreq)); if (ret < 0) zlog_warn ("IRDP: %s can't setsockopt %s: %s", add_leave == IP_ADD_MEMBERSHIP? "join group":"leave group", inet_2a(group, b1), safe_strerror (errno)); return ret; } static int if_add_group (struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; int ret; char b1[INET_ADDRSTRLEN]; ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP); if (ret < 0) { return ret; } if(irdp->flags & IF_DEBUG_MISC ) zlog_debug("IRDP: Adding group %s for %s", inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); return 0; } static int if_drop_group (struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; int ret; char b1[INET_ADDRSTRLEN]; ret = if_group (ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_DROP_MEMBERSHIP); if (ret < 0) return ret; if(irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: Leaving group %s for %s", inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); return 0; } static void if_set_defaults(struct interface *ifp) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL; irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL; irdp->Preference = IRDP_PREFERENCE; irdp->Lifetime = IRDP_LIFETIME; } static struct Adv *Adv_new (void) { return XCALLOC (MTYPE_TMP, sizeof (struct Adv)); } static void Adv_free (struct Adv *adv) { XFREE (MTYPE_TMP, adv); } static void irdp_if_start(struct interface *ifp, int multicast, int set_defaults) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; struct listnode *node; struct connected *ifc; u_int32_t timer, seed; if (irdp->flags & IF_ACTIVE ) { zlog_warn("IRDP: Interface is already active %s", ifp->name); return; } if ((irdp_sock < 0) && ((irdp_sock = irdp_sock_init()) < 0)) { zlog_warn("IRDP: Cannot activate interface %s (cannot create " "IRDP socket)", ifp->name); return; } irdp->flags |= IF_ACTIVE; if(!multicast) irdp->flags |= IF_BROADCAST; if_add_update(ifp); if (! (ifp->flags & IFF_UP)) { zlog_warn("IRDP: Interface is down %s", ifp->name); } /* Shall we cancel if_start if if_add_group fails? */ if( multicast) { if_add_group(ifp); if (! (ifp->flags & (IFF_MULTICAST|IFF_ALLMULTI))) { zlog_warn("IRDP: Interface not multicast enabled %s", ifp->name); } } if(set_defaults) if_set_defaults(ifp); irdp->irdp_sent = 0; /* The spec suggests this for randomness */ seed = 0; if( ifp->connected) for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { seed = ifc->address->u.prefix4.s_addr; break; } srandom(seed); timer = (random () % IRDP_DEFAULT_INTERVAL) + 1; irdp->AdvPrefList = list_new(); irdp->AdvPrefList->del = (void (*)(void *)) Adv_free; /* Destructor */ /* And this for startup. Speed limit from 1991 :-). But it's OK*/ if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS && timer > MAX_INITIAL_ADVERT_INTERVAL ) timer= MAX_INITIAL_ADVERT_INTERVAL; if(irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: Init timer for %s set to %u", ifp->name, timer); irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer); } static void irdp_if_stop(struct interface *ifp) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; if (irdp == NULL) { zlog_warn ("Interface %s structure is NULL", ifp->name); return; } if (! (irdp->flags & IF_ACTIVE )) { zlog_warn("Interface is not active %s", ifp->name); return; } if(! (irdp->flags & IF_BROADCAST)) if_drop_group(ifp); irdp_advert_off(ifp); list_delete(irdp->AdvPrefList); irdp->AdvPrefList=NULL; irdp->flags = 0; } static void irdp_if_shutdown(struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; if (irdp->flags & IF_SHUTDOWN ) { zlog_warn("IRDP: Interface is already shutdown %s", ifp->name); return; } irdp->flags |= IF_SHUTDOWN; irdp->flags &= ~IF_ACTIVE; if(! (irdp->flags & IF_BROADCAST)) if_drop_group(ifp); /* Tell the hosts we are out of service */ irdp_advert_off(ifp); } static void irdp_if_no_shutdown(struct interface *ifp) { struct zebra_if *zi= ifp->info; struct irdp_interface *irdp = &zi->irdp; if (! (irdp->flags & IF_SHUTDOWN )) { zlog_warn("IRDP: Interface is not shutdown %s", ifp->name); return; } irdp->flags &= ~IF_SHUTDOWN; irdp_if_start(ifp, irdp->flags & IF_BROADCAST? FALSE : TRUE, FALSE); } /* Write configuration to user */ void irdp_config_write (struct vty *vty, struct interface *ifp) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; struct Adv *adv; struct listnode *node; char b1[INET_ADDRSTRLEN]; if(irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) { if( irdp->flags & IF_SHUTDOWN) vty_out (vty, " ip irdp shutdown %s", VTY_NEWLINE); if( irdp->flags & IF_BROADCAST) vty_out (vty, " ip irdp broadcast%s", VTY_NEWLINE); else vty_out (vty, " ip irdp multicast%s", VTY_NEWLINE); vty_out (vty, " ip irdp preference %ld%s", irdp->Preference, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) vty_out (vty, " ip irdp address %s preference %d%s", inet_2a(adv->ip.s_addr, b1), adv->pref, VTY_NEWLINE); vty_out (vty, " ip irdp holdtime %d%s", irdp->Lifetime, VTY_NEWLINE); vty_out (vty, " ip irdp minadvertinterval %ld%s", irdp->MinAdvertInterval, VTY_NEWLINE); vty_out (vty, " ip irdp maxadvertinterval %ld%s", irdp->MaxAdvertInterval, VTY_NEWLINE); } } DEFUN (ip_irdp_multicast, ip_irdp_multicast_cmd, "ip irdp multicast", IP_STR "ICMP Router discovery on this interface using multicast\n") { struct interface *ifp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } irdp_if_start(ifp, TRUE, TRUE); return CMD_SUCCESS; } DEFUN (ip_irdp_broadcast, ip_irdp_broadcast_cmd, "ip irdp broadcast", IP_STR "ICMP Router discovery on this interface using broadcast\n") { struct interface *ifp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } irdp_if_start(ifp, FALSE, TRUE); return CMD_SUCCESS; } DEFUN (no_ip_irdp, no_ip_irdp_cmd, "no ip irdp", NO_STR IP_STR "Disable ICMP Router discovery on this interface\n") { struct interface *ifp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } irdp_if_stop(ifp); return CMD_SUCCESS; } DEFUN (ip_irdp_shutdown, ip_irdp_shutdown_cmd, "ip irdp shutdown", IP_STR "ICMP Router discovery shutdown on this interface\n") { struct interface *ifp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } irdp_if_shutdown(ifp); return CMD_SUCCESS; } DEFUN (no_ip_irdp_shutdown, no_ip_irdp_shutdown_cmd, "no ip irdp shutdown", NO_STR IP_STR "ICMP Router discovery no shutdown on this interface\n") { struct interface *ifp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } irdp_if_no_shutdown(ifp); return CMD_SUCCESS; } DEFUN (ip_irdp_holdtime, ip_irdp_holdtime_cmd, "ip irdp holdtime <0-9000>", IP_STR "ICMP Router discovery on this interface\n" "Set holdtime value\n" "Holdtime value in seconds. Default is 1800 seconds\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->Lifetime = atoi(argv[0]); return CMD_SUCCESS; } DEFUN (ip_irdp_minadvertinterval, ip_irdp_minadvertinterval_cmd, "ip irdp minadvertinterval <3-1800>", IP_STR "ICMP Router discovery on this interface\n" "Set minimum time between advertisement\n" "Minimum advertisement interval in seconds\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; if( (unsigned) atoi(argv[0]) <= irdp->MaxAdvertInterval) { irdp->MinAdvertInterval = atoi(argv[0]); return CMD_SUCCESS; } vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", VTY_NEWLINE); vty_out (vty, "Please correct!%s", VTY_NEWLINE); return CMD_WARNING; } DEFUN (ip_irdp_maxadvertinterval, ip_irdp_maxadvertinterval_cmd, "ip irdp maxadvertinterval <4-1800>", IP_STR "ICMP Router discovery on this interface\n" "Set maximum time between advertisement\n" "Maximum advertisement interval in seconds\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; if( irdp->MinAdvertInterval <= (unsigned) atoi(argv[0]) ) { irdp->MaxAdvertInterval = atoi(argv[0]); return CMD_SUCCESS; } vty_out (vty, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s", VTY_NEWLINE); vty_out (vty, "Please correct!%s", VTY_NEWLINE); return CMD_WARNING; } /* DEFUN needs to be fixed for negative ranages... * "ip irdp preference <-2147483648-2147483647>", * Be positive for now. :-) */ DEFUN (ip_irdp_preference, ip_irdp_preference_cmd, "ip irdp preference <0-2147483647>", IP_STR "ICMP Router discovery on this interface\n" "Set default preference level for this interface\n" "Preference level\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->Preference = atoi(argv[0]); return CMD_SUCCESS; } DEFUN (ip_irdp_address_preference, ip_irdp_address_preference_cmd, "ip irdp address A.B.C.D preference <0-2147483647>", IP_STR "Alter ICMP Router discovery preference this interface\n" "Specify IRDP non-default preference to advertise\n" "Set IRDP address for advertise\n" "Preference level\n") { struct listnode *node; struct in_addr ip; int pref; int ret; struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; struct Adv *adv; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; ret = inet_aton(argv[0], &ip); if(!ret) return CMD_WARNING; pref = atoi(argv[1]); for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) if(adv->ip.s_addr == ip.s_addr) return CMD_SUCCESS; adv = Adv_new(); adv->ip = ip; adv->pref = pref; listnode_add(irdp->AdvPrefList, adv); return CMD_SUCCESS; } DEFUN (no_ip_irdp_address_preference, no_ip_irdp_address_preference_cmd, "no ip irdp address A.B.C.D preference <0-2147483647>", NO_STR IP_STR "Alter ICMP Router discovery preference this interface\n" "Removes IRDP non-default preference\n" "Select IRDP address\n" "Old preference level\n") { struct listnode *node, *nnode; struct in_addr ip; int ret; struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; struct Adv *adv; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; ret = inet_aton(argv[0], &ip); if (!ret) return CMD_WARNING; for (ALL_LIST_ELEMENTS (irdp->AdvPrefList, node, nnode, adv)) { if(adv->ip.s_addr == ip.s_addr ) { listnode_delete(irdp->AdvPrefList, adv); break; } } return CMD_SUCCESS; } DEFUN (ip_irdp_debug_messages, ip_irdp_debug_messages_cmd, "ip irdp debug messages", IP_STR "ICMP Router discovery debug Averts. and Solicits (short)\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->flags |= IF_DEBUG_MESSAGES; return CMD_SUCCESS; } DEFUN (ip_irdp_debug_misc, ip_irdp_debug_misc_cmd, "ip irdp debug misc", IP_STR "ICMP Router discovery debug Averts. and Solicits (short)\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->flags |= IF_DEBUG_MISC; return CMD_SUCCESS; } DEFUN (ip_irdp_debug_packet, ip_irdp_debug_packet_cmd, "ip irdp debug packet", IP_STR "ICMP Router discovery debug Averts. and Solicits (short)\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->flags |= IF_DEBUG_PACKET; return CMD_SUCCESS; } DEFUN (ip_irdp_debug_disable, ip_irdp_debug_disable_cmd, "ip irdp debug disable", IP_STR "ICMP Router discovery debug Averts. and Solicits (short)\n") { struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; ifp = (struct interface *) vty->index; if(!ifp) { return CMD_WARNING; } zi=ifp->info; irdp=&zi->irdp; irdp->flags &= ~IF_DEBUG_PACKET; irdp->flags &= ~IF_DEBUG_MESSAGES; irdp->flags &= ~IF_DEBUG_MISC; return CMD_SUCCESS; } void irdp_init () { install_element (INTERFACE_NODE, &ip_irdp_broadcast_cmd); install_element (INTERFACE_NODE, &ip_irdp_multicast_cmd); install_element (INTERFACE_NODE, &no_ip_irdp_cmd); install_element (INTERFACE_NODE, &ip_irdp_shutdown_cmd); install_element (INTERFACE_NODE, &no_ip_irdp_shutdown_cmd); install_element (INTERFACE_NODE, &ip_irdp_holdtime_cmd); install_element (INTERFACE_NODE, &ip_irdp_maxadvertinterval_cmd); install_element (INTERFACE_NODE, &ip_irdp_minadvertinterval_cmd); install_element (INTERFACE_NODE, &ip_irdp_preference_cmd); install_element (INTERFACE_NODE, &ip_irdp_address_preference_cmd); install_element (INTERFACE_NODE, &no_ip_irdp_address_preference_cmd); install_element (INTERFACE_NODE, &ip_irdp_debug_messages_cmd); install_element (INTERFACE_NODE, &ip_irdp_debug_misc_cmd); install_element (INTERFACE_NODE, &ip_irdp_debug_packet_cmd); install_element (INTERFACE_NODE, &ip_irdp_debug_disable_cmd); } #endif /* HAVE_IRDP */ quagga-0.99.24.1/zebra/irdp_main.c0000644000175000017500000001745412476520570013460 00000000000000/* * * Copyright (C) 2000 Robert Olsson. * Swedish University of Agricultural Sciences * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ /* * This work includes work with the following copywrite: * * Copyright (C) 1997, 2000 Kunihiro Ishiguro * */ /* * Thanks to Jens Låås at Swedish University of Agricultural Sciences * for reviewing and tests. */ #include #ifdef HAVE_IRDP #include "if.h" #include "vty.h" #include "sockunion.h" #include "sockopt.h" #include "prefix.h" #include "command.h" #include "memory.h" #include "stream.h" #include "ioctl.h" #include "connected.h" #include "log.h" #include "zclient.h" #include "thread.h" #include "privs.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/irdp.h" #include #include "checksum.h" #include "if.h" #include "sockunion.h" #include "log.h" /* GLOBAL VARS */ extern struct zebra_privs_t zserv_privs; /* Master of threads. */ extern struct zebra_t zebrad; struct thread *t_irdp_raw; /* Timer interval of irdp. */ int irdp_timer_interval = IRDP_DEFAULT_INTERVAL; int irdp_sock_init (void) { int ret, i; int save_errno; int sock; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("irdp_sock_init: could not raise privs, %s", safe_strerror (errno) ); sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP); save_errno = errno; if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("irdp_sock_init: could not lower privs, %s", safe_strerror (errno) ); if (sock < 0) { zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno)); return sock; }; i = 1; ret = setsockopt (sock, IPPROTO_IP, IP_TTL, (void *) &i, sizeof (i)); if (ret < 0) { zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno)); close(sock); return ret; }; ret = setsockopt_ifindex (AF_INET, sock, 1); if (ret < 0) { zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno)); close(sock); return ret; }; t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, sock); return sock; } static int get_pref(struct irdp_interface *irdp, struct prefix *p) { struct listnode *node; struct Adv *adv; /* Use default preference or use the override pref */ if( irdp->AdvPrefList == NULL ) return irdp->Preference; for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv)) if( p->u.prefix4.s_addr == adv->ip.s_addr ) return adv->pref; return irdp->Preference; } /* Make ICMP Router Advertisement Message. */ static int make_advertisement_packet (struct interface *ifp, struct prefix *p, struct stream *s) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; int size; int pref; u_int16_t checksum; pref = get_pref(irdp, p); stream_putc (s, ICMP_ROUTERADVERT); /* Type. */ stream_putc (s, 0); /* Code. */ stream_putw (s, 0); /* Checksum. */ stream_putc (s, 1); /* Num address. */ stream_putc (s, 2); /* Address Entry Size. */ if(irdp->flags & IF_SHUTDOWN) stream_putw (s, 0); else stream_putw (s, irdp->Lifetime); stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */ stream_putl (s, pref); /* in_cksum return network byte order value */ size = 16; checksum = in_cksum (s->data, size); stream_putw_at (s, 2, htons(checksum)); return size; } static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; u_int32_t dst; u_int32_t ttl=1; if (! (ifp->flags & IFF_UP)) return; if (irdp->flags & IF_BROADCAST) dst =INADDR_BROADCAST ; else dst = htonl(INADDR_ALLHOSTS_GROUP); if(irdp->flags & IF_DEBUG_MESSAGES) zlog_debug("IRDP: TX Advert on %s %s/%d Holdtime=%d Preference=%d", ifp->name, inet_ntoa(p->u.prefix4), p->prefixlen, irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime, get_pref(irdp, p)); send_packet (ifp, s, dst, p, ttl); } static void irdp_advertisement (struct interface *ifp, struct prefix *p) { struct stream *s; s = stream_new (128); make_advertisement_packet (ifp, p, s); irdp_send(ifp, p, s); stream_free (s); } int irdp_send_thread(struct thread *t_advert) { u_int32_t timer, tmp; struct interface *ifp = THREAD_ARG (t_advert); struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; struct prefix *p; struct listnode *node, *nnode; struct connected *ifc; irdp->flags &= ~IF_SOLICIT; if(ifp->connected) for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc)) { p = ifc->address; if (p->family != AF_INET) continue; irdp_advertisement(ifp, p); irdp->irdp_sent++; } tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval; timer = (random () % tmp ) + 1; timer = irdp->MinAdvertInterval + timer; if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS && timer > MAX_INITIAL_ADVERT_INTERVAL ) timer= MAX_INITIAL_ADVERT_INTERVAL; if(irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer); irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer); return 0; } void irdp_advert_off(struct interface *ifp) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; struct listnode *node, *nnode; int i; struct connected *ifc; struct prefix *p; if(irdp->t_advertise) thread_cancel(irdp->t_advertise); irdp->t_advertise = NULL; if(ifp->connected) for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc)) { p = ifc->address; /* Output some packets with Lifetime 0 we should add a wait... */ for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++) { irdp->irdp_sent++; irdp_advertisement(ifp, p); } } } void process_solicit (struct interface *ifp) { struct zebra_if *zi=ifp->info; struct irdp_interface *irdp=&zi->irdp; u_int32_t timer; /* When SOLICIT is active we reject further incoming solicits this keeps down the answering rate so we don't have think about DoS attacks here. */ if( irdp->flags & IF_SOLICIT) return; irdp->flags |= IF_SOLICIT; if(irdp->t_advertise) thread_cancel(irdp->t_advertise); irdp->t_advertise = NULL; timer = (random () % MAX_RESPONSE_DELAY) + 1; irdp->t_advertise = thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer); } void irdp_finish() { struct listnode *node, *nnode; struct interface *ifp; struct zebra_if *zi; struct irdp_interface *irdp; zlog_info("IRDP: Received shutdown notification."); for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { zi = ifp->info; if (!zi) continue; irdp = &zi->irdp; if (!irdp) continue; if (irdp->flags & IF_ACTIVE ) { irdp->flags |= IF_SHUTDOWN; irdp_advert_off(ifp); } } } #endif /* HAVE_IRDP */ quagga-0.99.24.1/zebra/zebra_snmp.c0000644000175000017500000003570612476520570013656 00000000000000/* FIB SNMP. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "smux.h" #include "table.h" #include "zebra/rib.h" #include "zebra/zserv.h" #define IPFWMIB 1,3,6,1,2,1,4,24 /* ipForwardTable */ #define IPFORWARDDEST 1 #define IPFORWARDMASK 2 #define IPFORWARDPOLICY 3 #define IPFORWARDNEXTHOP 4 #define IPFORWARDIFINDEX 5 #define IPFORWARDTYPE 6 #define IPFORWARDPROTO 7 #define IPFORWARDAGE 8 #define IPFORWARDINFO 9 #define IPFORWARDNEXTHOPAS 10 #define IPFORWARDMETRIC1 11 #define IPFORWARDMETRIC2 12 #define IPFORWARDMETRIC3 13 #define IPFORWARDMETRIC4 14 #define IPFORWARDMETRIC5 15 /* ipCidrRouteTable */ #define IPCIDRROUTEDEST 1 #define IPCIDRROUTEMASK 2 #define IPCIDRROUTETOS 3 #define IPCIDRROUTENEXTHOP 4 #define IPCIDRROUTEIFINDEX 5 #define IPCIDRROUTETYPE 6 #define IPCIDRROUTEPROTO 7 #define IPCIDRROUTEAGE 8 #define IPCIDRROUTEINFO 9 #define IPCIDRROUTENEXTHOPAS 10 #define IPCIDRROUTEMETRIC1 11 #define IPCIDRROUTEMETRIC2 12 #define IPCIDRROUTEMETRIC3 13 #define IPCIDRROUTEMETRIC4 14 #define IPCIDRROUTEMETRIC5 15 #define IPCIDRROUTESTATUS 16 #define INTEGER32 ASN_INTEGER #define GAUGE32 ASN_GAUGE #define ENUMERATION ASN_INTEGER #define ROWSTATUS ASN_INTEGER #define IPADDRESS ASN_IPADDRESS #define OBJECTIDENTIFIER ASN_OBJECT_ID extern struct zebra_t zebrad; oid ipfw_oid [] = { IPFWMIB }; /* Hook functions. */ static u_char * ipFwNumber (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipFwTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipCidrNumber (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char * ipCidrTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); struct variable zebra_variables[] = { {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}}, {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}}, {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}}, {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}}, {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}}, {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}}, {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}}, {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}}, {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}}, {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}}, {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}}, {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}}, {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}}, {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}}, {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}}, {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}}, {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}}, {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}}, {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}}, {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}}, {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}}, {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}}, {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}}, {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}}, {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}}, {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}}, {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}}, {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}}, {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}}, {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}}, {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}} }; static u_char * ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { static int result; struct route_table *table; struct route_node *rn; struct rib *rib; if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return NULL; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; } static u_char * ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { static int result; struct route_table *table; struct route_node *rn; struct rib *rib; if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return 0; /* Return number of routing entries. */ result = 0; for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, rib) result++; return (u_char *)&result; } static int in_addr_cmp(u_char *p1, u_char *p2) { int i; for (i=0; i<4; i++) { if (*p1 < *p2) return -1; if (*p1 > *p2) return 1; p1++; p2++; } return 0; } static int in_addr_add(u_char *p, int num) { int i, ip0; ip0 = *p; p += 4; for (i = 3; 0 <= i; i--) { p--; if (*p + num > 255) { *p += num; num = 1; } else { *p += num; return 1; } } if (ip0 > *p) { /* ip + num > 0xffffffff */ return 0; } return 1; } static int proto_trans(int type) { switch (type) { case ZEBRA_ROUTE_SYSTEM: return 1; /* other */ case ZEBRA_ROUTE_KERNEL: return 1; /* other */ case ZEBRA_ROUTE_CONNECT: return 2; /* local interface */ case ZEBRA_ROUTE_STATIC: return 3; /* static route */ case ZEBRA_ROUTE_RIP: return 8; /* rip */ case ZEBRA_ROUTE_RIPNG: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_OSPF: return 13; /* ospf */ case ZEBRA_ROUTE_OSPF6: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_BGP: return 14; /* bgp */ default: return 1; /* other */ } } static void check_replace(struct route_node *np2, struct rib *rib2, struct route_node **np, struct rib **rib) { int proto, proto2; if (!*np) { *np = np2; *rib = rib2; return; } if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0) return; if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0) { *np = np2; *rib = rib2; return; } proto = proto_trans((*rib)->type); proto2 = proto_trans(rib2->type); if (proto2 > proto) return; if (proto2 < proto) { *np = np2; *rib = rib2; return; } if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, (u_char *)&rib2->nexthop->gate.ipv4) <= 0) return; *np = np2; *rib = rib2; return; } static void get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, int exact, struct route_node **np, struct rib **rib) { struct in_addr dest; struct route_table *table; struct route_node *np2; struct rib *rib2; int proto; int policy; struct in_addr nexthop; u_char *pnt; int i; /* Init index variables */ pnt = (u_char *) &dest; for (i = 0; i < 4; i++) *pnt++ = 0; pnt = (u_char *) &nexthop; for (i = 0; i < 4; i++) *pnt++ = 0; proto = 0; policy = 0; /* Init return variables */ *np = NULL; *rib = NULL; /* Short circuit exact matches of wrong length */ if (exact && (*objid_len != (unsigned) v->namelen + 10)) return; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (! table) return; /* Get INDEX information out of OID. * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop */ if (*objid_len > (unsigned) v->namelen) oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest); if (*objid_len > (unsigned) v->namelen + 4) proto = objid[v->namelen + 4]; if (*objid_len > (unsigned) v->namelen + 5) policy = objid[v->namelen + 5]; if (*objid_len > (unsigned) v->namelen + 6) oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6), &nexthop); /* Apply GETNEXT on not exact search */ if (!exact && (*objid_len >= (unsigned) v->namelen + 10)) { if (! in_addr_add((u_char *) &nexthop, 1)) return; } /* For exact: search matching entry in rib table. */ if (exact) { if (policy) /* Not supported (yet?) */ return; for (*np = route_top (table); *np; *np = route_next (*np)) { if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) { RNODE_FOREACH_RIB (*np, *rib) { if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, (u_char *)&nexthop)) if (proto == proto_trans((*rib)->type)) return; } } } return; } /* Search next best entry */ for (np2 = route_top (table); np2; np2 = route_next (np2)) { /* Check destination first */ if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0) RNODE_FOREACH_RIB (np2, rib2) check_replace(np2, rib2, np, rib); if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0) { /* have to look at each rib individually */ RNODE_FOREACH_RIB (np2, rib2) { int proto2, policy2; proto2 = proto_trans(rib2->type); policy2 = 0; if ((policy < policy2) || ((policy == policy2) && (proto < proto2)) || ((policy == policy2) && (proto == proto2) && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4, (u_char *) &nexthop) >= 0) )) check_replace(np2, rib2, np, rib); } } } if (!*rib) return; policy = 0; proto = proto_trans((*rib)->type); *objid_len = v->namelen + 10; pnt = (u_char *) &(*np)->p.u.prefix; for (i = 0; i < 4; i++) objid[v->namelen + i] = *pnt++; objid[v->namelen + 4] = proto; objid[v->namelen + 5] = policy; { struct nexthop *nexthop; nexthop = (*rib)->nexthop; if (nexthop) { pnt = (u_char *) &nexthop->gate.ipv4; for (i = 0; i < 4; i++) objid[i + v->namelen + 6] = *pnt++; } } return; } static u_char * ipFwTable (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { struct route_node *np; struct rib *rib; static int result; static int resarr[2]; static struct in_addr netmask; struct nexthop *nexthop; if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib); if (!np) return NULL; nexthop = rib->nexthop; if (! nexthop) return NULL; switch (v->magic) { case IPFORWARDDEST: *val_len = 4; return &np->p.u.prefix; break; case IPFORWARDMASK: masklen2ip(np->p.prefixlen, &netmask); *val_len = 4; return (u_char *)&netmask; break; case IPFORWARDPOLICY: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDNEXTHOP: *val_len = 4; return (u_char *)&nexthop->gate.ipv4; break; case IPFORWARDIFINDEX: *val_len = sizeof(int); return (u_char *)&nexthop->ifindex; break; case IPFORWARDTYPE: if (nexthop->type == NEXTHOP_TYPE_IFINDEX || nexthop->type == NEXTHOP_TYPE_IFNAME) result = 3; else result = 4; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDPROTO: result = proto_trans(rib->type); *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDAGE: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDINFO: resarr[0] = 0; resarr[1] = 0; *val_len = 2 * sizeof(int); return (u_char *)resarr; break; case IPFORWARDNEXTHOPAS: result = -1; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDMETRIC1: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDMETRIC2: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDMETRIC3: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDMETRIC4: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; case IPFORWARDMETRIC5: result = 0; *val_len = sizeof(int); return (u_char *)&result; break; default: return NULL; break; } return NULL; } static u_char * ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; switch (v->magic) { case IPCIDRROUTEDEST: break; default: return NULL; break; } return NULL; } void zebra_snmp_init () { smux_init (zebrad.master); REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); } #endif /* HAVE_SNMP */ quagga-0.99.24.1/zebra/rtadv.c0000644000175000017500000014401212476520570012625 00000000000000/* Router advertisement * Copyright (C) 2005 6WIND * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "sockopt.h" #include "thread.h" #include "if.h" #include "log.h" #include "prefix.h" #include "linklist.h" #include "command.h" #include "privs.h" #include "zebra/interface.h" #include "zebra/rtadv.h" #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/zserv.h" extern struct zebra_privs_t zserv_privs; #if defined (HAVE_IPV6) && defined (RTADV) #ifdef OPEN_BSD #include #endif /* If RFC2133 definition is used. */ #ifndef IPV6_JOIN_GROUP #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP #endif #ifndef IPV6_LEAVE_GROUP #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP #endif #define ALLNODE "ff02::1" #define ALLROUTER "ff02::2" extern struct zebra_t zebrad; enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER, RTADV_TIMER_MSEC, RTADV_READ}; static void rtadv_event (enum rtadv_event, int); static int if_join_all_router (int, struct interface *); static int if_leave_all_router (int, struct interface *); /* Structure which hold status of router advertisement. */ struct rtadv { int sock; int adv_if_count; int adv_msec_if_count; struct thread *ra_read; struct thread *ra_timer; }; struct rtadv *rtadv = NULL; static struct rtadv * rtadv_new (void) { return XCALLOC (MTYPE_TMP, sizeof (struct rtadv)); } static int rtadv_recv_packet (int sock, u_char *buf, int buflen, struct sockaddr_in6 *from, unsigned int *ifindex, int *hoplimit) { int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_addr dst; char adata[1024]; /* Fill in message and iovec. */ msg.msg_name = (void *) from; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = sizeof adata; iov.iov_base = buf; iov.iov_len = buflen; /* If recvmsg fail return minus value. */ ret = recvmsg (sock, &msg, 0); if (ret < 0) return ret; for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { /* I want interface index which this packet comes from. */ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO) { struct in6_pktinfo *ptr; ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); *ifindex = ptr->ipi6_ifindex; memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr)); } /* Incoming packet's hop limit. */ if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) { int *hoptr = (int *) CMSG_DATA (cmsgptr); *hoplimit = *hoptr; } } return ret; } #define RTADV_MSG_SIZE 4096 /* Send router advertisement packet. */ static void rtadv_send_packet (int sock, struct interface *ifp) { struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; #ifdef HAVE_STRUCT_SOCKADDR_DL struct sockaddr_dl *sdl; #endif /* HAVE_STRUCT_SOCKADDR_DL */ static void *adata = NULL; unsigned char buf[RTADV_MSG_SIZE]; struct nd_router_advert *rtadv; int ret; int len = 0; struct zebra_if *zif; struct rtadv_prefix *rprefix; u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; struct listnode *node; u_int16_t pkt_RouterLifetime; /* * Allocate control message bufffer. This is dynamic because * CMSG_SPACE is not guaranteed not to call a function. Note that * the size will be different on different architectures due to * differing alignment rules. */ if (adata == NULL) { /* XXX Free on shutdown. */ adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo))); if (adata == NULL) zlog_err("rtadv_send_packet: can't malloc control data\n"); } /* Logging of packet. */ if (IS_ZEBRA_DEBUG_PACKET) zlog_debug ("Router advertisement send to %s", ifp->name); /* Fill in sockaddr_in6. */ memset (&addr, 0, sizeof (struct sockaddr_in6)); addr.sin6_family = AF_INET6; #ifdef SIN6_LEN addr.sin6_len = sizeof (struct sockaddr_in6); #endif /* SIN6_LEN */ addr.sin6_port = htons (IPPROTO_ICMPV6); IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr); /* Fetch interface information. */ zif = ifp->info; /* Make router advertisement message. */ rtadv = (struct nd_router_advert *) buf; rtadv->nd_ra_type = ND_ROUTER_ADVERT; rtadv->nd_ra_code = 0; rtadv->nd_ra_cksum = 0; rtadv->nd_ra_curhoplimit = 64; /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */ rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference; rtadv->nd_ra_flags_reserved <<= 3; if (zif->rtadv.AdvManagedFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; if (zif->rtadv.AdvOtherConfigFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; if (zif->rtadv.AdvHomeAgentFlag) rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; /* Note that according to Neighbor Discovery (RFC 4861 [18]), * AdvDefaultLifetime is by default based on the value of * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime * field of Router Advertisements. Given that this field is expressed * in seconds, a small MaxRtrAdvInterval value can result in a zero * value for this field. To prevent this, routers SHOULD keep * AdvDefaultLifetime in at least one second, even if the use of * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */ pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ? zif->rtadv.AdvDefaultLifetime : MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval); rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime); rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime); rtadv->nd_ra_retransmit = htonl (0); len = sizeof (struct nd_router_advert); /* If both the Home Agent Preference and Home Agent Lifetime are set to * their default values specified above, this option SHOULD NOT be * included in the Router Advertisement messages sent by this home * agent. -- RFC6275, 7.4 */ if ( zif->rtadv.AdvHomeAgentFlag && (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1) ) { struct nd_opt_homeagent_info *ndopt_hai = (struct nd_opt_homeagent_info *)(buf + len); ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION; ndopt_hai->nd_opt_hai_len = 1; ndopt_hai->nd_opt_hai_reserved = 0; ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference); /* 16-bit unsigned integer. The lifetime associated with the home * agent in units of seconds. The default value is the same as the * Router Lifetime, as specified in the main body of the Router * Advertisement. The maximum value corresponds to 18.2 hours. A * value of 0 MUST NOT be used. -- RFC6275, 7.5 */ ndopt_hai->nd_opt_hai_lifetime = htons ( zif->rtadv.HomeAgentLifetime != -1 ? zif->rtadv.HomeAgentLifetime : MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/ ); len += sizeof(struct nd_opt_homeagent_info); } if (zif->rtadv.AdvIntervalOption) { struct nd_opt_adv_interval *ndopt_adv = (struct nd_opt_adv_interval *)(buf + len); ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL; ndopt_adv->nd_opt_ai_len = 1; ndopt_adv->nd_opt_ai_reserved = 0; ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval); len += sizeof(struct nd_opt_adv_interval); } /* Fill in prefix. */ for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { struct nd_opt_prefix_info *pinfo; pinfo = (struct nd_opt_prefix_info *) (buf + len); pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; pinfo->nd_opt_pi_len = 4; pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen; pinfo->nd_opt_pi_flags_reserved = 0; if (rprefix->AdvOnLinkFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK; if (rprefix->AdvAutonomousFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; if (rprefix->AdvRouterAddressFlag) pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR; pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime); pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime); pinfo->nd_opt_pi_reserved2 = 0; IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix); #ifdef DEBUG { u_char buf[INET6_ADDRSTRLEN]; zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix, buf, INET6_ADDRSTRLEN)); } #endif /* DEBUG */ len += sizeof (struct nd_opt_prefix_info); } /* Hardware address. */ #ifdef HAVE_STRUCT_SOCKADDR_DL sdl = &ifp->sdl; if (sdl != NULL && sdl->sdl_alen != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; /* Option length should be rounded up to next octet if the link address does not end on an octet boundary. */ buf[len++] = (sdl->sdl_alen + 9) >> 3; memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen); len += sdl->sdl_alen; /* Pad option to end on an octet boundary. */ memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7); len += -(sdl->sdl_alen + 2) & 0x7; } #else if (ifp->hw_addr_len != 0) { buf[len++] = ND_OPT_SOURCE_LINKADDR; /* Option length should be rounded up to next octet if the link address does not end on an octet boundary. */ buf[len++] = (ifp->hw_addr_len + 9) >> 3; memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len); len += ifp->hw_addr_len; /* Pad option to end on an octet boundary. */ memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7); len += -(ifp->hw_addr_len + 2) & 0x7; } #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* MTU */ if (zif->rtadv.AdvLinkMTU) { struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len); opt->nd_opt_mtu_type = ND_OPT_MTU; opt->nd_opt_mtu_len = 1; opt->nd_opt_mtu_reserved = 0; opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU); len += sizeof (struct nd_opt_mtu); } msg.msg_name = (void *) &addr; msg.msg_namelen = sizeof (struct sockaddr_in6); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = (void *) adata; msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); msg.msg_flags = 0; iov.iov_base = buf; iov.iov_len = len; cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsgptr->cmsg_level = IPPROTO_IPV6; cmsgptr->cmsg_type = IPV6_PKTINFO; pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr); memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr)); pkt->ipi6_ifindex = ifp->ifindex; ret = sendmsg (sock, &msg, 0); if (ret < 0) { zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n", errno, safe_strerror(errno)); } } static int rtadv_timer (struct thread *thread) { struct listnode *node, *nnode; struct interface *ifp; struct zebra_if *zif; int period; rtadv->ra_timer = NULL; if (rtadv->adv_msec_if_count == 0) { period = 1000; /* 1 s */ rtadv_event (RTADV_TIMER, 1 /* 1 s */); } else { period = 10; /* 10 ms */ rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */); } for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp)) { if (if_is_loopback (ifp) || ! if_is_operative (ifp)) continue; zif = ifp->info; if (zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvIntervalTimer -= period; if (zif->rtadv.AdvIntervalTimer <= 0) { /* FIXME: using MaxRtrAdvInterval each time isn't what section 6.2.4 of RFC4861 tells to do. */ zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; rtadv_send_packet (rtadv->sock, ifp); } } } return 0; } static void rtadv_process_solicit (struct interface *ifp) { zlog_info ("Router solicitation received on %s", ifp->name); rtadv_send_packet (rtadv->sock, ifp); } static void rtadv_process_advert (void) { zlog_info ("Router advertisement received"); } static void rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit) { struct icmp6_hdr *icmph; struct interface *ifp; struct zebra_if *zif; /* Interface search. */ ifp = if_lookup_by_index (ifindex); if (ifp == NULL) { zlog_warn ("Unknown interface index: %d", ifindex); return; } if (if_is_loopback (ifp)) return; /* Check interface configuration. */ zif = ifp->info; if (! zif->rtadv.AdvSendAdvertisements) return; /* ICMP message length check. */ if (len < sizeof (struct icmp6_hdr)) { zlog_warn ("Invalid ICMPV6 packet length: %d", len); return; } icmph = (struct icmp6_hdr *) buf; /* ICMP message type check. */ if (icmph->icmp6_type != ND_ROUTER_SOLICIT && icmph->icmp6_type != ND_ROUTER_ADVERT) { zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type); return; } /* Hoplimit check. */ if (hoplimit >= 0 && hoplimit != 255) { zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet", hoplimit); return; } /* Check ICMP message type. */ if (icmph->icmp6_type == ND_ROUTER_SOLICIT) rtadv_process_solicit (ifp); else if (icmph->icmp6_type == ND_ROUTER_ADVERT) rtadv_process_advert (); return; } static int rtadv_read (struct thread *thread) { int sock; int len; u_char buf[RTADV_MSG_SIZE]; struct sockaddr_in6 from; unsigned int ifindex = 0; int hoplimit = -1; sock = THREAD_FD (thread); rtadv->ra_read = NULL; /* Register myself. */ rtadv_event (RTADV_READ, sock); len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); if (len < 0) { zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno)); return len; } rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit); return 0; } static int rtadv_make_socket (void) { int sock; int ret; struct icmp6_filter filter; if ( zserv_privs.change (ZPRIVS_RAISE) ) zlog_err ("rtadv_make_socket: could not raise privs, %s", safe_strerror (errno) ); sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); if ( zserv_privs.change (ZPRIVS_LOWER) ) zlog_err ("rtadv_make_socket: could not lower privs, %s", safe_strerror (errno) ); /* When we can't make ICMPV6 socket simply back. Router advertisement feature will not be supported. */ if (sock < 0) return -1; ret = setsockopt_ipv6_pktinfo (sock, 1); if (ret < 0) return ret; ret = setsockopt_ipv6_multicast_loop (sock, 0); if (ret < 0) return ret; ret = setsockopt_ipv6_unicast_hops (sock, 255); if (ret < 0) return ret; ret = setsockopt_ipv6_multicast_hops (sock, 255); if (ret < 0) return ret; ret = setsockopt_ipv6_hoplimit (sock, 1); if (ret < 0) return ret; ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter); ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter); ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof (struct icmp6_filter)); if (ret < 0) { zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno)); return ret; } return sock; } static struct rtadv_prefix * rtadv_prefix_new (void) { return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix)); } static void rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix) { XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix); } static struct rtadv_prefix * rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p) { struct listnode *node; struct rtadv_prefix *rprefix; for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix)) if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p)) return rprefix; return NULL; } static struct rtadv_prefix * rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p) { struct rtadv_prefix *rprefix; rprefix = rtadv_prefix_lookup (rplist, p); if (rprefix) return rprefix; rprefix = rtadv_prefix_new (); memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6)); listnode_add (rplist, rprefix); return rprefix; } static void rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp) { struct rtadv_prefix *rprefix; rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix); /* Set parameters. */ rprefix->AdvValidLifetime = rp->AdvValidLifetime; rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime; rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag; rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag; rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag; } static int rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp) { struct rtadv_prefix *rprefix; rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix); if (rprefix != NULL) { listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix); rtadv_prefix_free (rprefix); return 1; } else return 0; } DEFUN (ipv6_nd_suppress_ra, ipv6_nd_suppress_ra_cmd, "ipv6 nd suppress-ra", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") { struct interface *ifp; struct zebra_if *zif; ifp = vty->index; zif = ifp->info; if (if_is_loopback (ifp)) { vty_out (vty, "Invalid interface%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 0; zif->rtadv.AdvIntervalTimer = 0; rtadv->adv_if_count--; if_leave_all_router (rtadv->sock, ifp); if (rtadv->adv_if_count == 0) rtadv_event (RTADV_STOP, 0); } return CMD_SUCCESS; } DEFUN (no_ipv6_nd_suppress_ra, no_ipv6_nd_suppress_ra_cmd, "no ipv6 nd suppress-ra", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Suppress Router Advertisement\n") { struct interface *ifp; struct zebra_if *zif; ifp = vty->index; zif = ifp->info; if (if_is_loopback (ifp)) { vty_out (vty, "Invalid interface%s", VTY_NEWLINE); return CMD_WARNING; } if (! zif->rtadv.AdvSendAdvertisements) { zif->rtadv.AdvSendAdvertisements = 1; zif->rtadv.AdvIntervalTimer = 0; rtadv->adv_if_count++; if_join_all_router (rtadv->sock, ifp); if (rtadv->adv_if_count == 1) rtadv_event (RTADV_START, rtadv->sock); } return CMD_SUCCESS; } DEFUN (ipv6_nd_ra_interval_msec, ipv6_nd_ra_interval_msec_cmd, "ipv6 nd ra-interval msec <70-1800000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") { unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) { vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.MaxRtrAdvInterval % 1000) rtadv->adv_msec_if_count--; if (interval % 1000) rtadv->adv_msec_if_count++; zif->rtadv.MaxRtrAdvInterval = interval; zif->rtadv.MinRtrAdvInterval = 0.33 * interval; zif->rtadv.AdvIntervalTimer = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_ra_interval, ipv6_nd_ra_interval_cmd, "ipv6 nd ra-interval <1-1800>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in seconds\n") { unsigned interval; struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800); if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) { vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE); return CMD_WARNING; } if (zif->rtadv.MaxRtrAdvInterval % 1000) rtadv->adv_msec_if_count--; /* convert to milliseconds */ interval = interval * 1000; zif->rtadv.MaxRtrAdvInterval = interval; zif->rtadv.MinRtrAdvInterval = 0.33 * interval; zif->rtadv.AdvIntervalTimer = 0; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_ra_interval, no_ipv6_nd_ra_interval_cmd, "no ipv6 nd ra-interval", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; if (zif->rtadv.MaxRtrAdvInterval % 1000) rtadv->adv_msec_if_count--; zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL; zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL; zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_ra_interval, no_ipv6_nd_ra_interval_val_cmd, "no ipv6 nd ra-interval <1-1800>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n") ALIAS (no_ipv6_nd_ra_interval, no_ipv6_nd_ra_interval_msec_val_cmd, "no ipv6 nd ra-interval msec <1-1800000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router Advertisement interval\n" "Router Advertisement interval in milliseconds\n") DEFUN (ipv6_nd_ra_lifetime, ipv6_nd_ra_lifetime_cmd, "ipv6 nd ra-lifetime <0-9000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") { int lifetime; struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000); /* The value to be placed in the Router Lifetime field * of Router Advertisements sent from the interface, * in seconds. MUST be either zero or between * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */ if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) { vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE); return CMD_WARNING; } zif->rtadv.AdvDefaultLifetime = lifetime; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_ra_lifetime, no_ipv6_nd_ra_lifetime_cmd, "no ipv6 nd ra-lifetime", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvDefaultLifetime = -1; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_ra_lifetime, no_ipv6_nd_ra_lifetime_val_cmd, "no ipv6 nd ra-lifetime <0-9000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Router lifetime\n" "Router lifetime in seconds (0 stands for a non-default gw)\n") DEFUN (ipv6_nd_reachable_time, ipv6_nd_reachable_time_cmd, "ipv6 nd reachable-time <1-3600000>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_reachable_time, no_ipv6_nd_reachable_time_cmd, "no ipv6 nd reachable-time", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvReachableTime = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_reachable_time, no_ipv6_nd_reachable_time_val_cmd, "no ipv6 nd reachable-time <1-3600000>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Reachable time\n" "Reachable time in milliseconds\n") DEFUN (ipv6_nd_homeagent_preference, ipv6_nd_homeagent_preference_cmd, "ipv6 nd home-agent-preference <0-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_preference, no_ipv6_nd_homeagent_preference_cmd, "no ipv6 nd home-agent-preference", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.HomeAgentPreference = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_homeagent_preference, no_ipv6_nd_homeagent_preference_val_cmd, "no ipv6 nd home-agent-preference <0-65535>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent preference\n" "preference value (default is 0, least preferred)\n") DEFUN (ipv6_nd_homeagent_lifetime, ipv6_nd_homeagent_lifetime_cmd, "ipv6 nd home-agent-lifetime <0-65520>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_lifetime, no_ipv6_nd_homeagent_lifetime_cmd, "no ipv6 nd home-agent-lifetime", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.HomeAgentLifetime = -1; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_homeagent_lifetime, no_ipv6_nd_homeagent_lifetime_val_cmd, "no ipv6 nd home-agent-lifetime <0-65520>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent lifetime\n" "Home Agent lifetime in seconds (0 to track ra-lifetime)\n") DEFUN (ipv6_nd_managed_config_flag, ipv6_nd_managed_config_flag_cmd, "ipv6 nd managed-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvManagedFlag = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_managed_config_flag, no_ipv6_nd_managed_config_flag_cmd, "no ipv6 nd managed-config-flag", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Managed address configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvManagedFlag = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_homeagent_config_flag, ipv6_nd_homeagent_config_flag_cmd, "ipv6 nd home-agent-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvHomeAgentFlag = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_homeagent_config_flag, no_ipv6_nd_homeagent_config_flag_cmd, "no ipv6 nd home-agent-config-flag", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Home Agent configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvHomeAgentFlag = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_adv_interval_config_option, ipv6_nd_adv_interval_config_option_cmd, "ipv6 nd adv-interval-option", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvIntervalOption = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_adv_interval_config_option, no_ipv6_nd_adv_interval_config_option_cmd, "no ipv6 nd adv-interval-option", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertisement Interval Option\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvIntervalOption = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_other_config_flag, ipv6_nd_other_config_flag_cmd, "ipv6 nd other-config-flag", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvOtherConfigFlag = 1; return CMD_SUCCESS; } DEFUN (no_ipv6_nd_other_config_flag, no_ipv6_nd_other_config_flag_cmd, "no ipv6 nd other-config-flag", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Other statefull configuration flag\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.AdvOtherConfigFlag = 0; return CMD_SUCCESS; } DEFUN (ipv6_nd_prefix, ipv6_nd_prefix_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n" "Set Router Address flag\n") { int i; int ret; int cursor = 1; struct interface *ifp; struct zebra_if *zebra_if; struct rtadv_prefix rp; ifp = (struct interface *) vty->index; zebra_if = ifp->info; ret = str2prefix_ipv6 (argv[0], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ rp.AdvOnLinkFlag = 1; rp.AdvAutonomousFlag = 1; rp.AdvRouterAddressFlag = 0; rp.AdvValidLifetime = RTADV_VALID_LIFETIME; rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; if (argc > 1) { if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0) { if ( strncmp (argv[1], "i", 1) == 0) rp.AdvValidLifetime = UINT32_MAX; else rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1], (char **)NULL, 10); if ( strncmp (argv[2], "i", 1) == 0) rp.AdvPreferredLifetime = UINT32_MAX; else rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2], (char **)NULL, 10); if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) { vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE); return CMD_WARNING; } cursor = cursor + 2; } if (argc > cursor) { for (i = cursor; i < argc; i++) { if (strncmp (argv[i], "of", 2) == 0) rp.AdvOnLinkFlag = 0; if (strncmp (argv[i], "no", 2) == 0) rp.AdvAutonomousFlag = 0; if (strncmp (argv[i], "ro", 2) == 0) rp.AdvRouterAddressFlag = 1; } } } rtadv_prefix_set (zebra_if, &rp); return CMD_SUCCESS; } ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_nortaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rev_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rev_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_noauto_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for autoconfiguration") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_offlink_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite) (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_val_cmd, "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) " "(<0-4294967295>|infinite)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Valid lifetime in seconds\n" "Infinite valid lifetime\n" "Preferred lifetime in seconds\n" "Infinite preferred lifetime\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_cmd, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_rev_cmd, "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_noauto_cmd, "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for autoconfiguration\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_offlink_cmd, "ipv6 nd prefix X:X::X:X/M (off-link|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Do not use prefix for onlink determination\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_noval_rtaddr_cmd, "ipv6 nd prefix X:X::X:X/M (router-address|)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n" "Set Router Address flag\n") ALIAS (ipv6_nd_prefix, ipv6_nd_prefix_prefix_cmd, "ipv6 nd prefix X:X::X:X/M", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") DEFUN (no_ipv6_nd_prefix, no_ipv6_nd_prefix_cmd, "no ipv6 nd prefix IPV6PREFIX", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Prefix information\n" "IPv6 prefix\n") { int ret; struct interface *ifp; struct zebra_if *zebra_if; struct rtadv_prefix rp; ifp = (struct interface *) vty->index; zebra_if = ifp->info; ret = str2prefix_ipv6 (argv[0], &rp.prefix); if (!ret) { vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */ ret = rtadv_prefix_reset (zebra_if, &rp); if (!ret) { vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN (ipv6_nd_router_preference, ipv6_nd_router_preference_cmd, "ipv6 nd router-preference (high|medium|low)", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") { struct interface *ifp; struct zebra_if *zif; int i = 0; ifp = (struct interface *) vty->index; zif = ifp->info; while (0 != rtadv_pref_strs[i]) { if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0) { zif->rtadv.DefaultPreference = i; return CMD_SUCCESS; } i++; } return CMD_ERR_NO_MATCH; } DEFUN (no_ipv6_nd_router_preference, no_ipv6_nd_router_preference_cmd, "no ipv6 nd router-preference", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n") { struct interface *ifp; struct zebra_if *zif; ifp = (struct interface *) vty->index; zif = ifp->info; zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */ return CMD_SUCCESS; } ALIAS (no_ipv6_nd_router_preference, no_ipv6_nd_router_preference_val_cmd, "no ipv6 nd router-preference (high|medium|low)", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Default router preference\n" "High default router preference\n" "Low default router preference\n" "Medium default router preference (default)\n") DEFUN (ipv6_nd_mtu, ipv6_nd_mtu_cmd, "ipv6 nd mtu <1-65535>", "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535); return CMD_SUCCESS; } DEFUN (no_ipv6_nd_mtu, no_ipv6_nd_mtu_cmd, "no ipv6 nd mtu", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n") { struct interface *ifp = (struct interface *) vty->index; struct zebra_if *zif = ifp->info; zif->rtadv.AdvLinkMTU = 0; return CMD_SUCCESS; } ALIAS (no_ipv6_nd_mtu, no_ipv6_nd_mtu_val_cmd, "no ipv6 nd mtu <1-65535>", NO_STR "Interface IPv6 config commands\n" "Neighbor discovery\n" "Advertised MTU\n" "MTU in bytes\n") /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) { struct zebra_if *zif; struct listnode *node; struct rtadv_prefix *rprefix; u_char buf[INET6_ADDRSTRLEN]; int interval; if (! rtadv) return; zif = ifp->info; if (! if_is_loopback (ifp)) { if (zif->rtadv.AdvSendAdvertisements) vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE); else vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE); } interval = zif->rtadv.MaxRtrAdvInterval; if (interval % 1000) vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval, VTY_NEWLINE); else if (interval != RTADV_MAX_RTR_ADV_INTERVAL) vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000, VTY_NEWLINE); if (zif->rtadv.AdvIntervalOption) vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE); if (zif->rtadv.AdvDefaultLifetime != -1) vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime, VTY_NEWLINE); if (zif->rtadv.HomeAgentPreference) vty_out (vty, " ipv6 nd home-agent-preference %u%s", zif->rtadv.HomeAgentPreference, VTY_NEWLINE); if (zif->rtadv.HomeAgentLifetime != -1) vty_out (vty, " ipv6 nd home-agent-lifetime %u%s", zif->rtadv.HomeAgentLifetime, VTY_NEWLINE); if (zif->rtadv.AdvHomeAgentFlag) vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE); if (zif->rtadv.AdvReachableTime) vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime, VTY_NEWLINE); if (zif->rtadv.AdvManagedFlag) vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE); if (zif->rtadv.AdvOtherConfigFlag) vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE); if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM) vty_out (vty, " ipv6 nd router-preference %s%s", rtadv_pref_strs[zif->rtadv.DefaultPreference], VTY_NEWLINE); if (zif->rtadv.AdvLinkMTU) vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE); for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix)) { vty_out (vty, " ipv6 nd prefix %s/%d", inet_ntop (AF_INET6, &rprefix->prefix.prefix, (char *) buf, INET6_ADDRSTRLEN), rprefix->prefix.prefixlen); if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) || (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME)) { if (rprefix->AdvValidLifetime == UINT32_MAX) vty_out (vty, " infinite"); else vty_out (vty, " %u", rprefix->AdvValidLifetime); if (rprefix->AdvPreferredLifetime == UINT32_MAX) vty_out (vty, " infinite"); else vty_out (vty, " %u", rprefix->AdvPreferredLifetime); } if (!rprefix->AdvOnLinkFlag) vty_out (vty, " off-link"); if (!rprefix->AdvAutonomousFlag) vty_out (vty, " no-autoconfig"); if (rprefix->AdvRouterAddressFlag) vty_out (vty, " router-address"); vty_out (vty, "%s", VTY_NEWLINE); } } static void rtadv_event (enum rtadv_event event, int val) { switch (event) { case RTADV_START: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer, NULL, 0); break; case RTADV_STOP: if (rtadv->ra_timer) { thread_cancel (rtadv->ra_timer); rtadv->ra_timer = NULL; } if (rtadv->ra_read) { thread_cancel (rtadv->ra_read); rtadv->ra_read = NULL; } break; case RTADV_TIMER: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL, val); break; case RTADV_TIMER_MSEC: if (! rtadv->ra_timer) rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer, NULL, val); break; case RTADV_READ: if (! rtadv->ra_read) rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val); break; default: break; } return; } void rtadv_init (void) { int sock; sock = rtadv_make_socket (); if (sock < 0) return; rtadv = rtadv_new (); rtadv->sock = sock; install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd); install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd); install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd); install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd); } static int if_join_all_router (int sock, struct interface *ifp) { int ret; struct ipv6_mreq mreq; memset (&mreq, 0, sizeof (struct ipv6_mreq)); inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreq, sizeof mreq); if (ret < 0) zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno)); zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name); return 0; } static int if_leave_all_router (int sock, struct interface *ifp) { int ret; struct ipv6_mreq mreq; memset (&mreq, 0, sizeof (struct ipv6_mreq)); inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *) &mreq, sizeof mreq); if (ret < 0) zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno)); zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name); return 0; } #else void rtadv_init (void) { /* Empty.*/; } #endif /* RTADV && HAVE_IPV6 */ quagga-0.99.24.1/zebra/redistribute.c0000644000175000017500000002400512476520570014211 00000000000000/* Redistribution Handler * Copyright (C) 1998 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "vector.h" #include "vty.h" #include "command.h" #include "prefix.h" #include "table.h" #include "stream.h" #include "zclient.h" #include "linklist.h" #include "log.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/router-id.h" /* master zebra server structure */ extern struct zebra_t zebrad; int zebra_check_addr (struct prefix *p) { if (p->family == AF_INET) { u_int32_t addr; addr = p->u.prefix4.s_addr; addr = ntohl (addr); if (IPV4_NET127 (addr) || IN_CLASSD (addr) || IPV4_LINKLOCAL(addr)) return 0; } #ifdef HAVE_IPV6 if (p->family == AF_INET6) { if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6)) return 0; if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) return 0; } #endif /* HAVE_IPV6 */ return 1; } static int is_default (struct prefix *p) { if (p->family == AF_INET) if (p->u.prefix4.s_addr == 0 && p->prefixlen == 0) return 1; #ifdef HAVE_IPV6 #if 0 /* IPv6 default separation is now pending until protocol daemon can handle that. */ if (p->family == AF_INET6) if (IN6_IS_ADDR_UNSPECIFIED (&p->u.prefix6) && p->prefixlen == 0) return 1; #endif /* 0 */ #endif /* HAVE_IPV6 */ return 0; } static void zebra_redistribute_default (struct zserv *client) { struct prefix_ipv4 p; struct route_table *table; struct route_node *rn; struct rib *newrib; #ifdef HAVE_IPV6 struct prefix_ipv6 p6; #endif /* HAVE_IPV6 */ /* Lookup default route. */ memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) { rn = route_node_lookup (table, (struct prefix *)&p); if (rn) { RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); route_unlock_node (rn); } } #ifdef HAVE_IPV6 /* Lookup default route. */ memset (&p6, 0, sizeof (struct prefix_ipv6)); p6.family = AF_INET6; /* Lookup table. */ table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) { rn = route_node_lookup (table, (struct prefix *)&p6); if (rn) { RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->distance != DISTANCE_INFINITY) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); route_unlock_node (rn); } } #endif /* HAVE_IPV6 */ } /* Redistribute routes. */ static void zebra_redistribute (struct zserv *client, int type) { struct rib *newrib; struct route_table *table; struct route_node *rn; table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib); #ifdef HAVE_IPV6 table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) RNODE_FOREACH_RIB (rn, newrib) if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED) && newrib->type == type && newrib->distance != DISTANCE_INFINITY && zebra_check_addr (&rn->p)) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib); #endif /* HAVE_IPV6 */ } void redistribute_add (struct prefix *p, struct rib *rib) { struct listnode *node, *nnode; struct zserv *client; for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { if (is_default (p)) { if (client->redist_default || client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); #endif /* HAVE_IPV6 */ } } else if (client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib); #endif /* HAVE_IPV6 */ } } } void redistribute_delete (struct prefix *p, struct rib *rib) { struct listnode *node, *nnode; struct zserv *client; /* Add DISTANCE_INFINITY check. */ if (rib->distance == DISTANCE_INFINITY) return; for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) { if (is_default (p)) { if (client->redist_default || client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib); #endif /* HAVE_IPV6 */ } } else if (client->redist[rib->type]) { if (p->family == AF_INET) zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib); #ifdef HAVE_IPV6 if (p->family == AF_INET6) zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib); #endif /* HAVE_IPV6 */ } } } void zebra_redistribute_add (int command, struct zserv *client, int length) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; if (! client->redist[type]) { client->redist[type] = 1; zebra_redistribute (client, type); } } void zebra_redistribute_delete (int command, struct zserv *client, int length) { int type; type = stream_getc (client->ibuf); if (type == 0 || type >= ZEBRA_ROUTE_MAX) return; client->redist[type] = 0; } void zebra_redistribute_default_add (int command, struct zserv *client, int length) { client->redist_default = 1; zebra_redistribute_default (client); } void zebra_redistribute_default_delete (int command, struct zserv *client, int length) { client->redist_default = 0;; } /* Interface up information. */ void zebra_interface_up_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp); } /* Interface down information. */ void zebra_interface_down_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp); } /* Interface information update. */ void zebra_interface_add_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADD %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) zsend_interface_add (client, ifp); } void zebra_interface_delete_update (struct interface *ifp) { struct listnode *node, *nnode; struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DELETE %s", ifp->name); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo) zsend_interface_delete (client, ifp); } /* Interface address addition. */ void zebra_interface_address_add_update (struct interface *ifp, struct connected *ifc) { struct listnode *node, *nnode; struct zserv *client; struct prefix *p; if (IS_ZEBRA_DEBUG_EVENT) { char buf[INET6_ADDRSTRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s", inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, ifc->ifp->name); } if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) zlog_warn("WARNING: advertising address to clients that is not yet usable."); router_id_add_address(ifc); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc); } /* Interface address deletion. */ void zebra_interface_address_delete_update (struct interface *ifp, struct connected *ifc) { struct listnode *node, *nnode; struct zserv *client; struct prefix *p; if (IS_ZEBRA_DEBUG_EVENT) { char buf[INET6_ADDRSTRLEN]; p = ifc->address; zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s", inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN), p->prefixlen, ifc->ifp->name); } router_id_del_address(ifc); for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client)) if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL)) zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc); } quagga-0.99.24.1/zebra/zebra_routemap.c0000644000175000017500000004344412476520570014533 00000000000000/* zebra routemap. * Copyright (C) 2006 IBM Corporation * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "memory.h" #include "prefix.h" #include "rib.h" #include "routemap.h" #include "command.h" #include "filter.h" #include "plist.h" #include "zebra/zserv.h" /* Add zebra route map rule */ static int zebra_route_match_add(struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete zebra route map rule. */ static int zebra_route_match_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_match (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Add zebra route map rule. */ static int zebra_route_set_add (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_add_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* Delete zebra route map rule. */ static int zebra_route_set_delete (struct vty *vty, struct route_map_index *index, const char *command, const char *arg) { int ret; ret = route_map_delete_set (index, command, arg); if (ret) { switch (ret) { case RMAP_RULE_MISSING: vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE); return CMD_WARNING; case RMAP_COMPILE_ERROR: vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE); return CMD_WARNING; } } return CMD_SUCCESS; } /* `match interface IFNAME' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_interface (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct nexthop *nexthop; char *ifname = rule; unsigned int ifindex; if (type == RMAP_ZEBRA) { if (strcasecmp(ifname, "any") == 0) return RMAP_MATCH; ifindex = ifname2ifindex(ifname); if (ifindex == 0) return RMAP_NOMATCH; nexthop = object; if (!nexthop) return RMAP_NOMATCH; if (nexthop->ifindex == ifindex) return RMAP_MATCH; } return RMAP_NOMATCH; } /* Route map `match interface' match statement. `arg' is IFNAME value */ static void * route_match_interface_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `match interface' value. */ static void route_match_interface_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for interface matching */ struct route_map_rule_cmd route_match_interface_cmd = { "interface", route_match_interface, route_match_interface_compile, route_match_interface_free }; DEFUN (match_interface, match_interface_cmd, "match interface WORD", MATCH_STR "match first hop interface of route\n" "Interface name\n") { return zebra_route_match_add (vty, vty->index, "interface", argv[0]); } DEFUN (no_match_interface, no_match_interface_cmd, "no match interface", NO_STR MATCH_STR "Match first hop interface of route\n") { if (argc == 0) return zebra_route_match_delete (vty, vty->index, "interface", NULL); return zebra_route_match_delete (vty, vty->index, "interface", argv[0]); } ALIAS (no_match_interface, no_match_interface_val_cmd, "no match interface WORD", NO_STR MATCH_STR "Match first hop interface of route\n" "Interface name\n") DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, "match ip next-hop (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return zebra_route_match_add (vty, vty->index, "ip next-hop", argv[0]); } DEFUN (no_match_ip_next_hop, no_match_ip_next_hop_cmd, "no match ip next-hop", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n") { if (argc == 0) return zebra_route_match_delete (vty, vty->index, "ip next-hop", NULL); return zebra_route_match_delete (vty, vty->index, "ip next-hop", argv[0]); } ALIAS (no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, "match ip next-hop prefix-list WORD", MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return zebra_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]); } DEFUN (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, "no match ip next-hop prefix-list", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL); return zebra_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]); } ALIAS (no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_address, match_ip_address_cmd, "match ip address (<1-199>|<1300-2699>|WORD)", MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") { return zebra_route_match_add (vty, vty->index, "ip address", argv[0]); } DEFUN (no_match_ip_address, no_match_ip_address_cmd, "no match ip address", NO_STR MATCH_STR IP_STR "Match address of route\n") { if (argc == 0) return zebra_route_match_delete (vty, vty->index, "ip address", NULL); return zebra_route_match_delete (vty, vty->index, "ip address", argv[0]); } ALIAS (no_match_ip_address, no_match_ip_address_val_cmd, "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, "match ip address prefix-list WORD", MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") { return zebra_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]); } DEFUN (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, "no match ip address prefix-list", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n") { if (argc == 0) return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", NULL); return zebra_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]); } ALIAS (no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") /* set functions */ DEFUN (set_src, set_src_cmd, "set src A.B.C.D", SET_STR "src address for route\n" "src address\n") { struct in_addr src; struct interface *pif; if (inet_pton(AF_INET, argv[0], &src) <= 0) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } pif = if_lookup_exact_address (src); if (!pif) { vty_out (vty, "%% not a local address%s", VTY_NEWLINE); return CMD_WARNING; } return zebra_route_set_add (vty, vty->index, "src", argv[0]); } DEFUN (no_set_src, no_set_src_cmd, "no set src", NO_STR SET_STR "Source address for route\n") { if (argc == 0) return zebra_route_set_delete (vty, vty->index, "src", NULL); return zebra_route_set_delete (vty, vty->index, "src", argv[0]); } ALIAS (no_set_src, no_set_src_val_cmd, "no set src (A.B.C.D)", NO_STR SET_STR "src address for route\n" "src address\n") /*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ /* `match ip next-hop IP_ACCESS_LIST' */ /* Match function return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_next_hop (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; struct nexthop *nexthop; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { nexthop = object; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: return RMAP_NOMATCH; } alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip next-hop' match statement. `arg' should be access-list name. */ static void * route_match_ip_next_hop_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `. */ static void route_match_ip_next_hop_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip next-hop matching. */ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = { "ip next-hop", route_match_ip_next_hop, route_match_ip_next_hop_compile, route_match_ip_next_hop_free }; /* `match ip next-hop prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; struct nexthop *nexthop; struct prefix_ipv4 p; if (type == RMAP_ZEBRA) { nexthop = object; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: case NEXTHOP_TYPE_IFNAME: /* Interface routes can't match ip next-hop */ return RMAP_NOMATCH; case NEXTHOP_TYPE_IPV4_IFINDEX: case NEXTHOP_TYPE_IPV4_IFNAME: case NEXTHOP_TYPE_IPV4: p.family = AF_INET; p.prefix = nexthop->gate.ipv4; p.prefixlen = IPV4_MAX_BITLEN; break; default: return RMAP_NOMATCH; } plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, &p) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_next_hop_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_next_hop_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = { "ip next-hop prefix-list", route_match_ip_next_hop_prefix_list, route_match_ip_next_hop_prefix_list_compile, route_match_ip_next_hop_prefix_list_free }; /* `match ip address IP_ACCESS_LIST' */ /* Match function should return 1 if match is success else return zero. */ static route_map_result_t route_match_ip_address (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct access_list *alist; if (type == RMAP_ZEBRA) { alist = access_list_lookup (AFI_IP, (char *) rule); if (alist == NULL) return RMAP_NOMATCH; return (access_list_apply (alist, prefix) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } /* Route map `ip address' match statement. `arg' should be access-list name. */ static void * route_match_ip_address_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } /* Free route map's compiled `ip address' value. */ static void route_match_ip_address_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Route map commands for ip address matching. */ static struct route_map_rule_cmd route_match_ip_address_cmd = { "ip address", route_match_ip_address, route_match_ip_address_compile, route_match_ip_address_free }; /* `match ip address prefix-list PREFIX_LIST' */ static route_map_result_t route_match_ip_address_prefix_list (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { struct prefix_list *plist; if (type == RMAP_ZEBRA) { plist = prefix_list_lookup (AFI_IP, (char *) rule); if (plist == NULL) return RMAP_NOMATCH; return (prefix_list_apply (plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH : RMAP_MATCH); } return RMAP_NOMATCH; } static void * route_match_ip_address_prefix_list_compile (const char *arg) { return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg); } static void route_match_ip_address_prefix_list_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = { "ip address prefix-list", route_match_ip_address_prefix_list, route_match_ip_address_prefix_list_compile, route_match_ip_address_prefix_list_free }; /* `set src A.B.C.D' */ /* Set src. */ static route_map_result_t route_set_src (void *rule, struct prefix *prefix, route_map_object_t type, void *object) { if (type == RMAP_ZEBRA) { struct nexthop *nexthop; nexthop = object; nexthop->src = *(union g_addr *)rule; } return RMAP_OKAY; } /* set src compilation. */ static void * route_set_src_compile (const char *arg) { union g_addr src, *psrc; if (inet_pton(AF_INET, arg, &src.ipv4) != 1 #ifdef HAVE_IPV6 && inet_pton(AF_INET6, arg, &src.ipv6) != 1 #endif /* HAVE_IPV6 */ ) return NULL; psrc = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (union g_addr)); *psrc = src; return psrc; } /* Free route map's compiled `set src' value. */ static void route_set_src_free (void *rule) { XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); } /* Set src rule structure. */ static struct route_map_rule_cmd route_set_src_cmd = { "src", route_set_src, route_set_src_compile, route_set_src_free, }; void zebra_route_map_init () { route_map_init (); route_map_init_vty (); route_map_install_match (&route_match_interface_cmd); route_map_install_match (&route_match_ip_next_hop_cmd); route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd); route_map_install_match (&route_match_ip_address_cmd); route_map_install_match (&route_match_ip_address_prefix_list_cmd); /* */ route_map_install_set (&route_set_src_cmd); /* */ install_element (RMAP_NODE, &match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_cmd); install_element (RMAP_NODE, &no_match_interface_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd); install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd); install_element (RMAP_NODE, &match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_cmd); install_element (RMAP_NODE, &no_match_ip_address_val_cmd); install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd); install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); /* */ install_element (RMAP_NODE, &set_src_cmd); install_element (RMAP_NODE, &no_set_src_cmd); } quagga-0.99.24.1/zebra/main.c0000644000175000017500000002322612476520570012434 00000000000000/* zebra daemon main routine. * Copyright (C) 1997, 98 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "getopt.h" #include "command.h" #include "thread.h" #include "filter.h" #include "memory.h" #include "prefix.h" #include "log.h" #include "plist.h" #include "privs.h" #include "sigevent.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/debug.h" #include "zebra/router-id.h" #include "zebra/irdp.h" #include "zebra/rtadv.h" #include "zebra/zebra_fpm.h" /* Zebra instance */ struct zebra_t zebrad = { .rtm_table_default = 0, }; /* process id. */ pid_t pid; /* Pacify zclient.o in libzebra, which expects this variable. */ struct thread_master *master; /* Route retain mode flag. */ int retain_mode = 0; /* Don't delete kernel route. */ int keep_kernel_mode = 0; #ifdef HAVE_NETLINK /* Receive buffer size for netlink socket */ u_int32_t nl_rcvbufsize = 0; #endif /* HAVE_NETLINK */ /* Command line options. */ struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, { "keep_kernel", no_argument, NULL, 'k'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, { "retain", no_argument, NULL, 'r'}, { "dryrun", no_argument, NULL, 'C'}, #ifdef HAVE_NETLINK { "nl-bufsize", required_argument, NULL, 's'}, #endif /* HAVE_NETLINK */ { "user", required_argument, NULL, 'u'}, { "group", required_argument, NULL, 'g'}, { "version", no_argument, NULL, 'v'}, { 0 } }; zebra_capabilities_t _caps_p [] = { ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN, ZCAP_NET_RAW, }; /* zebra privileges to run with */ struct zebra_privs_t zserv_privs = { #if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) .user = QUAGGA_USER, .group = QUAGGA_GROUP, #endif #ifdef VTY_GROUP .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), .cap_num_i = 0 }; /* Default configuration file path. */ char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; /* Process ID saved for use by init system */ const char *pid_file = PATH_ZEBRA_PID; /* Help information display. */ static void usage (char *progname, int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", progname); else { printf ("Usage : %s [OPTION...]\n\n"\ "Daemon which manages kernel routing table management and "\ "redistribution between different routing protocols.\n\n"\ "-b, --batch Runs in batch mode\n"\ "-d, --daemon Runs in daemon mode\n"\ "-f, --config_file Set configuration file name\n"\ "-i, --pid_file Set process identifier file name\n"\ "-z, --socket Set path of zebra socket\n"\ "-k, --keep_kernel Don't delete old routes which installed by "\ "zebra.\n"\ "-C, --dryrun Check configuration for validity and exit\n"\ "-A, --vty_addr Set vty's bind address\n"\ "-P, --vty_port Set vty's port number\n"\ "-r, --retain When program terminates, retain added route "\ "by zebra.\n"\ "-u, --user User to run as\n"\ "-g, --group Group to run as\n", progname); #ifdef HAVE_NETLINK printf ("-s, --nl-bufsize Set netlink receive buffer size\n"); #endif /* HAVE_NETLINK */ printf ("-v, --version Print program version\n"\ "-h, --help Display this help and exit\n"\ "\n"\ "Report bugs to %s\n", ZEBRA_BUG_ADDRESS); } exit (status); } /* SIGHUP handler. */ static void sighup (void) { zlog_info ("SIGHUP received"); /* Reload of config file. */ ; } /* SIGINT handler. */ static void sigint (void) { zlog_notice ("Terminating on signal"); if (!retain_mode) rib_close (); #ifdef HAVE_IRDP irdp_finish(); #endif exit (0); } /* SIGUSR1 handler. */ static void sigusr1 (void) { zlog_rotate (NULL); } struct quagga_signal_t zebra_signals[] = { { .signal = SIGHUP, .handler = &sighup, }, { .signal = SIGUSR1, .handler = &sigusr1, }, { .signal = SIGINT, .handler = &sigint, }, { .signal = SIGTERM, .handler = &sigint, }, }; /* Main startup routine. */ int main (int argc, char **argv) { char *p; char *vty_addr = NULL; int vty_port = ZEBRA_VTY_PORT; int dryrun = 0; int batch_mode = 0; int daemon_mode = 0; char *config_file = NULL; char *progname; struct thread thread; char *zserv_path = NULL; /* Set umask before anything for security */ umask (0027); /* preserve my name */ progname = ((p = strrchr (argv[0], '/')) ? ++p : argv[0]); zlog_default = openzlog (progname, ZLOG_ZEBRA, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); while (1) { int opt; #ifdef HAVE_NETLINK opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vs:C", longopts, 0); #else opt = getopt_long (argc, argv, "bdkf:i:z:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ if (opt == EOF) break; switch (opt) { case 0: break; case 'b': batch_mode = 1; case 'd': daemon_mode = 1; break; case 'k': keep_kernel_mode = 1; break; case 'C': dryrun = 1; break; case 'f': config_file = optarg; break; case 'A': vty_addr = optarg; break; case 'i': pid_file = optarg; break; case 'z': zserv_path = optarg; break; case 'P': /* Deal with atoi() returning 0 on failure, and zebra not listening on zebra port... */ if (strcmp(optarg, "0") == 0) { vty_port = 0; break; } vty_port = atoi (optarg); if (vty_port <= 0 || vty_port > 0xffff) vty_port = ZEBRA_VTY_PORT; break; case 'r': retain_mode = 1; break; #ifdef HAVE_NETLINK case 's': nl_rcvbufsize = atoi (optarg); break; #endif /* HAVE_NETLINK */ case 'u': zserv_privs.user = optarg; break; case 'g': zserv_privs.group = optarg; break; case 'v': print_version (progname); exit (0); break; case 'h': usage (progname, 0); break; default: usage (progname, 1); break; } } /* Make master thread emulator. */ zebrad.master = thread_master_create (); /* privs initialise */ zprivs_init (&zserv_privs); /* Vty related initialize. */ signal_init (zebrad.master, array_size(zebra_signals), zebra_signals); cmd_init (1); vty_init (zebrad.master); memory_init (); /* Zebra related initialize. */ zebra_init (); rib_init (); zebra_if_init (); zebra_debug_init (); router_id_init(); zebra_vty_init (); access_list_init (); prefix_list_init (); #ifdef RTADV rtadv_init (); #endif #ifdef HAVE_IRDP irdp_init(); #endif /* For debug purpose. */ /* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */ /* Make kernel routing socket. */ kernel_init (); interface_list (); route_read (); #ifdef HAVE_SNMP zebra_snmp_init (); #endif /* HAVE_SNMP */ #ifdef HAVE_FPM zfpm_init (zebrad.master, 1, 0); #else zfpm_init (zebrad.master, 0, 0); #endif /* Process the configuration file. Among other configuration * directives we can meet those installing static routes. Such * requests will not be executed immediately, but queued in * zebra->ribq structure until we enter the main execution loop. * The notifications from kernel will show originating PID equal * to that after daemon() completes (if ever called). */ vty_read_config (config_file, config_default); /* Don't start execution if we are in dry-run mode */ if (dryrun) return(0); /* Clean up rib. */ rib_weed_tables (); /* Exit when zebra is working in batch mode. */ if (batch_mode) exit (0); /* Daemonize. */ if (daemon_mode && daemon (0, 0) < 0) { zlog_err("Zebra daemon failed: %s", strerror(errno)); exit (1); } /* Output pid of zebra. */ pid_output (pid_file); /* After we have successfully acquired the pidfile, we can be sure * about being the only copy of zebra process, which is submitting * changes to the FIB. * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, * we have to have route_read() called before. */ if (! keep_kernel_mode) rib_sweep_route (); /* Needed for BSD routing socket. */ pid = getpid (); /* This must be done only after locking pidfile (bug #403). */ zebra_zserv_socket_init (zserv_path); /* Make vty server socket. */ vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); while (thread_fetch (zebrad.master, &thread)) thread_call (&thread); /* Not reached... */ return 0; } quagga-0.99.24.1/zebra/zserv.c0000644000175000017500000014117212476520570012662 00000000000000/* Zebra daemon server routine. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "prefix.h" #include "command.h" #include "if.h" #include "thread.h" #include "stream.h" #include "memory.h" #include "table.h" #include "rib.h" #include "network.h" #include "sockunion.h" #include "log.h" #include "zclient.h" #include "privs.h" #include "network.h" #include "buffer.h" #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/redistribute.h" #include "zebra/debug.h" #include "zebra/ipforward.h" /* Event list of zebra. */ enum event { ZEBRA_SERV, ZEBRA_READ, ZEBRA_WRITE }; extern struct zebra_t zebrad; static void zebra_event (enum event event, int sock, struct zserv *client); extern struct zebra_privs_t zserv_privs; static void zebra_client_close (struct zserv *client); static int zserv_delayed_close(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_suicide = NULL; zebra_client_close(client); return 0; } /* When client connects, it sends hello message * with promise to send zebra routes of specific type. * Zebra stores a socket fd of the client into * this array. And use it to clean up routes that * client didn't remove for some reasons after closing * connection. */ static int route_type_oaths[ZEBRA_ROUTE_MAX]; static int zserv_flush_data(struct thread *thread) { struct zserv *client = THREAD_ARG(thread); client->t_write = NULL; if (client->t_suicide) { zebra_client_close(client); return -1; } switch (buffer_flush_available(client->wb, client->sock)) { case BUFFER_ERROR: zlog_warn("%s: buffer_flush_available failed on zserv client fd %d, " "closing", __func__, client->sock); zebra_client_close(client); break; case BUFFER_PENDING: client->t_write = thread_add_write(zebrad.master, zserv_flush_data, client, client->sock); break; case BUFFER_EMPTY: break; } return 0; } static int zebra_server_send_message(struct zserv *client) { if (client->t_suicide) return -1; switch (buffer_write(client->wb, client->sock, STREAM_DATA(client->obuf), stream_get_endp(client->obuf))) { case BUFFER_ERROR: zlog_warn("%s: buffer_write failed to zserv client fd %d, closing", __func__, client->sock); /* Schedule a delayed close since many of the functions that call this one do not check the return code. They do not allow for the possibility that an I/O error may have caused the client to be deleted. */ client->t_suicide = thread_add_event(zebrad.master, zserv_delayed_close, client, 0); return -1; case BUFFER_EMPTY: THREAD_OFF(client->t_write); break; case BUFFER_PENDING: THREAD_WRITE_ON(zebrad.master, client->t_write, zserv_flush_data, client, client->sock); break; } return 0; } static void zserv_create_header (struct stream *s, uint16_t cmd) { /* length placeholder, caller can update */ stream_putw (s, ZEBRA_HEADER_SIZE); stream_putc (s, ZEBRA_HEADER_MARKER); stream_putc (s, ZSERV_VERSION); stream_putw (s, cmd); } static void zserv_encode_interface (struct stream *s, struct interface *ifp) { /* Interface information. */ stream_put (s, ifp->name, INTERFACE_NAMSIZ); stream_putl (s, ifp->ifindex); stream_putc (s, ifp->status); stream_putq (s, ifp->flags); stream_putl (s, ifp->metric); stream_putl (s, ifp->mtu); stream_putl (s, ifp->mtu6); stream_putl (s, ifp->bandwidth); #ifdef HAVE_STRUCT_SOCKADDR_DL stream_put (s, &ifp->sdl, sizeof (ifp->sdl_storage)); #else stream_putl (s, ifp->hw_addr_len); if (ifp->hw_addr_len) stream_put (s, ifp->hw_addr, ifp->hw_addr_len); #endif /* HAVE_STRUCT_SOCKADDR_DL */ /* Write packet size. */ stream_putw_at (s, 0, stream_get_endp (s)); } /* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */ /* * This function is called in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client. * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) */ int zsend_interface_add (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_ADD); zserv_encode_interface (s, ifp); return zebra_server_send_message(client); } /* Interface deletion from zebra daemon. */ int zsend_interface_delete (struct zserv *client, struct interface *ifp) { struct stream *s; /* Check this client need interface information. */ if (! client->ifinfo) return 0; s = client->obuf; stream_reset (s); zserv_create_header (s, ZEBRA_INTERFACE_DELETE); zserv_encode_interface (s, ifp); return zebra_server_send_message (client); } /* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or * ZEBRA_INTERFACE_ADDRESS_DELETE to the client. * * A ZEBRA_INTERFACE_ADDRESS_ADD is sent in the following situations: * - in response to a 3-byte ZEBRA_INTERFACE_ADD request * from the client, after the ZEBRA_INTERFACE_ADD has been * sent from zebra to the client * - redistribute new address info to all clients in the following situations * - at startup, when zebra figures out the available interfaces * - when an interface is added (where support for * RTM_IFANNOUNCE or AF_NETLINK sockets is available), or when * an interface is marked IFF_UP (i.e., an RTM_IFINFO message is * received) * - for the vty commands "ip address A.B.C.D/M [|